| 1 | #include "mupdf/fitz.h" |
| 2 | #include "fitz-imp.h" |
| 3 | |
| 4 | #include <string.h> |
| 5 | |
| 6 | #include <zlib.h> |
| 7 | |
| 8 | #if !defined (INT32_MAX) |
| 9 | #define INT32_MAX 2147483647L |
| 10 | #endif |
| 11 | |
| 12 | #define ZIP_LOCAL_FILE_SIG 0x04034b50 |
| 13 | #define ZIP_CENTRAL_DIRECTORY_SIG 0x02014b50 |
| 14 | #define ZIP_END_OF_CENTRAL_DIRECTORY_SIG 0x06054b50 |
| 15 | |
| 16 | struct fz_zip_writer_s |
| 17 | { |
| 18 | fz_output *output; |
| 19 | fz_buffer *central; |
| 20 | int count; |
| 21 | int closed; |
| 22 | }; |
| 23 | |
| 24 | void |
| 25 | fz_write_zip_entry(fz_context *ctx, fz_zip_writer *zip, const char *name, fz_buffer *buf, int compress) |
| 26 | { |
| 27 | int offset = fz_tell_output(ctx, zip->output); |
| 28 | int sum; |
| 29 | |
| 30 | sum = crc32(0, NULL, 0); |
| 31 | sum = crc32(sum, buf->data, (uInt)buf->len); |
| 32 | |
| 33 | fz_append_int32_le(ctx, zip->central, ZIP_CENTRAL_DIRECTORY_SIG); |
| 34 | fz_append_int16_le(ctx, zip->central, 0); /* version made by: MS-DOS */ |
| 35 | fz_append_int16_le(ctx, zip->central, 20); /* version to extract: 2.0 */ |
| 36 | fz_append_int16_le(ctx, zip->central, 0); /* general purpose bit flag */ |
| 37 | fz_append_int16_le(ctx, zip->central, 0); /* compression method: store */ |
| 38 | fz_append_int16_le(ctx, zip->central, 0); /* TODO: last mod file time */ |
| 39 | fz_append_int16_le(ctx, zip->central, 0); /* TODO: last mod file date */ |
| 40 | fz_append_int32_le(ctx, zip->central, sum); /* crc-32 */ |
| 41 | fz_append_int32_le(ctx, zip->central, (int)buf->len); /* csize */ |
| 42 | fz_append_int32_le(ctx, zip->central, (int)buf->len); /* usize */ |
| 43 | fz_append_int16_le(ctx, zip->central, (int)strlen(name)); /* file name length */ |
| 44 | fz_append_int16_le(ctx, zip->central, 0); /* extra field length */ |
| 45 | fz_append_int16_le(ctx, zip->central, 0); /* file comment length */ |
| 46 | fz_append_int16_le(ctx, zip->central, 0); /* disk number start */ |
| 47 | fz_append_int16_le(ctx, zip->central, 0); /* internal file attributes */ |
| 48 | fz_append_int32_le(ctx, zip->central, 0); /* external file attributes */ |
| 49 | fz_append_int32_le(ctx, zip->central, offset); /* relative offset of local header */ |
| 50 | fz_append_string(ctx, zip->central, name); |
| 51 | |
| 52 | fz_write_int32_le(ctx, zip->output, ZIP_LOCAL_FILE_SIG); |
| 53 | fz_write_int16_le(ctx, zip->output, 20); /* version to extract: 2.0 */ |
| 54 | fz_write_int16_le(ctx, zip->output, 0); /* general purpose bit flag */ |
| 55 | fz_write_int16_le(ctx, zip->output, 0); /* compression method: store */ |
| 56 | fz_write_int16_le(ctx, zip->output, 0); /* TODO: last mod file time */ |
| 57 | fz_write_int16_le(ctx, zip->output, 0); /* TODO: last mod file date */ |
| 58 | fz_write_int32_le(ctx, zip->output, sum); /* crc-32 */ |
| 59 | fz_write_int32_le(ctx, zip->output, (int)buf->len); /* csize */ |
| 60 | fz_write_int32_le(ctx, zip->output, (int)buf->len); /* usize */ |
| 61 | fz_write_int16_le(ctx, zip->output, (int)strlen(name)); /* file name length */ |
| 62 | fz_write_int16_le(ctx, zip->output, 0); /* extra field length */ |
| 63 | fz_write_data(ctx, zip->output, name, strlen(name)); |
| 64 | fz_write_data(ctx, zip->output, buf->data, buf->len); |
| 65 | |
| 66 | ++zip->count; |
| 67 | } |
| 68 | |
| 69 | void |
| 70 | fz_close_zip_writer(fz_context *ctx, fz_zip_writer *zip) |
| 71 | { |
| 72 | int64_t offset = fz_tell_output(ctx, zip->output); |
| 73 | |
| 74 | fz_write_data(ctx, zip->output, zip->central->data, zip->central->len); |
| 75 | |
| 76 | fz_write_int32_le(ctx, zip->output, ZIP_END_OF_CENTRAL_DIRECTORY_SIG); |
| 77 | fz_write_int16_le(ctx, zip->output, 0); /* number of this disk */ |
| 78 | fz_write_int16_le(ctx, zip->output, 0); /* number of disk where central directory starts */ |
| 79 | fz_write_int16_le(ctx, zip->output, zip->count); /* entries in central directory in this disk */ |
| 80 | fz_write_int16_le(ctx, zip->output, zip->count); /* entries in central directory in total */ |
| 81 | fz_write_int32_le(ctx, zip->output, (int)zip->central->len); /* size of the central directory */ |
| 82 | fz_write_int32_le(ctx, zip->output, (int)offset); /* offset of the central directory */ |
| 83 | fz_write_int16_le(ctx, zip->output, 5); /* zip file comment length */ |
| 84 | |
| 85 | fz_write_data(ctx, zip->output, "MuPDF" , 5); |
| 86 | |
| 87 | fz_close_output(ctx, zip->output); |
| 88 | |
| 89 | zip->closed = 1; |
| 90 | } |
| 91 | |
| 92 | void |
| 93 | fz_drop_zip_writer(fz_context *ctx, fz_zip_writer *zip) |
| 94 | { |
| 95 | if (!zip) |
| 96 | return; |
| 97 | if (!zip->closed) |
| 98 | fz_warn(ctx, "dropping unclosed zip writer" ); |
| 99 | fz_drop_output(ctx, zip->output); |
| 100 | fz_drop_buffer(ctx, zip->central); |
| 101 | fz_free(ctx, zip); |
| 102 | } |
| 103 | |
| 104 | fz_zip_writer * |
| 105 | fz_new_zip_writer(fz_context *ctx, const char *filename) |
| 106 | { |
| 107 | fz_zip_writer *zip = fz_malloc_struct(ctx, fz_zip_writer); |
| 108 | fz_try(ctx) |
| 109 | { |
| 110 | zip->output = fz_new_output_with_path(ctx, filename, 0); |
| 111 | zip->central = fz_new_buffer(ctx, 0); |
| 112 | } |
| 113 | fz_catch(ctx) |
| 114 | { |
| 115 | fz_drop_output(ctx, zip->output); |
| 116 | fz_drop_buffer(ctx, zip->central); |
| 117 | fz_free(ctx, zip); |
| 118 | fz_rethrow(ctx); |
| 119 | } |
| 120 | return zip; |
| 121 | } |
| 122 | |