예제 #1
0
static int
read_open_memory_internal(struct archive *a, void *buff,
    size_t size, size_t read_size, int fullapi)
{
	struct read_memory_data *mine;

	mine = (struct read_memory_data *)malloc(sizeof(*mine));
	if (mine == NULL) {
		archive_set_error(a, ENOMEM, "No memory");
		return (ARCHIVE_FATAL);
	}
	memset(mine, 0, sizeof(*mine));
	mine->buffer = (unsigned char *)buff;
	mine->end = mine->buffer + size;
	mine->read_size = read_size;
	mine->copy_buff_offset = 32;
	mine->copy_buff_size = read_size + mine->copy_buff_offset * 2;
	mine->copy_buff = malloc(mine->copy_buff_size);
	memset(mine->copy_buff, 0xA5, mine->copy_buff_size);
	if (fullapi)
		return (archive_read_open2(a, mine, memory_read_open,
			    memory_read, memory_read_skip, memory_read_close));
	else
		return (archive_read_open2(a, mine, NULL,
			    memory_read, NULL, memory_read_close));
}
예제 #2
0
bool OdinPatcher::Impl::openInputArchive()
{
    assert(aInput == nullptr);

    aInput = archive_read_new();

    // TODO: Eventually support tar within a zip since many people distribute
    //       stock firmware packages in this format
    //archive_read_support_format_zip(aInput);
    archive_read_support_format_tar(aInput);
    archive_read_support_filter_gzip(aInput);
    archive_read_support_filter_xz(aInput);

    // Our callbacks use io::File, which supports LFS on Android. Also allows
    // progress info by counting number of bytes read.
    int ret = archive_read_open2(aInput, this, &Impl::laOpenCb, &Impl::laReadCb,
                                 &Impl::laSkipCb, &Impl::laCloseCb);
    if (ret != ARCHIVE_OK) {
        LOGW("libarchive: Failed to open for reading: %s",
             archive_error_string(aInput));
        archive_read_free(aInput);
        aInput = nullptr;
        error = ErrorCode::ArchiveReadOpenError;
        return false;
    }

    return true;
}
int
archive_read_open_qiodevice(struct archive *a, QIODevice *device)
{
	if (device == 0) {
		qDebug () << "archive_read_open_qiodevice";
		archive_set_error(a, -1, "Invalid QIODevice");
		return ARCHIVE_FATAL;
	}

	if (!device->isOpen() && !device->open(QIODevice::ReadOnly)) {
		qDebug () << "archive_read_open_qiodevice";
		archive_set_error(a, -1, "Could not open QIODevice for reading");
		return ARCHIVE_FATAL;
	}

	if (!device->isReadable()) {
		qDebug () << "archive_read_open_qiodevice";
		archive_set_error(a, -1, "Could not open QIODevice for reading");
		return ARCHIVE_FATAL;
	}

	struct read_qiodevice_data *data = new read_qiodevice_data;
	if (data == 0) {
		qDebug () << "archive_read_open_qiodevice";
		archive_set_error(a, -1, "No Memory");
		return ARCHIVE_FATAL;
	}
	data->device = device;

	device->reset(); // Seek to begining of file
	device->setTextModeEnabled(false); // Binary mode

	return (archive_read_open2(a, data, NULL, qiodevice_read,
	        qiodevice_read_skip, qiodevice_read_close));
}
int
archive_read_open_filename(struct archive *a, const char *filename,
    size_t block_size)
{
	struct read_file_data *mine;

	if (filename == NULL || filename[0] == '\0') {
		mine = (struct read_file_data *)malloc(sizeof(*mine));
		if (mine == NULL) {
			archive_set_error(a, ENOMEM, "No memory");
			return (ARCHIVE_FATAL);
		}
		mine->filename[0] = '\0';
	} else {
		mine = (struct read_file_data *)malloc(sizeof(*mine) + strlen(filename));
		if (mine == NULL) {
			archive_set_error(a, ENOMEM, "No memory");
			return (ARCHIVE_FATAL);
		}
		strcpy(mine->filename, filename);
	}
	mine->block_size = block_size;
	mine->buffer = NULL;
	mine->fd = -1;
	/* lseek() almost never works; disable it by default.  See below. */
	mine->can_skip = 0;
	return (archive_read_open2(a, mine, file_open, file_read, file_skip, file_close));
}
예제 #5
0
/*
 * Open the archive
 */
