summaryrefslogtreecommitdiffstats
path: root/src/streams-gzip.cpp
blob: c2cda1c2b7b5ebc814cea5c07cd70bf3470a6321 (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
147
148
149
/*
 * IO layer : gzip streambuf and streams
 *
 * Authors:
 *   Johan Ceuppens <jceuppen at easynet dot be>
 *
 * Copyright (C) 2004 Johan Ceuppens
 *
 * Released under GNU LGPL, read the file 'COPYING.LIB' for more information
 */

#include "streams-gzip.h"

namespace Inkscape {

//With some inpsiration and code from libgsf, fastjar, libpng and RFC 1952

static int const GZIP_IS_ASCII	     = 0x01; //file contains text
static int const GZIP_HEADER_CRC     = 0x02; //there is a CRC in the header
static int const GZIP_EXTRA_FIELD    = 0x04; //there is an 'extra' field
static int const GZIP_ORIGINAL_NAME  = 0x08; //the original is stored
static int const GZIP_HAS_COMMENT    = 0x10; //There is a comment in the header 
static unsigned int const GZIP_HEADER_FLAGS = (GZIP_IS_ASCII 
					       |GZIP_HEADER_CRC 
					       |GZIP_EXTRA_FIELD
					       |GZIP_ORIGINAL_NAME
					       |GZIP_HAS_COMMENT);

/**
 * GZipBuffer
 */

void GZipBuffer::consume_header() throw(GZipHeaderException)
{
    unsigned int flags;
    guint8 data[4];
    
    try {
	_urihandle->read(data, 4);
	check_signature(data);
	check_flags(data);
	flags = data[3];
	_urihandle->read(data, 4);
	//get_modification_time()
	_urihandle->read(data, 1);
	//check_extra_flags();
	_urihandle->read(data, 1);
	//check_OS();
	
	if (flags & GZIP_EXTRA_FIELD) {
	    get_extrafield();
	}
	if (flags & GZIP_ORIGINAL_NAME) {
	    get_filename();
	}
	if (flags & GZIP_HAS_COMMENT) {
	    get_comment();
	}
	if (flags & GZIP_HEADER_CRC) {
	    get_crc();
	}
    }
    catch(std::exception& e) {
	throw GZipHeaderException();
    }
}

void GZipBuffer::check_signature(guint8 *data) throw(GZipHeaderException)
{
    guint8 const signature[2] = {0x1f, 0x8b};
    if (memcmp(data, signature, sizeof(signature)) != 0)
	throw GZipHeaderException();
}

void GZipBuffer::check_flags(guint8 *data) throw(GZipHeaderException)
{
    unsigned int flags = data[3];
    if (data[2] != Z_DEFLATED || (flags & ~GZIP_HEADER_FLAGS) != 0)
	throw GZipHeaderException();
}

gchar *GZipBuffer::get_filename()
{
#ifdef DEBUG_STREAMS
    std::cout<<"Filename is ";
#endif
    return read_string();
}

gchar *GZipBuffer::get_comment()
{
#ifdef DEBUG_STREAMS
    std::cout<<"Comment is "<<std::endl;
#endif
    return read_string();
}

guint16 GZipBuffer::get_crc()
{
    guint16 buf;
    _urihandle->read(&buf, 2);
    return buf;
}

void GZipBuffer::get_extrafield()
{
    guint8 length_data[2];
    _urihandle->read(length_data, 2);
    unsigned int const length = length_data[0] | (length_data[1] << 8);
    guint8 *data = new guint8[length];
    _urihandle->read(data, length);
}

gchar *GZipBuffer::read_string() throw(GZipHeaderException)
{
    GByteArray *gba = g_byte_array_new();
    try {
	guint8 byte[1];
	do {
	    _urihandle->read(byte, 1);
	    g_byte_array_append(gba, byte, sizeof(byte));
#ifdef DEBUG_STREAMS
	    std::cout <<(char)*byte;
#endif
	} while (*byte != 0);
    } catch (std::exception& e) {
	g_byte_array_free(gba, TRUE);
	throw GZipHeaderException();
    }
#ifdef DEBUG_STREAMS
    std::cout<<std::endl;
#endif
    gchar *ret = (gchar *)gba->data;
    g_byte_array_free(gba, FALSE);
    return ret;
}

} // 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 :