~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/inkjar/jar.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1999, 2000  Bryan Burns
 
3
 * Copyright (C) 2004 Johan Ceuppens
 
4
 *
 
5
 * Released under GNU GPL, read the file 'COPYING' for more information
 
6
 */
 
7
 
 
8
/*
 
9
 * TODO/FIXME: 
 
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
 
14
 * - windowsify
 
15
 * - remove a few g_free/g_mallocs
 
16
 * - unseekable files
 
17
 * - move to LGPL by rewriting macros
 
18
 * - crcs for compressed files
 
19
 * - put in eof
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
# include "config.h"
 
24
#endif
 
25
 
 
26
 
 
27
//#ifdef STDC_HEADERS
 
28
//#endif
 
29
 
 
30
//#ifdef HAVE_UNISTD_H
 
31
//#endif
 
32
 
 
33
//#ifdef HAVE_SYS_PARAM_H
 
34
//#else
 
35
//#define MAXPATHLEN 1024
 
36
//#endif
 
37
 
 
38
//#ifdef HAVE_DIRENT_H
 
39
//#endif
 
40
 
 
41
//#ifdef HAVE_FCNTL_H
 
42
#include <fcntl.h>
 
43
//#endif
 
44
 
 
45
#include <cstring>
 
46
#include <string>
 
47
#include <cstdlib>
 
48
#include <glib.h>
 
49
#include <zlib.h>
 
50
 
 
51
#include "jar.h"
 
52
 
 
53
#include <fstream>
 
54
#ifdef WORDS_BIGENDIAN
 
55
 
 
56
#define L2BI(l) ((l & 0xff000000) >> 24) | \
 
57
((l & 0x00ff0000) >> 8)  | \
 
58
((l & 0x0000ff00) << 8)  | \
 
59
((l & 0x000000ff) << 24);
 
60
 
 
61
#define L2BS(l) ((l & 0xff00) >> 8) | ((l & 0x00ff) << 8);
 
62
 
 
63
#endif
 
64
 
 
65
namespace Inkjar {
 
66
 
 
67
JarFile::JarFile(gchar const*new_filename)
 
68
{
 
69
    _filename = strdup(new_filename);
 
70
    _last_filename = NULL;
 
71
    fd = -1;
 
72
}
 
73
 
 
74
//fixme: the following should probably just return a const gchar* and not 
 
75
//       use strdup
 
76
gchar *JarFile::get_last_filename() const
 
77
{
 
78
    return (_last_filename != NULL ? strdup(_last_filename) : NULL);
 
79
}
 
80
 
 
81
JarFile::~JarFile()
 
82
 
83
    if (_filename != NULL)
 
84
        g_free(_filename); 
 
85
    if (_last_filename != NULL)
 
86
        g_free(_last_filename); 
 
87
}
 
88
 
 
89
bool JarFile::init_inflation()
 
90
{
 
91
    memset(&_zs, 0, sizeof(z_stream));
 
92
    
 
93
    _zs.zalloc = Z_NULL;
 
94
    _zs.zfree = Z_NULL;
 
95
    _zs.opaque = Z_NULL;
 
96
    
 
97
    if(inflateInit2(&_zs, -15) != Z_OK) {
 
98
        fprintf(stderr,"error initializing inflation!\n");
 
99
        return false;
 
100
    }
 
101
 
 
102
    return true;
 
103
}
 
104
 
 
105
bool JarFile::open()
 
106
{
 
107
    if ((fd = ::open(_filename, O_RDONLY)) < 0) {
 
108
        fprintf(stderr, "open failed.\n");
 
109
        return false;
 
110
    }
 
111
    if (!init_inflation())
 
112
        return false;
 
113
 
 
114
    return true;
 
115
}
 
116
 
 
117
bool JarFile::close()
 
118
{
 
119
    if (fd >= 0 && !::close(fd)) {
 
120
        inflateEnd(&_zs);
 
121
        return true;
 
122
    }
 
123
    return false;
 
124
}
 
125
 
 
126
bool JarFile::read_signature()
 
127
{
 
128
    guint8 *bytes = (guint8 *)g_malloc(sizeof(guint8) * 4);
 
129
    if (!read(bytes, 4)) {
 
130
        g_free(bytes);
 
131
        return false;
 
132
    }
 
133
 
 
134
    guint32 signature = UNPACK_UB4(bytes, 0);
 
135
    g_free(bytes);
 
136
 
 
137
#ifdef DEBUG
 
138
    std::printf("signature is %x\n", signature);
 
139
#endif
 
140
 
 
141
    if (signature == 0x08074b50) {
 
142
        //skip data descriptor
 
143
        bytes = (guint8 *)malloc(sizeof(guint8) * 12);
 
144
        if (!read(bytes, 12)) {
 
145
            g_free(bytes);
 
146
            return false;
 
147
        }
 
148
    } else if (signature == 0x02014b50 || signature == 0x04034b50) {
 
149
        return true;
 
150
    } else {
 
151
        return false;
 
152
    }
 
153
    return false;
 
154
}
 
155
 
 
156
guint32 JarFile::get_crc(guint8 *bytes, guint16 flags)
 
157
{
 
158
    guint32 crc = 0;
 
159
    //no data descriptor
 
160
    if (!(flags & 0x0008)) {
 
161
        crc = UNPACK_UB4(bytes, LOC_CRC);
 
162
        
 
163
#ifdef DEBUG
 
164
        std::printf("CRC from file is %x\n", crc);
 
165
#endif
 
166
    }
 
167
    
 
168
    return crc;
 
169
}
 
170
 
 
171
guint8 *JarFile::read_filename(guint16 filename_length)
 
172
{
 
173
    guint8 *filename = (guint8 *)g_malloc(sizeof(guint8)
 
174
                                          * (filename_length+1));
 
175
    if (!read(filename, filename_length)) {
 
176
        g_free(filename);
 
177
        return NULL;
 
178
    }
 
179
    filename[filename_length] = '\0';
 
180
 
 
181
#ifdef DEBUG
 
182
    std::printf("Filename is %s\n", filename);
 
183
#endif
 
184
 
 
185
    return filename;
 
186
}
 
187
 
 
188
bool JarFile::check_compression_method(guint16 method, guint16 flags)
 
189
{
 
190
    return !(method != 8 && flags & 0x0008);
 
191
}
 
192
 
 
193
GByteArray *JarFile::get_next_file_contents()
 
194
{
 
195
    guint8 *bytes;
 
196
    GByteArray *gba = g_byte_array_new();
 
197
 
 
198
    read_signature();
 
199
    
 
200
    //get compressed size
 
201
    bytes = (guint8 *)g_malloc(sizeof(guint8) * 30);
 
202
    if (!read(bytes+4, 26)) {
 
203
        g_free(bytes);
 
204
        return NULL;
 
205
    }
 
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);
 
211
 
 
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;
 
217
        return NULL;
 
218
    }
 
219
 
 
220
 
 
221
#ifdef DEBUG    
 
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);
 
227
#endif
 
228
    
 
229
    guint32 crc = get_crc(bytes, flags);
 
230
    
 
231
    gchar *filename = (gchar *)read_filename(filename_length);
 
232
    g_free(bytes);
 
233
    
 
234
    if (filename == NULL) 
 
235
        return NULL;
 
236
   
 
237
    if (_last_filename != NULL)
 
238
        g_free(_last_filename);
 
239
    _last_filename = filename;
 
240
 
 
241
    //check if this is a directory and skip
 
242
    
 
243
    char *c_ptr;
 
244
    if ((c_ptr = std::strrchr(filename, '/')) != NULL) {
 
245
        if (*(++c_ptr) == '\0') {
 
246
            return NULL;
 
247
        }
 
248
    }
 
249
   
 
250
    if (!check_compression_method(method, flags)) {
 
251
        std::fprintf(stderr, "error in jar file\n");
 
252
        return NULL;
 
253
    }    
 
254
    
 
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, 
 
259
                                                crc, flags);
 
260
        if (file_data == NULL) {
 
261
            g_byte_array_free(gba, FALSE);
 
262
            return NULL;
 
263
        }
 
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, 
 
267
                                                  eflen, flags); 
 
268
 
 
269
        if (file_data == NULL) {
 
270
            g_byte_array_free(gba, TRUE);
 
271
            return NULL;
 
272
        }
 
273
        g_byte_array_append(gba, file_data, compressed_size);
 
274
    } else {
 
275
        lseek(fd, compressed_size+eflen, SEEK_CUR);
 
276
        g_byte_array_free(gba, FALSE);
 
277
        return NULL;
 
278
    }
 
279
        
 
280
    
 
281
    return gba;
 
282
}
 
283
 
 
284
guint8 *JarFile::get_uncompressed_file(guint32 compressed_size, guint32 crc, 
 
285
                                       guint16 eflen, guint16 flags)
 
286
{
 
287
    GByteArray *gba = g_byte_array_new();
 
288
    unsigned int out_a = 0;
 
289
    unsigned int in_a = compressed_size;
 
290
    guint8 *bytes;
 
291
    guint32 crc2 = 0;
 
292
    
 
293
    crc2 = crc32(crc2, NULL, 0);
 
294
    
 
295
    bytes = (guint8 *)g_malloc(sizeof(guint8) * RDSZ);
 
296
    while(out_a < compressed_size){
 
297
        unsigned int nbytes = (in_a > RDSZ ? RDSZ : in_a);
 
298
        
 
299
        if (!(nbytes = read(bytes, nbytes))) {
 
300
            g_free(bytes);
 
301
            return NULL;
 
302
        }
 
303
        
 
304
        crc2 = crc32(crc2, (Bytef*)bytes, nbytes);
 
305
            
 
306
        g_byte_array_append (gba, bytes, nbytes);
 
307
        out_a += nbytes;
 
308
        in_a -= nbytes;
 
309
            
 
310
#ifdef DEBUG    
 
311
        std::printf("%d bytes written\n", out_a);
 
312
#endif
 
313
    }
 
314
    lseek(fd, eflen, SEEK_CUR);
 
315
    g_free(bytes);
 
316
 
 
317
    if (!check_crc(crc, crc2, flags)) {
 
318
        bytes = gba->data;
 
319
        g_byte_array_free(gba, FALSE);//FALSE argument does not free actual data
 
320
        return NULL;
 
321
    }
 
322
    
 
323
    return bytes;
 
324
}
 
325
 
 
326
int JarFile::read(guint8 *buf, int count)
 
327
{
 
328
    int nbytes;
 
329
    if ((nbytes = ::read(fd, buf, count)) != count) {
 
330
        fprintf(stderr, "read error\n");
 
331
        exit(1);
 
332
        return 0;
 
333
    }
 
334
    return nbytes;
 
335
}
 
336
 
 
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)
 
341
{
 
342
    if (compressed_size == 0)
 
343
        return NULL;
 
344
    
 
345
    guint8 in_buffer[RDSZ];
 
346
    guint8 out_buffer[RDSZ];
 
347
    int nbytes;
 
348
    unsigned int leftover_in = compressed_size;
 
349
    GByteArray *gba = g_byte_array_new();
 
350
    
 
351
    _zs.avail_in = 0;
 
352
    guint32 crc = crc32(0, Z_NULL, 0);
 
353
    
 
354
    do {
 
355
                
 
356
        if (!_zs.avail_in) {
 
357
        
 
358
            if ((nbytes = ::read(fd, in_buffer, 
 
359
                                 (leftover_in < RDSZ ? leftover_in : RDSZ))) 
 
360
                < 0) {
 
361
                fprintf(stderr, "jarfile read error");
 
362
            }
 
363
            _zs.avail_in = nbytes;
 
364
            _zs.next_in = in_buffer;
 
365
            crc = crc32(crc, in_buffer, _zs.avail_in);
 
366
            leftover_in -= RDSZ;
 
367
        }
 
368
        _zs.next_out = out_buffer;
 
369
        _zs.avail_out = RDSZ;
 
370
        
 
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) 
 
375
                                                   * tmp_len);
 
376
            memcpy(tmp_bytes, out_buffer, tmp_len);
 
377
            g_byte_array_append(gba, tmp_bytes, tmp_len);
 
378
        }
 
379
        
 
380
        if (ret == Z_STREAM_END) {
 
381
            break;
 
382
        }
 
383
        if (ret != Z_OK)
 
384
            std::printf("decompression error %d\n", ret);
 
385
    } while (_zs.total_in < compressed_size);
 
386
    
 
387
    file_length = _zs.total_out;
 
388
#ifdef DEBUG
 
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);
 
392
#endif
 
393
    
 
394
    guint8 *ret_bytes;
 
395
    if (check_crc(oldcrc, crc, flags) && gba->len > 0)
 
396
        ret_bytes = gba->data;
 
397
    else 
 
398
        ret_bytes = NULL;
 
399
    g_byte_array_free(gba, FALSE);
 
400
 
 
401
    inflateReset(&_zs); 
 
402
    return ret_bytes;
 
403
}
 
404
 
 
405
bool JarFile::check_crc(guint32 oldcrc, guint32 crc, guint16 flags)
 
406
{
 
407
    //fixme: does not work yet
 
408
        
 
409
    if(flags & 0x0008) {
 
410
        guint8 *bytes = (guint8 *)g_malloc(sizeof(guint8) * 16);
 
411
        if (!read(bytes, 16)) {
 
412
            g_free(bytes);
 
413
            return false;
 
414
        }
 
415
        
 
416
        guint32 signature = UNPACK_UB4(bytes, 0);
 
417
        g_free(bytes);
 
418
        if(signature != 0x08074b50) {
 
419
            fprintf(stderr, "missing data descriptor!\n");
 
420
        }
 
421
        
 
422
        crc = UNPACK_UB4(bytes, 4);
 
423
        
 
424
    }
 
425
    if (oldcrc != crc) {
 
426
#ifdef DEBUG
 
427
        std::fprintf(stderr, "Error! CRCs do not match! Got %x, expected %x\n",
 
428
                     oldcrc, crc);
 
429
#endif
 
430
    }
 
431
    return true;
 
432
}
 
433
 
 
434
JarFile::JarFile(JarFile const& rhs)
 
435
{
 
436
    *this = rhs;
 
437
}
 
438
 
 
439
JarFile& JarFile::operator=(JarFile const& rhs)
 
440
{
 
441
    if (this == &rhs)
 
442
        return *this;
 
443
 
 
444
    _zs = rhs._zs;//fixme
 
445
    if (_filename == NULL)
 
446
        _filename = NULL;
 
447
    else
 
448
        _filename = strdup(rhs._filename);
 
449
    if (_last_filename == NULL)
 
450
        _last_filename = NULL;
 
451
    else 
 
452
        _last_filename = strdup(rhs._last_filename);
 
453
    fd = rhs.fd;
 
454
    
 
455
    return *this;
 
456
}
 
457
 
 
458
 
 
459
/////////////////////////
 
460
//      JarFileReader  //
 
461
/////////////////////////
 
462
 
 
463
GByteArray *JarFileReader::get_next_file()
 
464
{
 
465
    if (_state == CLOSED) {
 
466
        _jarfile.open();
 
467
        _state = OPEN;
 
468
    }
 
469
    
 
470
    return _jarfile.get_next_file_contents();
 
471
}
 
472
 
 
473
JarFileReader& JarFileReader::operator=(JarFileReader const& rhs)
 
474
{
 
475
    if (&rhs == this)
 
476
        return *this;
 
477
 
 
478
    _jarfile = rhs._jarfile;
 
479
    _state = rhs._state;
 
480
    
 
481
    return *this;
 
482
}
 
483
 
 
484
/*
 
485
 * If the filename gets reset, a jarfile object gets generated again,
 
486
 * ready to be opened for reading.
 
487
 */
 
