blob: d0334fb40a48440a7d55fff4e8a6a1808fa19526 [file] [log] [blame]
/*
* Copyright (C) 2003, 2004, 2005, 2015 Filip Pizlo. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY FILIP PIZLO ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FILIP PIZLO OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tsf_internal.h"
#include "tsf_format.h"
#include "tsf_serial_protocol.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
/* the get mode functions are here for historical reasons. right now all of
* the actual detection work happens in the adaptive reader. */
tsf_zip_mode_t tsf_stream_file_get_mode_from_fd(int fd) {
uint8_t magic[TSF_SP_MAGIC_LEN];
uint8_t *cur=magic;
while (cur<magic+TSF_SP_MAGIC_LEN) {
int res=read(fd,cur,magic+TSF_SP_MAGIC_LEN-cur);
if (res<0) {
tsf_set_errno("Error reading magic code");
return TSF_ZIP_UNKNOWN;
}
if (res==0) {
if (cur==magic) {
tsf_set_error(TSF_E_EOF,
"End of file before magic code (file empty or connection closed prior to the transmission of any TSF data)");
} else {
tsf_set_error(TSF_E_UNEXPECTED_EOF,
"End of file before end of magic code");
}
return TSF_ZIP_UNKNOWN;
}
cur+=res;
}
if (!memcmp(magic,TSF_SP_MAGIC_CODE,TSF_SP_MAGIC_LEN)) {
return TSF_ZIP_NONE;
} else if (!memcmp(magic,TSF_SP_ZLIB_MAGIC_CODE,TSF_SP_MAGIC_LEN)) {
return TSF_ZIP_ZLIB;
} else if (!memcmp(magic,TSF_SP_BZIP2_MAGIC_CODE,TSF_SP_MAGIC_LEN)) {
return TSF_ZIP_BZIP2;
}
tsf_set_error(TSF_E_PARSE_ERROR,
"Not a valid magic code for any TSF stream file format");
return TSF_ZIP_UNKNOWN;
}
tsf_zip_mode_t tsf_stream_file_get_mode(const char *filename) {
int fd=open(filename,O_RDONLY);
tsf_zip_mode_t result;
if (fd<0) {
tsf_set_errno("Could not open %s for reading",
filename);
return TSF_ZIP_UNKNOWN;
}
result=tsf_stream_file_get_mode_from_fd(fd);
close(fd);
return result;
}
tsf_stream_file_input_t *tsf_stream_file_input_open(const char *filename,
tsf_limits_t *limits,
tsf_zip_rdr_attr_t *attr) {
int fd;
tsf_stream_file_input_t *result;
fd=open(filename,O_RDONLY);
if (fd<0) {
tsf_set_errno("Could not open %s for reading",
filename);
return NULL;
}
result=tsf_stream_file_input_fd_open(fd,
limits,
attr,
tsf_true,
0);
if (result==NULL) {
close(fd);
return NULL;
}
return result;
}
tsf_stream_file_input_t *tsf_stream_file_input_fd_open(int fd,
tsf_limits_t *limits,
tsf_zip_rdr_attr_t *_attr,
tsf_bool_t keep,
uint32_t buf_size) {
tsf_stream_file_input_t *ret;
tsf_zip_rdr_attr_t attr;
tsf_reader_t reader;
if (_attr==NULL) {
tsf_zip_rdr_attr_get_default(&attr);
} else {
attr=*_attr;
}
if (buf_size==0) {
buf_size=TSF_DEF_BUF_SIZE;
}
ret=malloc(sizeof(tsf_stream_file_input_t));
if (ret==NULL) {
tsf_set_errno("Could not malloc tsf_stream_file_input_t");
return NULL;
}
ret->fd=fd;
ret->keep_fd=keep;
if (tsf_zip_rdr_attr_is_nozip(&attr)) {
ret->use_adpt=tsf_false;
ret->reader.buf=tsf_buf_reader_create(ret->fd,
buf_size,
tsf_false);
reader=tsf_buf_reader_read;
} else {
ret->use_adpt=tsf_true;
ret->reader.adpt=tsf_adaptive_reader_create(tsf_fd_partial_reader,
&(ret->fd),
buf_size,
&attr);
reader=tsf_adaptive_reader_read;
}
if (ret->reader.ptr==NULL) {
free(ret);
return NULL;
}
ret->in_man=tsf_serial_in_man_create(reader,
ret->reader.ptr,
limits);
if (ret->in_man==NULL) {
if (ret->use_adpt) {
tsf_adaptive_reader_destroy(ret->reader.adpt);
} else {
tsf_buf_reader_destroy(ret->reader.buf);
}
free(ret);
return NULL;
}
/* if we ever have a
* tsf_serial_in_man_pretend_that_youve_read_reset_types()
* function, we should call it here. */
return ret;
}
void tsf_stream_file_input_close(tsf_stream_file_input_t *file) {
tsf_serial_in_man_destroy(file->in_man);
if (file->keep_fd) {
close(file->fd);
} else {
/* try to seek the file descriptor back to where it should have been,
if we hadn't been reading with buffering. */
uint32_t num_remaining;
if (file->use_adpt) {
num_remaining=tsf_adaptive_reader_get_remaining(file->reader.adpt);
} else {
num_remaining=tsf_buf_reader_get_remaining(file->reader.buf);
}
lseek(file->fd,-((off_t)num_remaining),SEEK_CUR);
/* ignore error, since this is best effort anyway. */
}
if (file->use_adpt) {
tsf_adaptive_reader_destroy(file->reader.adpt);
} else {
tsf_buf_reader_destroy(file->reader.buf);
}
free(file);
}
tsf_bool_t tsf_stream_file_input_allows_compression(tsf_stream_file_input_t *file) {
return file->use_adpt;
}
tsf_bool_t tsf_stream_file_input_register_type_cback(tsf_stream_file_input_t *file,
tsf_type_cback_t cback,
void *arg) {
return tsf_serial_in_man_register_type_cback(file->in_man, cback, arg);
}
tsf_bool_t tsf_stream_file_input_unregister_type_cback(tsf_stream_file_input_t *file,
tsf_type_cback_t cback,
void *arg) {
return tsf_serial_in_man_unregister_type_cback(file->in_man, cback, arg);
}
tsf_buffer_t *tsf_stream_file_input_read(tsf_stream_file_input_t *file) {
if (file->use_adpt) {
tsf_adaptive_reader_hint_switch(file->reader.adpt);
}
return tsf_serial_in_man_read(file->in_man);
}
tsf_bool_t tsf_stream_file_input_read_existing_buffer(tsf_stream_file_input_t *file,
tsf_buffer_t *buf) {
if (file->use_adpt) {
tsf_adaptive_reader_hint_switch(file->reader.adpt);
}
return tsf_serial_in_man_read_existing_buffer(file->in_man, buf);
}
tsf_bool_t tsf_stream_file_input_get_mark(tsf_stream_file_input_t *file,
tsf_stream_file_mark_t *mark) {
if (file->use_adpt) {
tsf_set_error(TSF_E_NOT_SUPPORTED,
"tsf_stream_file_input_get_mark() is not supported if "
"compression is allowed");
return tsf_false;
}
mark->offset = lseek(file->fd,
(off_t) 0,
SEEK_CUR);
if (mark->offset<0) {
tsf_set_errno("Could not lseek() in "
"tsf_stream_file_input_get_mark_of_next()");
return tsf_false;
}
mark->offset -= tsf_buf_reader_get_remaining(file->reader.buf);
mark->state = tsf_serial_in_man_get_state(file->in_man);
return tsf_true;
}
tsf_bool_t tsf_stream_file_input_seek(tsf_stream_file_input_t *file,
const tsf_stream_file_mark_t *mark) {
/* if the file is compressed then the user should not have been able
* to get a mark. */
tsf_assert(!file->use_adpt);
if (lseek(file->fd,
mark->offset,
SEEK_SET) < 0) {
tsf_set_errno("Could not lseek() in "
"tsf_stream_file_input_seek_to_mark()");
return tsf_false;
}
tsf_buf_reader_reset(file->reader.buf);
tsf_serial_in_man_set_state(file->in_man,
mark->state);
return tsf_true;
}