Прочитать строку символа как виртуальный файл
Вопрос может показаться странным, но я не ошибся: я хочу распаковать некоторые загруженные данные, не записывая их на жесткий диск. Для этого я загружаю его в динамически размещенный буфер и хочу отправить его в используемую оболочку zlib (miniunzip). Проблема в том, что эта реализация довольно длинная (2-3 тыс. Строк), и я хотел бы избежать перезаписи ее всего на несколько строк. Я хотел бы знать, есть ли какой-либо способ чтения буфера через структуру FILE* (miniunzip использует свою собственную структуру, но я нашел скрытую "fopen()" под загрузчиком). Я знаю его длину, если это может помочь.
Заранее спасибо и извините за плохую грамматику.
Я работаю как на Windows, так и на UNIX системах (OSX/GNU Linux).
2 ответа
Если вы говорите о библиотеке минизипов, которая входит в состав zlib, вы можете использовать unzOpen2
функция, которая позволяет вам указать структуру, содержащую функции ввода / вывода для использования. Это должно помочь вам начать:
struct zmem_data {
char *buf;
size_t length;
};
static voidpf zmemopen(voidpf opaque, const char *filename, int mode) {
if ((mode&ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) return NULL;
uLong *pos = malloc(sizeof(uLong));
*pos = 0;
return pos;
}
static uLong zmemread(voidpf opaque, voidpf stream, void* buf, uLong size) {
struct zmem_data *data = (struct zmem_data*)opaque;
uLong *pos = (uLong*)stream;
uLong remaining = data->length - *pos;
uLong readlength = size < remaining ? size : remaining;
if (*pos > data->length) return 0;
memcpy(buf, data->buf+*pos, readlength);
*pos += readlength;
return readlength;
}
static uLong zmemwrite(voidpf opaque, voidpf stream, const void *buf, uLong size) {
/* no write support for now */
return 0;
}
static int zmemclose(voidpf opaque, voidpf stream) {
free(stream);
return 0;
}
static int zmemerror(voidpf opaque, voidpf stream) {
if (stream == NULL) return 1;
else return 0;
}
static long zmemtell(voidpf opaque, voidpf stream) {
return *(uLong*)stream;
}
static long zmemseek(voidpf opaque, voidpf stream, uLong offset, int origin) {
struct zmem_data *data = (struct zmem_data*)opaque;
uLong *pos = (uLong*)stream;
switch (origin) {
case ZLIB_FILEFUNC_SEEK_SET:
*pos = offset;
break;
case ZLIB_FILEFUNC_SEEK_CUR:
*pos = *pos + offset;
break;
case ZLIB_FILEFUNC_SEEK_END:
*pos = data->length + offset;
break;
default:
return -1;
}
return 0;
}
static void init_zmemfile(zlib_filefunc_def *inst, char *buf, size_t length) {
struct zmem_data *data = malloc(sizeof(struct zmem_data));
data->buf = buf;
data->length = length;
inst->opaque = data;
inst->zopen_file = zmemopen;
inst->zread_file = zmemread;
inst->zwrite_file = zmemwrite;
inst->ztell_file = zmemtell;
inst->zseek_file = zmemseek;
inst->zclose_file = zmemclose;
inst->zerror_file = zmemerror;
}
static void destroy_zmemfile(zlib_filefunc_def *inst) {
free(inst->opaque);
inst->opaque = NULL;
}
void example() {
zlib_filefunc_dec fileops;
init_zmemfile(&fileops, buffer, buffer_length);
unzFile zf = unzOpen2(NULL, &fileops);
/* ... process zip file ... */
unzClose(zf);
destroy_zmemfile(&fileops);
}
Подводя итог вашего вопроса: Вы хотите предоставить FILE*
интерфейс для буфера в памяти. Нет, ты не можешь этого сделать. fread()
и т. д. вызовы фактически заканчиваются системными вызовами, которые имеют дело с дескриптором открытого файла, которого у вас нет.
Вы слишком усложняете это. Декомпрессионный код почти всегда работает из буферов, находящихся в памяти. Если у них есть файловый интерфейс, то, конечно, это просто оболочка, которая обрабатывает чтение файла в память, а затем распаковку (возможно, частями для экономии памяти). Вы должны быть в состоянии найти библиотеку распаковки с вызовами для распаковки буфера, который вы ей даете (только указатель и длина).
Почему вы не хотите записывать загруженные данные на жесткий диск, конечно, решать вам, но я надеюсь, что это на пользу, а не на зло.
Другой вариант - открыть файл с отображением в памяти, в который вы пишете во время загрузки и читаете во время распаковки. Может быть способ указать, что файл не записывается на диск, но в этом я не уверен. Кроме того, это будет сильно отличаться между Windows и Linux.
Это может помочь: