summaryrefslogtreecommitdiffstats
path: root/src/streams-jar.cpp
blob: ffaccc2e4a1726bad93186634fe8bdfa3d522f44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "streams-jar.h"

namespace Inkscape {

const int LOC_EXTRA = 6;  // extra bytes
const int LOC_COMP  = 8;  // compression method
const int LOC_CSIZE = 18; // compressed size
const int LOC_FNLEN = 26; // filename length
const int LOC_EFLEN = 28; // extra-field length

void JarBuffer::consume_header() throw(JarHeaderException)
{
    try {
	guint8 data[30];
	_urihandle->read(data, 4);
    	check_signature(data);
	_urihandle->read(data+4, 26);
	compressed_size = compressed_left = unpack_4bytes(data, LOC_CSIZE);
	guint16 filename_length = unpack_2bytes(data, LOC_FNLEN);
	eflen = unpack_2bytes(data, LOC_EFLEN);
	flags = unpack_2bytes(data, LOC_EXTRA);
	method = unpack_2bytes(data, LOC_COMP);
	
#ifdef DEBUG_STREAMS    
	std::printf("Compressed size is %u\n", compressed_size);
	std::printf("Filename length is %hu\n", filename_length);
	std::printf("Extra field length is %hu\n", eflen);
	std::printf("Flags are %#hx\n", flags);
	std::printf("Compression method is %#hx\n", method);
#endif
    
	//guint32 crc = check_crc(data, flags);
	gchar filename[filename_length+1];
	_urihandle->read(filename, filename_length);
	filename[filename_length] = '\0';

#ifdef DEBUG_STREAMS
	std::printf("Filename is %s\n", filename);
#endif
    }
    catch (std::exception& e) {
	throw JarHeaderException();
    }
}

void JarBuffer::check_signature(guint8 *data) throw(JarHeaderException)
{
    guint32 signature = unpack_4bytes(data, 0);

#ifdef DEBUG_STREAMS
    std::printf("signature is %x\n", signature);
#endif

    if (signature == 0x08074b50) {
	_urihandle->read(data, 12);
    } else if (signature != 0x02014b50 && signature != 0x04034b50) {
	throw JarHeaderException();
    }
}

void JarBuffer::reset()//resets zlib and buffer (also skips archived directories)
{
    bool do_reset = false;
    while (compressed_left == 0) {
	consume_header();
	do_reset = true;
    }

    if (do_reset) {
	reset_inflation();
	setg(eback(), eback(), eback());
    }
}

int JarBuffer::consume_and_inflate()
{
    int nbytes;
    
    reset();

    nbytes = compressed_left > BUFSIZE_STREAM ? BUFSIZE_STREAM 
	    : compressed_left;
    
    if (is_compressed())
	return consume_compressed(nbytes);
    else
	return consume_uncompressed(nbytes);
}

int JarBuffer::consume_compressed(int nbytes)
{
    int ret;

    if ((ret = do_consume_and_inflate(nbytes)) == EOF && eflen > 0) {
	guint8 efbuf[eflen];
	_urihandle->read(efbuf, eflen);
	return 1;
    } 

    return ret;
}

int JarBuffer::consume_uncompressed(int nbytes)
{
    guint8 data[nbytes];
    if (consume(data, nbytes) == EOF)
	return EOF;
    
    copy_to_get(data, nbytes);
    compressed_left -= nbytes;

    return nbytes;
}

GByteArray *JarBuffer::inflate(guint8 *data, const int nbytes)
{
    GByteArray *gba = do_inflate(data, nbytes);
    compressed_left -= nbytes;
    return gba;
}

guint32 JarBuffer::unpack_4bytes(guint8 *data, const int offset) 
{
    return ((guint32)data[offset] 
	    + (((guint32)data[offset + 1]) << 8)
	    + (((guint32)data[offset + 2]) << 16) 
	    + (((guint32)data[offset + 3]) << 24));
}

guint16 JarBuffer::unpack_2bytes(guint8 *data, int offset)
{
    return ((guint16)data[offset] + (((guint16)data[offset + 1]) << 8));
}

} // namespace Inkscape

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :