GPAK  1.0.0
A general-purpose archive library
gpak.c
1 #include "gpak.h"
2 
3 #include "filesystem_tree.h"
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdbool.h>
8 #include <assert.h>
9 
10 #ifdef _WIN32
11 #include "libfmemopen.h"
12 #endif
13 
14 #include "gpak_compressors.h"
15 #include "gpak_helper.h"
16 
17 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
18 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
19 //---------------------------------HELPERS--------------------------------
20 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
21 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
22 
23 pak_header_t _pak_make_header()
24 {
25  pak_header_t _header;
26 
27  strcpy(_header.format_, "gpak\0");
29  _header.compression_level_ = 0;
30  _header.entry_count_ = 0u;
31  _header.dictionary_size_ = 0u;
32 
33  return _header;
34 }
35 
36 int _pak_validate_header(gpak_t* _pak)
37 {
38  if (strcmp(_pak->header_.format_, "gpak") != 0)
39  return _gpak_make_error(_pak, GPAK_ERROR_INCORRECT_HEADER);
40 
41  return _gpak_make_error(_pak, GPAK_ERROR_OK);
42 }
43 
44 long _write_entry_header(gpak_t* _pak, const char* _path, pak_entry_t* _entry)
45 {
46  long bytes_writen = 0u;
47 
48  // Write filename
49  short name_size = strlen(_path);
50  bytes_writen += _fwriteb(&name_size, sizeof(short), 1ull, _pak->stream_);
51  bytes_writen += _fwriteb(_path, 1ull, name_size, _pak->stream_);
52  bytes_writen += _fwriteb(_entry, sizeof(pak_entry_t), 1ull, _pak->stream_);
53 
54  return bytes_writen;
55 }
56 
57 long _read_entry_header(gpak_t* _pak, char* _path, pak_entry_t* _entry)
58 {
59  long bytes_readed = 0u;
60 
61  short name_size;
62  bytes_readed += _freadb(&name_size, sizeof(short), 1ull, _pak->stream_);
63  bytes_readed += _freadb(_path, 1ull, name_size, _pak->stream_);
64  bytes_readed += _freadb(_entry, sizeof(pak_entry_t), 1ull, _pak->stream_);
65  _path[name_size] = '\0';
66 
67  return bytes_readed;
68 }
69 
70 int _update_entry_header(gpak_t* _pak, size_t _commressed_size, size_t _uncompressed_size, long _entry_size, uint32_t _crc32)
71 {
72  pak_entry_t _entry;
73 
74  if (!_pak->stream_ )
75  return _gpak_make_error(_pak, GPAK_ERROR_STREAM_IS_NULL);
76 
77  size_t _shift = 0ull;
78  if (_uncompressed_size == _commressed_size)
79  _shift = _uncompressed_size;
80  else
81  _shift = _commressed_size;
82 
83  long _cur_pos = ftell(_pak->stream_);
84  fseek(_pak->stream_, -((long)_shift), SEEK_CUR);
85  long _offset = ftell(_pak->stream_);
86  fseek(_pak->stream_, -_entry_size, SEEK_CUR);
87 
88  char _entry_path[256];
89  _read_entry_header(_pak, _entry_path, &_entry);
90 
91  _entry.compressed_size_ = _commressed_size;
92  _entry.uncompressed_size_ = _uncompressed_size;
93  _entry.crc32_ = _crc32;
94  _entry.offset_ = _offset;
95 
96  fseek(_pak->stream_, -_entry_size, SEEK_CUR);
97 
98  _write_entry_header(_pak, _entry_path, &_entry);
99 
100  fseek(_pak->stream_, 0l, SEEK_END);
101 
102  if (_cur_pos != ftell(_pak->stream_))
103  return _gpak_make_error(_pak, GPAK_ERROR_WRITE);
104 
105  return GPAK_ERROR_OK;
106 }
107 
108 int _update_pak_header(gpak_t* _pak)
109 {
110  fseek(_pak->stream_, 0, SEEK_SET);
111 
112  size_t readed = _fwriteb(&_pak->header_, sizeof(pak_header_t), 1ull, _pak->stream_);
113  if (readed != sizeof(pak_header_t))
114  {
115  fseek(_pak->stream_, 0l, SEEK_END);
116  return _gpak_make_error(_pak, GPAK_ERROR_WRITE);
117  }
118 
119  return GPAK_ERROR_OK;
120 }
121 
122 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
123 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
124 //--------------------------------FILE TREE-------------------------------
125 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
126 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
127 int _gpak_archivate_file_tree(gpak_t* _pak)
128 {
130  filesystem_tree_node_t* next_directory = _pak->root_;
131  do
132  {
133  filesystem_tree_file_t* next_file = NULL;
134  while ((next_file = filesystem_iterator_next_file(iterator)))
135  {
136  // Write file header first
137  _pak->current_file_ = filesystem_tree_file_path(next_directory, next_file);
138  pak_entry_t _entry;
139  long header_size = _write_entry_header(_pak, _pak->current_file_, &_entry);
140 
141  FILE* _infile = fopen(next_file->path_, "rb");
142  FILE* _outfile = NULL;
143  if (!_infile)
144  return _gpak_make_error(_pak, GPAK_ERROR_OPEN_FILE);
145 
146  long cursor = ftell(_pak->stream_);
147 
148  uint32_t _crc32 = 0u;
150  _crc32 = _gpak_compressor_deflate(_pak, _infile, _pak->stream_);
152  _crc32 = _gpak_compressor_zstd(_pak, _infile, _pak->stream_);
153  else
154  _crc32 = _gpak_compressor_none(_pak, _infile, _pak->stream_);
155 
156  long position = ftell(_pak->stream_);
157  size_t uncompressed_size = ftell(_infile);
158  size_t compressed_size = position - cursor;
159 
160  fflush(_pak->stream_);
161 
162  _update_entry_header(_pak, compressed_size, uncompressed_size, header_size, _crc32);
163 
164  free(_pak->current_file_);
165  fclose(_infile);
166  }
167  } while ((next_directory = filesystem_iterator_next_directory(iterator)));
168 
169  filesystem_iterator_free(iterator);
170 
171  return _gpak_make_error(_pak, GPAK_ERROR_OK);
172 }
173 
174 int _gpak_parse_dictionary(gpak_t* _pak)
175 {
176  if(_pak->header_.dictionary_size_ == 0u)
177  return _gpak_make_error(_pak, GPAK_ERROR_OK);
178 
179  _pak->dictionary_ = (char*)malloc(_pak->header_.dictionary_size_ + 1);
180  _pak->dictionary_[_pak->header_.dictionary_size_] = '\0';
181 
182  size_t readed = _freadb(_pak->dictionary_, 1ull, _pak->header_.dictionary_size_, _pak->stream_);
183 
184  if(readed != _pak->header_.dictionary_size_)
185  return _gpak_make_error(_pak, GPAK_ERROR_INVALID_DICTIONARY);
186 
187  return _gpak_make_error(_pak, GPAK_ERROR_OK);
188 }
189 
190 int _gpak_parse_file_tree(gpak_t* _pak)
191 {
192  while (1)
193  {
194  char _filename[256];
195  pak_entry_t _entry;
196  size_t readed = _read_entry_header(_pak, _filename, &_entry);
197  if (readed == 0)
198  break; // EOF
199 
200  filesystem_tree_add_file(_pak->root_, _filename, NULL, _entry);
201 
202  fseek(_pak->stream_, _entry.compressed_size_, SEEK_CUR);
203  }
204 
205  return _gpak_make_error(_pak, GPAK_ERROR_OK);
206 }
207 
208 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
209 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
210 //-----------------------------IMPLEMENTATION-----------------------------
211 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
212 //-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
213 gpak_t* gpak_open(const char* _path, int _mode)
214 {
215  gpak_t* pak;
216  pak = (gpak_t*)calloc(1, sizeof(gpak_t));
217  pak->mode_ = _mode;
218  pak->current_file_ = NULL;
219  pak->error_handler_ = NULL;
220  pak->progress_handler_ = NULL;
221  pak->user_data_ = NULL;
222  pak->dictionary_ = NULL;
223 
224  const char* open_mode_;
225  if (_mode & GPAK_MODE_CREATE)
226  open_mode_ = "wb+";
227  else if (_mode & GPAK_MODE_READ_ONLY)
228  open_mode_ = "rb+";
229  else if (_mode & GPAK_MODE_UPDATE)
230  open_mode_ = "ab+";
231  else
232  {
233  gpak_close(pak);
234  return NULL;
235  }
236 
237  // Trying to open pak file
238  pak->stream_ = fopen(_path, open_mode_);
239 
240  if (pak->stream_ == NULL)
241  {
242  gpak_close(pak);
243  return NULL;
244  }
245 
246  pak->root_ = filesystem_tree_create();
247 
248  if (_mode & GPAK_MODE_CREATE)
249  {
250  pak->header_ = _pak_make_header();
251  size_t res = _fwriteb(&pak->header_, sizeof(pak_header_t), 1ull, pak->stream_);
252  if (res != sizeof(pak_header_t))
253  {
254  gpak_close(pak);
255  return NULL;
256  }
257  }
258  else if (_mode & GPAK_MODE_UPDATE)
259  {
260  fseek(pak->stream_, 0, SEEK_SET);
261 
262  size_t res = _freadb(&pak->header_, sizeof(pak_header_t), 1ull, pak->stream_);
263  if (_pak_validate_header(pak) != GPAK_ERROR_OK || res != sizeof(pak_header_t))
264  {
265  gpak_close(pak);
266  return NULL;
267  }
268 
269  _gpak_parse_dictionary(pak);
270  _gpak_parse_file_tree(pak);
271 
272  fseek(pak->stream_, 0, SEEK_END);
273  }
274  else if (_mode & GPAK_MODE_READ_ONLY)
275  {
276  size_t res = _freadb(&pak->header_, sizeof(pak_header_t), 1ull, pak->stream_);
277  if (_pak_validate_header(pak) != GPAK_ERROR_OK || res != sizeof(pak_header_t))
278  {
279  gpak_close(pak);
280  return NULL;
281  }
282 
283  _gpak_parse_dictionary(pak);
284  _gpak_parse_file_tree(pak);
285  }
286 
287  return pak;
288 }
289 
290 int gpak_close(gpak_t* _pak)
291 {
292  if (_pak != NULL)
293  {
294  if (_pak->stream_ != NULL)
295  {
296  // Recalculate header
297 
298  if ((_pak->mode_ & GPAK_MODE_CREATE) || (_pak->mode_ & GPAK_MODE_UPDATE))
299  {
300  if (_pak->mode_ & GPAK_MODE_CREATE)
301  {
304  }
305 
306  _gpak_archivate_file_tree(_pak);
307  }
308 
310 
311  _update_pak_header(_pak);
312  fclose(_pak->stream_);
313  }
314 
315  free(_pak->dictionary_);
316  free(_pak);
317  return _gpak_make_error(_pak, GPAK_ERROR_OK);
318  }
319 
320  return -1;
321 }
322 
323 GPAK_API void gpak_set_user_data(gpak_t* _pak, void* _user_data)
324 {
325  _pak->user_data_ = _user_data;
326 }
327 
328 GPAK_API void gpak_set_error_handler(gpak_t* _pak, gpak_error_handler_t _error_handler)
329 {
330  _pak->error_handler_ = _error_handler;
331 }
332 
333 GPAK_API void gpak_set_process_handler(gpak_t* _pak, gpak_progress_handler_t _progress_handler)
334 {
335  _pak->progress_handler_ = _progress_handler;
336 }
337 
338 void gpak_set_compression_algorithm(gpak_t* _pak, int _algorithm)
339 {
340  _pak->header_.compression_ = _algorithm;
341 }
342 
343 void gpak_set_compression_level(gpak_t* _pak, int _level)
344 {
345  _pak->header_.compression_level_ = _level;
346 }
347 
348 int gpak_add_directory(gpak_t* _pak, const char* _internal_path)
349 {
350  filesystem_tree_add_directory(_pak->root_, _internal_path);
351  return _gpak_make_error(_pak, GPAK_ERROR_OK);
352 }
353 
354 int gpak_add_file(gpak_t* _pak, const char* _external_path, const char* _internal_path)
355 {
356  pak_entry_t _entry;
357  _entry.compressed_size_ = 0u;
358  _entry.uncompressed_size_ = 0u;
359  _entry.offset_ = 0u;
360  _entry.crc32_ = 0;
361 
362  ++_pak->header_.entry_count_;
363 
364  filesystem_tree_add_file(_pak->root_, _internal_path, _external_path, _entry);
365  return _gpak_make_error(_pak, GPAK_ERROR_OK);
366 }
367 
369 {
370  return _pak->root_;
371 }
372 
374 {
375  if (_pak == NULL)
376  return NULL;
377 
378  return filesystem_tree_find_directory(_pak->root_, _path);
379 }
380 
381 filesystem_tree_file_t* gpak_find_file(gpak_t* _pak, const char* _path)
382 {
383  if (_pak == NULL)
384  return NULL;
385 
386  return filesystem_tree_find_file(_pak->root_, _path);
387 }
388 
389 gpak_file_t* gpak_fopen(gpak_t* _pak, const char* _path)
390 {
391  filesystem_tree_file_t* _file_info = filesystem_tree_find_file(_pak->root_, _path);
392  if (!_file_info)
393  {
394  _gpak_make_error(_pak, GPAK_ERROR_FILE_NOT_FOUND);
395  return NULL;
396  }
397 
398  _pak->current_file_ = filesystem_tree_file_path(_pak->root_, _file_info);
399 
400  uint32_t uncompressed_size = _file_info->entry_.uncompressed_size_;
401  uint32_t compressed_size = _file_info->entry_.compressed_size_;
402 
403  gpak_file_t* mfile = (gpak_file_t*)malloc(sizeof(gpak_file_t));
404  mfile->data_ = (char*)malloc(uncompressed_size + 1);
405  mfile->data_[uncompressed_size] = '\0';
406 
407  mfile->stream_ = fmemopen(mfile->data_, uncompressed_size, "wb+");
408 
409  // Setting position to file start
410  fseek(_pak->stream_, _file_info->entry_.offset_, SEEK_SET);
411 
413  mfile->crc32_ = _gpak_decompressor_inflate(_pak, _pak->stream_, mfile->stream_, compressed_size);
415  mfile->crc32_ = _gpak_decompressor_zstd(_pak, _pak->stream_, mfile->stream_, compressed_size);
416  else
417  mfile->crc32_ = _gpak_decompressor_none(_pak, _pak->stream_, mfile->stream_, compressed_size);
418 
419  fseek(mfile->stream_, 0, SEEK_SET);
420 
421  // Check crc32
422  if (mfile->crc32_ != _file_info->entry_.crc32_)
423  {
424  _gpak_make_error(_pak, GPAK_ERROR_FILE_CRC_NOT_MATCH);
425  free(_pak->current_file_);
426  gpak_fclose(mfile);
427  return NULL;
428  }
429 
430  free(_pak->current_file_);
431 
432  return mfile;
433 }
434 
436 {
437  return fgetc(_file->stream_);
438 }
439 
440 char* gpak_fgets(gpak_file_t* _file, char* _buffer, int _max)
441 {
442  return fgets(_buffer, _max, _file->stream_);
443 }
444 
445 int gpak_ungetc(gpak_file_t* _file, int _character)
446 {
447  return ungetc(_character, _file->stream_);
448 }
449 
450 size_t gpak_fread(void* _buffer, size_t _elemSize, size_t _elemCount, gpak_file_t* _file)
451 {
452  return fread(_buffer, _elemSize, _elemCount, _file->stream_);
453 }
454 
456 {
457  return ftell(_file->stream_);
458 }
459 
460 long gpak_fseek(gpak_file_t* _file, long _offset, int _origin)
461 {
462  return fseek(_file->stream_, _offset, _origin);
463 }
464 
465 long gpak_feof(gpak_file_t* _file)
466 {
467  return feof(_file->stream_);
468 }
469 
471 {
472  free(_file->data_);
473  fclose(_file->stream_);
474  free(_file);
475 }
GPAK_API filesystem_tree_node_t * filesystem_tree_find_directory(filesystem_tree_node_t *_root, const char *_path)
GPAK_API char * filesystem_tree_file_path(filesystem_tree_node_t *_node, filesystem_tree_file_t *_file)
GPAK_API filesystem_tree_node_t * filesystem_tree_create()
GPAK_API filesystem_tree_node_t * filesystem_iterator_next_directory(filesystem_tree_iterator_t *_iterator)
GPAK_API void filesystem_iterator_free(filesystem_tree_iterator_t *_iterator)
GPAK_API void filesystem_tree_delete(filesystem_tree_node_t *_root)
GPAK_API void filesystem_tree_add_file(filesystem_tree_node_t *_root, const char *_path, const char *_file_path, pak_entry_t _entry)
GPAK_API void filesystem_tree_add_directory(filesystem_tree_node_t *_root, const char *_path)
GPAK_API filesystem_tree_iterator_t * filesystem_iterator_create(filesystem_tree_node_t *_root)
GPAK_API filesystem_tree_file_t * filesystem_iterator_next_file(filesystem_tree_iterator_t *_iterator)
GPAK_API filesystem_tree_file_t * filesystem_tree_find_file(filesystem_tree_node_t *_root, const char *_path)
GPAK_API struct filesystem_tree_file * gpak_find_file(gpak_t *_pak, const char *_path)
Definition: gpak.c:381
GPAK_API void gpak_set_compression_algorithm(gpak_t *_pak, int _algorithm)
Definition: gpak.c:338
GPAK_API long gpak_feof(gpak_file_t *_file)
Definition: gpak.c:465
GPAK_API int gpak_fgetc(gpak_file_t *_file)
Definition: gpak.c:435
GPAK_API int gpak_add_file(gpak_t *_pak, const char *_external_path, const char *_internal_path)
Definition: gpak.c:354
GPAK_API gpak_t * gpak_open(const char *_path, int _mode)
Definition: gpak.c:213
GPAK_API char * gpak_fgets(gpak_file_t *_file, char *_buffer, int _max)
Definition: gpak.c:440
GPAK_API size_t gpak_fread(void *_buffer, size_t _elemSize, size_t _elemCount, gpak_file_t *_file)
Definition: gpak.c:450
GPAK_API void gpak_set_error_handler(gpak_t *_pak, gpak_error_handler_t _error_handler)
Definition: gpak.c:328
GPAK_API int gpak_close(gpak_t *_pak)
Definition: gpak.c:290
GPAK_API int gpak_ungetc(gpak_file_t *_file, int _character)
Definition: gpak.c:445
GPAK_API void gpak_set_user_data(gpak_t *_pak, void *_user_data)
Definition: gpak.c:323
GPAK_API void gpak_set_compression_level(gpak_t *_pak, int _level)
Definition: gpak.c:343
GPAK_API gpak_file_t * gpak_fopen(gpak_t *_pak, const char *_path)
Definition: gpak.c:389
GPAK_API struct filesystem_tree_node * gpak_find_directory(gpak_t *_pak, const char *_path)
Definition: gpak.c:373
GPAK_API long gpak_fseek(gpak_file_t *_file, long _offset, int _origin)
Definition: gpak.c:460
GPAK_API long gpak_ftell(gpak_file_t *_file)
Definition: gpak.c:455
GPAK_API struct filesystem_tree_node * gpak_get_root(gpak_t *_pak)
Definition: gpak.c:368
GPAK_API int gpak_add_directory(gpak_t *_pak, const char *_internal_path)
Definition: gpak.c:348
GPAK_API void gpak_fclose(gpak_file_t *_file)
Definition: gpak.c:470
GPAK_API void gpak_set_process_handler(gpak_t *_pak, gpak_progress_handler_t _progress_handler)
Definition: gpak.c:333
GPAK_API uint32_t _gpak_compressor_deflate(gpak_t *_pak, FILE *_infile, FILE *_outfile)
GPAK_API uint32_t _gpak_compressor_none(gpak_t *_pak, FILE *_infile, FILE *_outfile)
GPAK_API uint32_t _gpak_decompressor_none(gpak_t *_pak, FILE *_infile, FILE *_outfile, size_t _read_size)
GPAK_API uint32_t _gpak_decompressor_inflate(gpak_t *_pak, FILE *_infile, FILE *_outfile, size_t _read_size)
GPAK_API uint32_t _gpak_decompressor_zstd(gpak_t *_pak, FILE *_infile, FILE *_outfile, size_t _read_size)
GPAK_API int32_t _gpak_compressor_generate_dictionary(gpak_t *_pak)
GPAK_API uint32_t _gpak_compressor_zstd(gpak_t *_pak, FILE *_infile, FILE *_outfile)
@ GPAK_HEADER_COMPRESSION_NONE
Definition: gpak_data.h:34
@ GPAK_HEADER_COMPRESSION_ZST
Definition: gpak_data.h:36
@ GPAK_HEADER_COMPRESSION_DEFLATE
Definition: gpak_data.h:35
@ GPAK_MODE_READ_ONLY
Definition: gpak_data.h:208
@ GPAK_MODE_CREATE
Definition: gpak_data.h:207
@ GPAK_MODE_UPDATE
Definition: gpak_data.h:209
void(* gpak_error_handler_t)(const char *, int32_t, void *)
Definition: gpak_data.h:241
void(* gpak_progress_handler_t)(const char *, size_t, size_t, int32_t, void *)
Definition: gpak_data.h:247
@ GPAK_ERROR_INVALID_DICTIONARY
Definition: gpak_data.h:188
@ GPAK_ERROR_WRITE
Definition: gpak_data.h:161
@ GPAK_ERROR_STREAM_IS_NULL
Definition: gpak_data.h:157
@ GPAK_ERROR_OPEN_FILE
Definition: gpak_data.h:160
@ GPAK_ERROR_FILE_NOT_FOUND
Definition: gpak_data.h:163
@ GPAK_ERROR_OK
Definition: gpak_data.h:155
@ GPAK_ERROR_INCORRECT_HEADER
Definition: gpak_data.h:159
@ GPAK_ERROR_FILE_CRC_NOT_MATCH
Definition: gpak_data.h:185
pak_entry_t entry_
Definition: gpak_data.h:306
uint32_t crc32_
Definition: gpak_data.h:137
uint32_t uncompressed_size_
Definition: gpak_data.h:135
uint32_t compressed_size_
Definition: gpak_data.h:134
size_t offset_
Definition: gpak_data.h:136
Definition: gpak_data.h:133
uint32_t crc32_
Definition: gpak_data.h:286
FILE * stream_
Definition: gpak_data.h:285
char * data_
Definition: gpak_data.h:284
char format_[5]
Definition: gpak_data.h:112
uint32_t entry_count_
Definition: gpak_data.h:115
char compression_level_
Definition: gpak_data.h:114
uint32_t dictionary_size_
Definition: gpak_data.h:116
gpak_header_compression_algorithm_t compression_
Definition: gpak_data.h:113
gpak_progress_handler_t progress_handler_
Definition: gpak_data.h:265
char * current_file_
Definition: gpak_data.h:263
char * dictionary_
Definition: gpak_data.h:262
struct filesystem_tree_node * root_
Definition: gpak_data.h:260
void * user_data_
Definition: gpak_data.h:266
gpak_error_handler_t error_handler_
Definition: gpak_data.h:264
FILE * stream_
Definition: gpak_data.h:259
int mode_
Definition: gpak_data.h:257
pak_header_t header_
Definition: gpak_data.h:258