488
void JarFileReader::set_filename(gchar const *new_filename)
 
489
{
 
490
    _jarfile.close();
 
491
    _jarfile = JarFile(new_filename);
 
492
}
 
493
 
 
494
void JarFileReader::set_jarfile(JarFile const& new_jarfile)
 
495
{
 
496
    _jarfile = new_jarfile;
 
497
}
 
498
 
 
499
JarFileReader::JarFileReader(JarFileReader const& rhs)
 
500
{
 
501
    *this = rhs;
 
502
}
 
503
 
 
504
} // namespace Inkjar
 
505
 
 
506
 
 
507
#if 0 //testing code
 
508
#include "jar.h"
 
509
/*
 
510
 * This program writes all the files from a jarfile to stdout and inflates
 
511
 * where needed.
 
512
 */
 
513
int main(int argc, char *argv[])
 
514
{
 
515
    gchar *filename;
 
516
    if (argc < 2) {
 
517
        filename = "./ide.jar\0";
 
518
    } else {
 
519
        filename = argv[1];
 
520
    }
 
521
 
 
522
    Inkjar::JarFileReader jar_file_reader(filename);
 
523
    
 
524
    for (;;) {
 
525
        GByteArray *gba = jar_file_reader.get_next_file();
 
526
        if (gba == NULL) {
 
527
            char *c_ptr;
 
528
            gchar *last_filename = jar_file_reader.get_last_filename();
 
529
            if (last_filename == NULL)
 
530
                break;
 
531
            if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
 
532
                if (*(++c_ptr) == '\0') {
 
533
                    g_free(last_filename);
 
534
                    continue;
 
535
                }
 
536
            }
 
537
        } else if (gba->len > 0)
 
538
            ::write(1, gba->data, gba->len);
 
539
        else
 
540
            break;
 
541
    }
 
542
    return 0;
 
543
}
 
544
#endif