2
* Copyright (C) 1999, 2000 Bryan Burns
3
* Copyright (C) 2004 Johan Ceuppens
5
* Released under GNU GPL, read the file 'COPYING' for more information
10
* - configure #ifdefs should be enabled
11
* - move to cstdlib instead of stdlib.h etc.
12
* - remove exit functions
13
* - move to clean C++ code
15
* - remove a few g_free/g_mallocs
17
* - move to LGPL by rewriting macros
18
* - crcs for compressed files
30
//#ifdef HAVE_UNISTD_H
33
//#ifdef HAVE_SYS_PARAM_H
35
//#define MAXPATHLEN 1024
38
//#ifdef HAVE_DIRENT_H
54
#ifdef WORDS_BIGENDIAN
56
#define L2BI(l) ((l & 0xff000000) >> 24) | \
57
((l & 0x00ff0000) >> 8) | \
58
((l & 0x0000ff00) << 8) | \
59
((l & 0x000000ff) << 24);
61
#define L2BS(l) ((l & 0xff00) >> 8) | ((l & 0x00ff) << 8);
67
JarFile::JarFile(gchar const*new_filename)
69
_filename = strdup(new_filename);
70
_last_filename = NULL;
74
//fixme: the following should probably just return a const gchar* and not
76
gchar *JarFile::get_last_filename() const
78
return (_last_filename != NULL ? strdup(_last_filename) : NULL);
83
if (_filename != NULL)
85
if (_last_filename != NULL)
86
g_free(_last_filename);
89
bool JarFile::init_inflation()
91
memset(&_zs, 0, sizeof(z_stream));
97
if(inflateInit2(&_zs, -15) != Z_OK) {
98
fprintf(stderr,"error initializing inflation!\n");
107
if ((fd = ::open(_filename, O_RDONLY)) < 0) {
108
fprintf(stderr, "open failed.\n");
111
if (!init_inflation())
117
bool JarFile::close()
119
if (fd >= 0 && !::close(fd)) {
126
bool JarFile::read_signature()
128
guint8 *bytes = (guint8 *)g_malloc(sizeof(guint8) * 4);
129
if (!read(bytes, 4)) {
134
guint32 signature = UNPACK_UB4(bytes, 0);
138
std::printf("signature is %x\n", signature);
141
if (signature == 0x08074b50) {
142
//skip data descriptor
143
bytes = (guint8 *)malloc(sizeof(guint8) * 12);
144
if (!read(bytes, 12)) {
148
} else if (signature == 0x02014b50 || signature == 0x04034b50) {
156
guint32 JarFile::get_crc(guint8 *bytes, guint16 flags)
160
if (!(flags & 0x0008)) {
161
crc = UNPACK_UB4(bytes, LOC_CRC);
164
std::printf("CRC from file is %x\n", crc);
171
guint8 *JarFile::read_filename(guint16 filename_length)
173
guint8 *filename = (guint8 *)g_malloc(sizeof(guint8)
174
* (filename_length+1));
175
if (!read(filename, filename_length)) {
179
filename[filename_length] = '\0';
182
std::printf("Filename is %s\n", filename);
188
bool JarFile::check_compression_method(guint16 method, guint16 flags)
190
return !(method != 8 && flags & 0x0008);
193
GByteArray *JarFile::get_next_file_contents()
196
GByteArray *gba = g_byte_array_new();
200
//get compressed size
201
bytes = (guint8 *)g_malloc(sizeof(guint8) * 30);
202
if (!read(bytes+4, 26)) {
206
guint32 compressed_size = UNPACK_UB4(bytes, LOC_CSIZE);
207
guint16 filename_length = UNPACK_UB2(bytes, LOC_FNLEN);
208
guint16 eflen = UNPACK_UB2(bytes, LOC_EFLEN);
209
guint16 flags = UNPACK_UB2(bytes, LOC_EXTRA);
210
guint16 method = UNPACK_UB2(bytes, LOC_COMP);
212
if (filename_length == 0) {
213
g_byte_array_free(gba, TRUE);
214
if (_last_filename != NULL)
215
g_free(_last_filename);
216
_last_filename = NULL;
222
std::printf("Compressed size is %u\n", compressed_size);
223
std::printf("Filename length is %hu\n", filename_length);
224
std::printf("Extra field length is %hu\n", eflen);
225
std::printf("Flags are %#hx\n", flags);
226
std::printf("Compression method is %#hx\n", method);
229
guint32 crc = get_crc(bytes, flags);
231
gchar *filename = (gchar *)read_filename(filename_length);
234
if (filename == NULL)
237
if (_last_filename != NULL)
238
g_free(_last_filename);
239
_last_filename = filename;
241
//check if this is a directory and skip
244
if ((c_ptr = std::strrchr(filename, '/')) != NULL) {
245
if (*(++c_ptr) == '\0') {
250
if (!check_compression_method(method, flags)) {
251
std::fprintf(stderr, "error in jar file\n");
255
if (method == 8 || flags & 0x0008) {
256
unsigned int file_length = 0;//uncompressed file length
257
lseek(fd, eflen, SEEK_CUR);
258
guint8 *file_data = get_compressed_file(compressed_size, file_length,
260
if (file_data == NULL) {
261
g_byte_array_free(gba, FALSE);
264
g_byte_array_append(gba, file_data, file_length);
265
} else if (method == 0) {
266
guint8 *file_data = get_uncompressed_file(compressed_size, crc,
269
if (file_data == NULL) {
270
g_byte_array_free(gba, TRUE);
273
g_byte_array_append(gba, file_data, compressed_size);
275
lseek(fd, compressed_size+eflen, SEEK_CUR);
276
g_byte_array_free(gba, FALSE);
284
guint8 *JarFile::get_uncompressed_file(guint32 compressed_size, guint32 crc,
285
guint16 eflen, guint16 flags)
287
GByteArray *gba = g_byte_array_new();
288
unsigned int out_a = 0;
289
unsigned int in_a = compressed_size;
293
crc2 = crc32(crc2, NULL, 0);
295
bytes = (guint8 *)g_malloc(sizeof(guint8) * RDSZ);
296
while(out_a < compressed_size){
297
unsigned int nbytes = (in_a > RDSZ ? RDSZ : in_a);
299
if (!(nbytes = read(bytes, nbytes))) {
304
crc2 = crc32(crc2, (Bytef*)bytes, nbytes);
306
g_byte_array_append (gba, bytes, nbytes);
311
std::printf("%d bytes written\n", out_a);
314
lseek(fd, eflen, SEEK_CUR);
317
if (!check_crc(crc, crc2, flags)) {
319
g_byte_array_free(gba, FALSE);//FALSE argument does not free actual data
326
int JarFile::read(guint8 *buf, int count)
329
if ((nbytes = ::read(fd, buf, count)) != count) {
330
fprintf(stderr, "read error\n");
337
/* FIXME: this could probably use ZlibBuffer */
338
guint8 *JarFile::get_compressed_file(guint32 compressed_size,
339
unsigned int& file_length,
340
guint32 oldcrc, guint16 flags)
342
if (compressed_size == 0)
345
guint8 in_buffer[RDSZ];
346
guint8 out_buffer[RDSZ];
348
unsigned int leftover_in = compressed_size;
349
GByteArray *gba = g_byte_array_new();
352
guint32 crc = crc32(0, Z_NULL, 0);
358
if ((nbytes = ::read(fd, in_buffer,
359
(leftover_in < RDSZ ? leftover_in : RDSZ)))
361
fprintf(stderr, "jarfile read error");
363
_zs.avail_in = nbytes;
364
_zs.next_in = in_buffer;
365
crc = crc32(crc, in_buffer, _zs.avail_in);
368
_zs.next_out = out_buffer;
369
_zs.avail_out = RDSZ;
371
int ret = inflate(&_zs, Z_NO_FLUSH);
372
if (RDSZ != _zs.avail_out) {
373
unsigned int tmp_len = RDSZ - _zs.avail_out;
374
guint8 *tmp_bytes = (guint8 *)g_malloc(sizeof(guint8)
376
memcpy(tmp_bytes, out_buffer, tmp_len);
377
g_byte_array_append(gba, tmp_bytes, tmp_len);
380
if (ret == Z_STREAM_END) {
384
std::printf("decompression error %d\n", ret);
385
} while (_zs.total_in < compressed_size);
387
file_length = _zs.total_out;
389
std::printf("done inflating\n");
390
std::printf("%d bytes left over\n", _zs.avail_in);
391
std::printf("CRC is %x\n", crc);
395
if (check_crc(oldcrc, crc, flags) && gba->len > 0)
396
ret_bytes = gba->data;
399
g_byte_array_free(gba, FALSE);
405
bool JarFile::check_crc(guint32 oldcrc, guint32 crc, guint16 flags)
407
//fixme: does not work yet
410
guint8 *bytes = (guint8 *)g_malloc(sizeof(guint8) * 16);
411
if (!read(bytes, 16)) {
416
guint32 signature = UNPACK_UB4(bytes, 0);
418
if(signature != 0x08074b50) {
419
fprintf(stderr, "missing data descriptor!\n");
422
crc = UNPACK_UB4(bytes, 4);
427
std::fprintf(stderr, "Error! CRCs do not match! Got %x, expected %x\n",
434
JarFile::JarFile(JarFile const& rhs)
439
JarFile& JarFile::operator=(JarFile const& rhs)
444
_zs = rhs._zs;//fixme
445
if (_filename == NULL)
448
_filename = strdup(rhs._filename);
449
if (_last_filename == NULL)
450
_last_filename = NULL;
452
_last_filename = strdup(rhs._last_filename);
459
/////////////////////////
461
/////////////////////////
463
GByteArray *JarFileReader::get_next_file()
465
if (_state == CLOSED) {
470
return _jarfile.get_next_file_contents();
473
JarFileReader& JarFileReader::operator=(JarFileReader const& rhs)
478
_jarfile = rhs._jarfile;
485
* If the filename gets reset, a jarfile object gets generated again,
486
* ready to be opened for reading.
488
void JarFileReader::set_filename(gchar const *new_filename)
491
_jarfile = JarFile(new_filename);
494
void JarFileReader::set_jarfile(JarFile const& new_jarfile)
496
_jarfile = new_jarfile;
499
JarFileReader::JarFileReader(JarFileReader const& rhs)
504
} // namespace Inkjar
510
* This program writes all the files from a jarfile to stdout and inflates
513
int main(int argc, char *argv[])
517
filename = "./ide.jar\0";
522
Inkjar::JarFileReader jar_file_reader(filename);
525
GByteArray *gba = jar_file_reader.get_next_file();
528
gchar *last_filename = jar_file_reader.get_last_filename();
529
if (last_filename == NULL)
531
if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
532
if (*(++c_ptr) == '\0') {
533
g_free(last_filename);
537
} else if (gba->len > 0)
538
::write(1, gba->data, gba->len);