size_t);
static int seek_pack(struct archive_read *);
static int64_t skip_stream(struct archive_read *, size_t);
-static int get_data_offset(struct archive_read *, int64_t *);
+static int get_data_offset(struct archive_read *, int64_t *, int);
static int get_pe_sfx_offset(struct archive_read *, int64_t *);
-static int get_elf_sfx_offset(struct archive_read *, int64_t *);
+static int get_elf_sfx_offset(struct archive_read *, int64_t *, int);
static int slurp_central_directory(struct archive_read *, struct _7zip *,
struct _7z_header_info *);
static int setup_decode_folder(struct archive_read *, struct _7z_folder *,
static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t);
static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t);
+static int64_t seek_compat(struct archive_read *, int64_t, int, int);
int
}
static int
-get_data_offset(struct archive_read *a, int64_t *data_offset)
+get_data_offset(struct archive_read *a, int64_t *data_offset, int compat)
{
const unsigned char *p;
int64_t offset, sfx_offset;
if ((p[0] == 'M' && p[1] == 'Z'))
r = get_pe_sfx_offset(a, &sfx_offset);
else if (memcmp(p, "\x7F\x45LF", 4) == 0)
- r = get_elf_sfx_offset(a, &sfx_offset);
+ r = get_elf_sfx_offset(a, &sfx_offset, compat);
else
r = ARCHIVE_FATAL;
if (r < ARCHIVE_WARN || sfx_offset > SFX_MAX_SEEK)
if (best_bid > 32)
return (-1);
- if (get_data_offset(a, &data_offset) < 0)
+ if (get_data_offset(a, &data_offset, 0) < 0)
return (0);
return (48);
}
static int
-get_elf_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
+get_elf_sfx_offset(struct archive_read *a, int64_t *sfx_offset, int compat)
{
int64_t r;
const char *h;
/*
* Reading the section table to find strtab section
*/
- if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
+ if (seek_compat(a, e_shoff, SEEK_SET, compat) < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
return (ARCHIVE_FATAL);
}
/*
* Read the STRTAB section to find the .data offset
*/
- if (__archive_read_seek(a, strtab_offset, SEEK_SET) < 0) {
+ if (seek_compat(a, strtab_offset, SEEK_SET, compat) < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
return (ARCHIVE_FATAL);
}
/*
* Find the section with the .data name
*/
- if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
+ if (seek_compat(a, e_shoff, SEEK_SET, compat) < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
return (ARCHIVE_FATAL);
}
break;
}
- r = __archive_read_seek(a, 0, SEEK_SET);
+ r = seek_compat(a, 0, SEEK_SET, compat);
if (r < 0)
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
return (int)r;
int64_t data_offset;
int check_header_crc, r;
- if (get_data_offset(a, &data_offset) < 0)
+ if (get_data_offset(a, &data_offset, 1) < 0)
return (ARCHIVE_FATAL);
if (__archive_read_consume(a, data_offset) < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
if (next_header_offset != 0) {
if (bytes_avail >= (ssize_t)next_header_offset)
__archive_read_consume(a, next_header_offset);
- else if (__archive_read_seek(a,
- next_header_offset + zip->seek_base, SEEK_SET) < 0) {
+ else if (seek_compat(a,
+ next_header_offset + zip->seek_base, SEEK_SET, 1) < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
return (ARCHIVE_FATAL);
}
zip->si.pi.sizes[zip->pack_stream_index];
pack_offset = zip->si.pi.positions[zip->pack_stream_index];
if (zip->stream_offset != pack_offset) {
- if (0 > __archive_read_seek(a, pack_offset + zip->seek_base,
- SEEK_SET)) {
+ if (0 > seek_compat(a, pack_offset + zip->seek_base,
+ SEEK_SET, 1)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
return (ARCHIVE_FATAL);
}
return ((ssize_t)outPos);
}
+
+/*
+ * Perform a seek to given position. If seeking is not supported,
+ * target position is in front of current position, and compat is requested,
+ * try to consume bytes until position is reached.
+ */
+int64_t
+seek_compat(struct archive_read *a, int64_t offset, int whence, int compat)
+{
+ int64_t ret = ARCHIVE_FAILED;
+
+ if (a->filter->can_seek)
+ ret = __archive_read_seek(a, offset, whence);
+ else if (compat) {
+ switch (whence) {
+ case SEEK_CUR:
+ ret = __archive_read_consume(a, offset);
+ break;
+ case SEEK_SET:
+ if (a->filter->position > offset)
+ break;
+ ret = __archive_read_consume(a,
+ offset - a->filter->position);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return (ret);
+}