int
archive_read_open(struct archive *a, void *client_data,
    archive_open_callback *client_opener, archive_read_callback *client_reader,
    archive_close_callback *client_closer)
{
	/* Old archive_read_open() is just a thin shell around
	 * archive_read_open2. */
	return archive_read_open2(a, client_data, client_opener,
	    client_reader, NULL, client_closer);
}
예제 #6
0
static void
test(int formatted, archive_open_callback *o, archive_read_callback *r,
    archive_skip_callback *s, archive_close_callback *c,
    int rv, const char *msg)
{
	struct archive* a = archive_read_new();
	if (formatted)
	    assertEqualInt(ARCHIVE_OK,
		archive_read_support_format_empty(a));
	assertEqualInt(rv,
	    archive_read_open2(a, NULL, o, r, s, c));
	assertEqualString(msg, archive_error_string(a));
	archive_read_free(a);
}
/*
 * Don't use _open_memory2() in production code; the archive_read_open_memory()
 * version is the one you really want.  This is just here so that
 * test harnesses can exercise block operations inside the library.
 */
int
archive_read_open_memory2(struct archive *a, void *buff,
    size_t size, size_t read_size)
{
	struct read_memory_data *mine;

	mine = (struct read_memory_data *)malloc(sizeof(*mine));
	if (mine == NULL) {
		archive_set_error(a, ENOMEM, "No memory");
		return (ARCHIVE_FATAL);
	}
	memset(mine, 0, sizeof(*mine));
	mine->buffer = (unsigned char *)buff;
	mine->end = mine->buffer + size;
	mine->read_size = read_size;
	return (archive_read_open2(a, mine, memory_read_open,
		    memory_read, memory_read_skip, memory_read_close));
}
/**
 * archive_read_open_multitape(a, machinenum, tapename):
 * Open the multitape tape ${tapename} for reading (and skipping) and
 * associate it with the archive $a$.  Return a cookie which can be passed
 * to the multitape layer.
 */
void *
archive_read_open_multitape(struct archive * a, uint64_t machinenum,
    const char * tapename)
{
	struct multitape_read_internal * d;

	/* Clear any error messages from the archive. */
	archive_clear_error(a);

	if ((d = readtape_open(machinenum, tapename)) == NULL) {
		archive_set_error(a, errno, "Error opening archive");
		return (NULL);
	}

	if (archive_read_open2(a, d, NULL, read_read, read_skip, read_close))
		return (NULL);
	else
		return (d);
}
예제 #9
0
int
archive_read_open_fd(struct archive *a, int fd, size_t block_size)
{
    struct stat st;
    struct read_fd_data *mine;
    void *b;

    archive_clear_error(a);
    if (fstat(fd, &st) != 0) {
        archive_set_error(a, errno, "Can't stat fd %d", fd);
        return (ARCHIVE_FATAL);
    }

    mine = (struct read_fd_data *)malloc(sizeof(*mine));
    b = malloc(block_size);
    if (mine == NULL || b == NULL) {
        archive_set_error(a, ENOMEM, "No memory");
        free(mine);
        free(b);
        return (ARCHIVE_FATAL);
    }
    mine->block_size = block_size;
    mine->buffer = b;
    mine->fd = fd;
    /*
     * Skip support is a performance optimization for anything
     * that supports lseek().  On FreeBSD, only regular files and
     * raw disk devices support lseek() and there's no portable
     * way to determine if a device is a raw disk device, so we
     * only enable this optimization for regular files.
     */
    if (S_ISREG(st.st_mode)) {
        archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
        mine->can_skip = 1;
    } else
        mine->can_skip = 0;
#if defined(__CYGWIN__) || defined(_WIN32)
    setmode(mine->fd, O_BINARY);
#endif

    return (archive_read_open2(a, mine,
                               NULL, file_read, file_skip, file_close));
}
예제 #10
0
int
archive_read_open_FILE(struct archive *a, FILE *f)
{
	struct stat st;
	struct read_FILE_data *mine;
	size_t block_size = 128 * 1024;
	void *b;

	archive_clear_error(a);
	mine = (struct read_FILE_data *)malloc(sizeof(*mine));
	b = malloc(block_size);
	if (mine == NULL || b == NULL) {
		archive_set_error(a, ENOMEM, "No memory");
		free(mine);
		free(b);
		return (ARCHIVE_FATAL);
	}
	mine->block_size = block_size;
	mine->buffer = b;
	mine->f = f;
	/*
	 * If we can't fstat() the file, it may just be that it's not
	 * a file.  (FILE * objects can wrap many kinds of I/O
	 * streams, some of which don't support fileno()).)
	 */
	if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) {
		archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
		/* Enable the seek optimization only for regular files. */
		mine->can_skip = 1;
	} else
		mine->can_skip = 0;

