Прочитать строку символа как виртуальный файл

Вопрос может показаться странным, но я не ошибся: я хочу распаковать некоторые загруженные данные, не записывая их на жесткий диск. Для этого я загружаю его в динамически размещенный буфер и хочу отправить его в используемую оболочку 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.

Это может помочь:

Другие вопросы по тегам