#if defined(__CYGWIN__) || defined(_WIN32)
	setmode(fileno(mine->f), O_BINARY);
#endif

	return (archive_read_open2(a, mine, NULL, file_read,
		    file_skip, file_close));
}
int
archive_read_open_filename(struct archive *a, const char *filename,
    size_t block_size)
{
	struct stat st;
	struct read_file_data *mine;
	void *b;
	int fd;

	archive_clear_error(a);
	if (filename == NULL || filename[0] == '\0') {
		/* We used to invoke archive_read_open_fd(a,0,block_size)
		 * here, but that doesn't (and shouldn't) handle the
		 * end-of-file flush when reading stdout from a pipe.
		 * Basically, read_open_fd() is intended for folks who
		 * are willing to handle such details themselves.  This
		 * API is intended to be a little smarter for folks who
		 * want easy handling of the common case.
		 */
		filename = ""; /* Normalize NULL to "" */
		fd = 0;
#if defined(__CYGWIN__) || defined(_WIN32)
		setmode(0, O_BINARY);
#endif
	} else {
		fd = open(filename, O_RDONLY | O_BINARY);
		if (fd < 0) {
			archive_set_error(a, errno,
			    "Failed to open '%s'", filename);
			return (ARCHIVE_FATAL);
		}
	}
	if (fstat(fd, &st) != 0) {
		archive_set_error(a, errno, "Can't stat '%s'", filename);
		return (ARCHIVE_FATAL);
	}

	mine = (struct read_file_data *)calloc(1,
	    sizeof(*mine) + strlen(filename));
	b = malloc(block_size);
	if (mine == NULL || b == NULL) {
		archive_set_error(a, ENOMEM, "No memory");
		free(mine);
		free(b);
		return (ARCHIVE_FATAL);
	}
	strcpy(mine->filename, filename);
	mine->block_size = block_size;
	mine->buffer = b;
	mine->fd = fd;
	/* Remember mode so close can decide whether to flush. */
	mine->st_mode = st.st_mode;
	/* If we're reading a file from disk, ensure that we don't
	   overwrite it with an extracted file. */
	if (S_ISREG(st.st_mode)) {
		archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
		/*
		 * Enabling skip here is a performance optimization
		 * for anything that supports lseek().  On FreeBSD
		 * (and probably many other systems), only regular
		 * files and raw disk devices support lseek() (on
		 * other input types, lseek() returns success but
		 * doesn't actually change the file pointer, which
		 * just completely screws up the position-tracking
		 * logic).  In addition, I've yet to find a portable
		 * way to determine if a device is a raw disk device.
		 * So I don't see a way to do much better than to only
		 * enable this optimization for regular files.
		 */
		mine->can_skip = 1;
	}
	return (archive_read_open2(a, mine,
		NULL, file_read, file_skip, file_close));
}
예제 #12
0
파일: archive.c 프로젝트: mstorsjo/vlc
static int archive_init( private_sys_t* p_sys, stream_t* source )
{
    /* CREATE ARCHIVE HANDLE */

    p_sys->p_archive = archive_read_new();

    if( unlikely( !p_sys->p_archive ) )
    {
        msg_Dbg( p_sys->p_obj, "unable to create libarchive handle" );
        return VLC_EGENERIC;
    }

    /* SETUP SEEKING */

    p_sys->b_seekable_archive = false;

    if( vlc_stream_Control( source, STREAM_CAN_SEEK,
        &p_sys->b_seekable_source ) )
    {
        msg_Warn( p_sys->p_obj, "unable to query whether source stream can seek" );
        p_sys->b_seekable_source = false;
    }

    if( p_sys->b_seekable_source )
    {
        if( archive_read_set_seek_callback( p_sys->p_archive,
            libarchive_seek_cb ) )
        {
            msg_Err( p_sys->p_obj, "archive_read_set_callback failed, aborting." );
            return VLC_EGENERIC;
        }
    }

    /* ENABLE ALL FORMATS/FILTERS */

    archive_read_support_filter_all( p_sys->p_archive );
    archive_read_support_format_all( p_sys->p_archive );

    /* REGISTER CALLBACK DATA */

    if( archive_read_set_switch_callback( p_sys->p_archive,
        libarchive_jump_cb ) )
    {
        msg_Err( p_sys->p_obj, "archive_read_set_switch_callback failed, aborting." );
        return VLC_EGENERIC;
    }

    for( size_t i = 0; i < p_sys->i_callback_data; ++i )
    {
        if( archive_read_append_callback_data( p_sys->p_archive,
            p_sys->pp_callback_data[i] ) )
        {
            return VLC_EGENERIC;
        }
    }

    /* OPEN THE ARCHIVE */

    if( archive_read_open2( p_sys->p_archive, p_sys->pp_callback_data[0], NULL,
        libarchive_read_cb, libarchive_skip_cb, libarchive_exit_cb ) )
    {
        msg_Dbg( p_sys->p_obj, "libarchive: %s",
          archive_error_string( p_sys->p_archive ) );

        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
예제 #13
0
파일: access.c 프로젝트: 9034725985/vlc
int AccessOpen(vlc_object_t *p_object)
{
    access_t *p_access = (access_t*)p_object;
    const char *sep = strchr(p_access->psz_location, ARCHIVE_SEP_CHAR);
    if (sep == NULL)
        return VLC_EGENERIC;

    char *psz_base = strdup(p_access->psz_location);
    if (unlikely(psz_base == NULL))
        return VLC_ENOMEM;

    char *psz_name = psz_base + (sep - p_access->psz_location);
    *(psz_name++) = '\0';

    if (decode_URI(psz_base) == NULL)
    {
        free(psz_base);
        return VLC_EGENERIC;
    }

    access_sys_t *p_sys = p_access->p_sys = calloc(1, sizeof(access_sys_t));
    p_sys->p_archive = archive_read_new();
    if (!p_sys->p_archive)
    {
        msg_Err(p_access, "can't create libarchive instance: %s",
                archive_error_string(p_sys->p_archive));
        free(psz_base);
        goto error;
    }

    EnableArchiveFormats(p_sys->p_archive);

    /* Set up the switch callback for multiple volumes handling */
    archive_read_set_switch_callback(p_sys->p_archive, SwitchCallback);

    /* !Warn: sucks because libarchive can't guess format without reading 1st header
     *        and it can't tell either if volumes are missing neither set following
     *        volumes after the first Open().
     *        We need to know volumes uri in advance then :/
     */

    /* Try to list existing volumes */
    char **ppsz_files = NULL;
    unsigned int i_files = 0;
    FindVolumes(p_access, p_sys->p_archive, psz_base, &ppsz_files, &i_files);

    p_sys->i_callback_data = 1 + i_files;
    p_sys->p_callback_data = malloc(sizeof(callback_data_t) * p_sys->i_callback_data);
    if (!p_sys->p_callback_data)
    {
        for(unsigned int i=0; i<i_files; i++)
            free(ppsz_files[i]);
        free(ppsz_files);
        free(psz_base);
        AccessClose(p_object);
        return VLC_ENOMEM;
    }

    /* set up our callback struct for our main uri */
    p_sys->p_callback_data[0].psz_uri = psz_base;
    p_sys->p_callback_data[0].p_access = p_access;
    archive_read_append_callback_data(p_sys->p_archive, &p_sys->p_callback_data[0]);

    /* and register other volumes */
    for(unsigned int i=0; i<i_files; i++)
    {
        p_sys->p_callback_data[1+i].psz_uri = ppsz_files[i];
        p_sys->p_callback_data[1+i].p_access = p_access;
        archive_read_append_callback_data(p_sys->p_archive, &p_sys->p_callback_data[1+i]);
    }
    free(ppsz_files);

    if (archive_read_open2(p_sys->p_archive, &p_sys->p_callback_data[0],
                           OpenCallback, ReadCallback, SkipCallback, CloseCallback) != ARCHIVE_OK)
    {
        msg_Err(p_access, "can't open archive: %s",
                archive_error_string(p_sys->p_archive));
        AccessClose(p_object);
        return VLC_EGENERIC;
    }

    bool b_present = false;
    while(archive_read_next_header(p_sys->p_archive, &p_sys->p_entry) == ARCHIVE_OK)
    {
        if (!strcmp(archive_entry_pathname(p_sys->p_entry), psz_name))
        {
            b_present = true;
            break;
        }
        msg_Dbg(p_access, "skipping entry %s != %s", archive_entry_pathname(p_sys->p_entry), psz_name);
    }

    if (!b_present)
    {
        msg_Err(p_access, "entry '%s' not found in archive", psz_name);
        /* entry not found */
        goto error;
    }

    msg_Dbg(p_access, "reading entry %s %"PRId64, archive_entry_pathname(p_sys->p_entry),
                                                  archive_entry_size(p_sys->p_entry));

    /* try to guess if it is seekable or not (does not depend on backend) */
    p_sys->b_seekable = (archive_seek_data(p_sys->p_archive, 0, SEEK_SET) >= 0);

    p_access->pf_read    = Read;
    p_access->pf_block   = NULL; /* libarchive's zerocopy keeps owning block :/ */
    p_access->pf_control = Control;
    p_access->pf_seek    = Seek;

    access_InitFields(p_access);

    return VLC_SUCCESS;

error:
    AccessClose(p_object);
    return VLC_EGENERIC;
}
예제 #14
0
static foreign_t
archive_open_stream(term_t data, term_t handle, term_t options)
{ IOSTREAM *datas;
  archive_wrapper *ar;
  term_t tail = PL_copy_term_ref(options);
  term_t head = PL_new_term_ref();
  term_t arg  = PL_new_term_ref();

  if ( !PL_get_stream_handle(data, &datas) )
    return FALSE;
  if ( !(datas->flags & SIO_INPUT) )
  { PL_release_stream(datas);
    return PL_domain_error("input_stream", data);
  }

  ar = PL_malloc(sizeof(*ar));
  memset(ar, 0, sizeof(*ar));
  ar->data = datas;
  ar->magic = ARCHIVE_MAGIC;
  if ( !PL_unify_blob(handle, ar, sizeof(*ar), &archive_blob) )
    return FALSE;

  while( PL_get_list_ex(tail, head, tail) )
  { atom_t name;
    int arity;

    if ( !PL_get_name_arity(head, &name, &arity) ||
	 !PL_get_arg(1, head, arg) )
      return PL_type_error("option", head);
    if ( name == ATOM_compression || name == ATOM_filter )
    { atom_t c;

      if ( !PL_get_atom_ex(arg, &c) )
	return FALSE;

      if ( c == ATOM_all )
	ar->type |= FILTER_ALL;
#ifdef FILTER_BZIP2
      else if ( c == ATOM_bzip2 )
	ar->type |= FILTER_BZIP2;
#endif
#ifdef FILTER_COMPRESS
      else if ( c == ATOM_compress )
	ar->type |= FILTER_COMPRESS;
#endif
#ifdef FILTER_GZIP
      else if ( c == ATOM_gzip )
	ar->type |= FILTER_GZIP;
#endif
#ifdef FILTER_GRZIP
      else if ( c == ATOM_grzip )
	ar->type |= FILTER_GRZIP;
#endif
#ifdef FILTER_LRZIP
      else if ( c == ATOM_lrzip )
	ar->type |= FILTER_LRZIP;
#endif
#ifdef FILTER_LZIP
      else if ( c == ATOM_lzip )
	ar->type |= FILTER_LZIP;
#endif
#ifdef FILTER_LZMA
      else if ( c == ATOM_lzma )
	ar->type |= FILTER_LZMA;
#endif
#ifdef FILTER_LZOP
      else if ( c == ATOM_lzop )
	ar->type |= FILTER_LZOP;
#endif
#ifdef FILTER_NONE
      else if ( c == ATOM_none )
	ar->type |= FILTER_NONE;
#endif
#ifdef FILTER_RPM
      else if ( c == ATOM_rpm )
	ar->type |= FILTER_RPM;
#endif
#ifdef FILTER_UU
      else if ( c == ATOM_uu )
	ar->type |= FILTER_UU;
#endif
#ifdef FILTER_XZ
      else if ( c == ATOM_xz )
	ar->type |= FILTER_XZ;
#endif
      else
	return PL_domain_error("filter", arg);
    } else if ( name == ATOM_format )
    { atom_t f;

      if ( !PL_get_atom_ex(arg, &f) )
	return FALSE;

      if ( f == ATOM_all )
	ar->type |= FORMAT_ALL;
#ifdef FORMAT_7ZIP
      else if ( f == ATOM_7zip )
	ar->type |= FORMAT_7ZIP;
#endif
#ifdef FORMAT_AR
      else if ( f == ATOM_ar )
	ar->type |= FORMAT_AR;
#endif
#ifdef FORMAT_CAB
      else if ( f == ATOM_cab )
	ar->type |= FORMAT_CAB;
#endif
#ifdef FORMAT_CPIO
      else if ( f == ATOM_cpio )
	ar->type |= FORMAT_CPIO;
#endif
#ifdef FORMAT_EMPTY
      else if ( f == ATOM_empty )
	ar->type |= FORMAT_EMPTY;
#endif
#ifdef FORMAT_GNUTAR
      else if ( f == ATOM_gnutar )
	ar->type |= FORMAT_GNUTAR;
#endif
#ifdef FORMAT_ISO9960
      else if ( f == ATOM_iso9960 )
	ar->type |= FORMAT_ISO9960;
#endif
#ifdef FORMAT_LHA
      else if ( f == ATOM_lha )
	ar->type |= FORMAT_LHA;
#endif
#ifdef FORMAT_MTREE
      else if ( f == ATOM_mtree )
	ar->type |= FORMAT_MTREE;
#endif
#ifdef FORMAT_RAR
      else if ( f == ATOM_rar )
	ar->type |= FORMAT_RAR;
#endif
#ifdef FORMAT_RAW
      else if ( f == ATOM_raw )
	ar->type |= FORMAT_RAW;
#endif
#ifdef FORMAT_TAR
      else if ( f == ATOM_tar )
	ar->type |= FORMAT_TAR;
#endif
#ifdef FORMAT_XAR
      else if ( f == ATOM_xar )
	ar->type |= FORMAT_XAR;
#endif
#ifdef FORMAT_ZIP
      else if ( f == ATOM_zip )
	ar->type |= FORMAT_ZIP;
#endif
      else
	return PL_domain_error("format", arg);
    } else if ( name == ATOM_close_parent )
    { if ( !PL_get_bool_ex(arg, &ar->close_parent) )
	return FALSE;
    }
  }
  if ( !PL_get_nil_ex(tail) )
    return FALSE;

  if ( !(ar->type & FILTER_ALL) )
    ar->type |= FILTER_ALL;
  if ( !(ar->type & FORMAT_MASK) )
    ar->type |= FORMAT_ALL;

  if ( !(ar->archive = archive_read_new()) )
    return PL_resource_error("memory");

  if ( (ar->type & FILTER_ALL) == FILTER_ALL )
  { archive_read_support_filter_all(ar->archive);
  } else
  {
#ifdef FILTER_BZIP2
    enable_type(ar, FILTER_BZIP2,    archive_read_support_filter_bzip2);
#endif
#ifdef FILTER_COMPRESS
    enable_type(ar, FILTER_COMPRESS, archive_read_support_filter_compress);
#endif
#ifdef FILTER_GZIP
    enable_type(ar, FILTER_GZIP,     archive_read_support_filter_gzip);
#endif
#ifdef FILTER_GRZIP
    enable_type(ar, FILTER_GRZIP,     archive_read_support_filter_grzip);
#endif
#ifdef FILTER_LRZIP
    enable_type(ar, FILTER_LRZIP,     archive_read_support_filter_lrzip);
#endif
#ifdef FILTER_LZIP
    enable_type(ar, FILTER_LZIP,     archive_read_support_filter_lzip);
#endif
#ifdef FILTER_LZMA
    enable_type(ar, FILTER_LZMA,     archive_read_support_filter_lzma);
#endif
#ifdef FILTER_LZOP
    enable_type(ar, FILTER_LZOP,     archive_read_support_filter_lzop);
#endif
#ifdef FILTER_NONE
    enable_type(ar, FILTER_NONE,     archive_read_support_filter_none);
#endif
#ifdef FILTER_RPM
    enable_type(ar, FILTER_RPM,      archive_read_support_filter_rpm);
#endif
#ifdef FILTER_UU
    enable_type(ar, FILTER_UU,       archive_read_support_filter_uu);
#endif
#ifdef FILTER_XZ
    enable_type(ar, FILTER_XZ,       archive_read_support_filter_xz);
#endif
  }

  if ( (ar->type & FORMAT_ALL) == FORMAT_ALL )
  { archive_read_support_format_all(ar->archive);
#ifdef FORMAT_RAW
    enable_type(ar, FORMAT_RAW,     archive_read_support_format_raw);
#endif
  } else
  {
#ifdef FORMAT_7ZIP
    enable_type(ar, FORMAT_7ZIP,    archive_read_support_format_7zip);
#endif
#ifdef FORMAT_AR
    enable_type(ar, FORMAT_AR,      archive_read_support_format_ar);
#endif
#ifdef FORMAT_CAB
    enable_type(ar, FORMAT_CAB,     archive_read_support_format_cab);
#endif
#ifdef FORMAT_CPIO
    enable_type(ar, FORMAT_CPIO,    archive_read_support_format_cpio);
#endif
#ifdef FORMAT_EMPTY
    enable_type(ar, FORMAT_EMPTY,   archive_read_support_format_empty);
#endif
#ifdef FORMAT_GNUTAR
    enable_type(ar, FORMAT_GNUTAR,  archive_read_support_format_gnutar);
#endif
#ifdef FORMAT_ISO9960
    enable_type(ar, FORMAT_ISO9960, archive_read_support_format_iso9660);
#endif
#ifdef FORMAT_LHA
    enable_type(ar, FORMAT_LHA,     archive_read_support_format_lha);
#endif
#ifdef FORMAT_MTREE
    enable_type(ar, FORMAT_MTREE,   archive_read_support_format_mtree);
#endif
#ifdef FORMAT_RAR
    enable_type(ar, FORMAT_RAR,     archive_read_support_format_rar);
#endif
#ifdef FORMAT_RAW
    enable_type(ar, FORMAT_RAW,     archive_read_support_format_raw);
#endif
#ifdef FORMAT_TAR
    enable_type(ar, FORMAT_TAR,     archive_read_support_format_tar);
#endif
#ifdef FORMAT_XAR
    enable_type(ar, FORMAT_XAR,     archive_read_support_format_xar);
#endif
#ifdef FORMAT_ZIP
    enable_type(ar, FORMAT_ZIP,     archive_read_support_format_zip);
#endif
  }

#ifdef HAVE_ARCHIVE_READ_OPEN1
  archive_read_set_callback_data(ar->archive, ar);
  archive_read_set_open_callback(ar->archive, ar_open);
  archive_read_set_read_callback(ar->archive, ar_read);
  archive_read_set_skip_callback(ar->archive, ar_skip);
  archive_read_set_seek_callback(ar->archive, ar_seek);
  archive_read_set_close_callback(ar->archive, ar_close);

  if ( archive_read_open1(ar->archive) == ARCHIVE_OK )
  { ar->status = AR_OPENED;
    return TRUE;
  }
#else
  if ( archive_read_open2(ar->archive, ar,
			  ar_open, ar_read, ar_skip, ar_close) == ARCHIVE_OK )
  { ar->status = AR_OPENED;
    return TRUE;
  }
#endif

  return archive_error(ar);
}