diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/inkjar | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/inkjar')
| -rw-r--r-- | src/inkjar/.cvsignore | 5 | ||||
| -rw-r--r-- | src/inkjar/Makefile_insert | 10 | ||||
| -rw-r--r-- | src/inkjar/jar.cpp | 541 | ||||
| -rw-r--r-- | src/inkjar/jar.h | 151 | ||||
| -rw-r--r-- | src/inkjar/makefile.in | 17 |
5 files changed, 724 insertions, 0 deletions
diff --git a/src/inkjar/.cvsignore b/src/inkjar/.cvsignore new file mode 100644 index 000000000..e8014d011 --- /dev/null +++ b/src/inkjar/.cvsignore @@ -0,0 +1,5 @@ +Makefile +Makefile.in +.deps +makefile +.dirstamp diff --git a/src/inkjar/Makefile_insert b/src/inkjar/Makefile_insert new file mode 100644 index 000000000..0376015fa --- /dev/null +++ b/src/inkjar/Makefile_insert @@ -0,0 +1,10 @@ +## Makefile.am fragment sourced by src/Makefile.am. + +inkjar/all: inkjar/libinkjar.a + +inkjar/clean: + rm -f inkjar/libinkjar.a $(inkjar_libinkjar_OBJECTS) + +inkjar_libinkjar_a_SOURCES = \ + inkjar/jar.cpp \ + inkjar/jar.h diff --git a/src/inkjar/jar.cpp b/src/inkjar/jar.cpp new file mode 100644 index 000000000..655f11cbb --- /dev/null +++ b/src/inkjar/jar.cpp @@ -0,0 +1,541 @@ +/* + * Copyright (C) 1999, 2000 Bryan Burns + * Copyright (C) 2004 Johan Ceuppens + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +/* + * TODO/FIXME: + * - configure #ifdefs should be enabled + * - move to cstdlib instead of stdlib.h etc. + * - remove exit functions + * - move to clean C++ code + * - windowsify + * - remove a few g_free/g_mallocs + * - unseekable files + * - move to LGPL by rewriting macros + * - crcs for compressed files + * - put in eof + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +//#ifdef STDC_HEADERS +//#endif + +//#ifdef HAVE_UNISTD_H +//#endif + +//#ifdef HAVE_SYS_PARAM_H +//#else +//#define MAXPATHLEN 1024 +//#endif + +//#ifdef HAVE_DIRENT_H +//#endif + +//#ifdef HAVE_FCNTL_H +#include <fcntl.h> +//#endif + + +#include <glib.h> + +#include "jar.h" + +#include <fstream> +#ifdef WORDS_BIGENDIAN + +#define L2BI(l) ((l & 0xff000000) >> 24) | \ +((l & 0x00ff0000) >> 8) | \ +((l & 0x0000ff00) << 8) | \ +((l & 0x000000ff) << 24); + +#define L2BS(l) ((l & 0xff00) >> 8) | ((l & 0x00ff) << 8); + +#endif + +namespace Inkjar { + +JarFile::JarFile(gchar const*new_filename) +{ + _filename = strdup(new_filename); + _last_filename = NULL; + fd = -1; +} + +//fixme: the following should probably just return a const gchar* and not +// use strdup +gchar *JarFile::get_last_filename() const +{ + return (_last_filename != NULL ? strdup(_last_filename) : NULL); +} + +JarFile::~JarFile() +{ + if (_filename != NULL) + g_free(_filename); + if (_last_filename != NULL) + g_free(_last_filename); +} + +bool JarFile::init_inflation() +{ + memset(&_zs, 0, sizeof(z_stream)); + + _zs.zalloc = Z_NULL; + _zs.zfree = Z_NULL; + _zs.opaque = Z_NULL; + + if(inflateInit2(&_zs, -15) != Z_OK) { + fprintf(stderr,"error initializing inflation!\n"); + return false; + } + + return true; +} + +bool JarFile::open() +{ + if ((fd = ::open(_filename, O_RDONLY)) < 0) { + fprintf(stderr, "open failed.\n"); + return false; + } + if (!init_inflation()) + return false; + + return true; +} + +bool JarFile::close() +{ + if (fd >= 0 && !::close(fd)) { + inflateEnd(&_zs); + return true; + } + return false; +} + +bool JarFile::read_signature() +{ + guint8 *bytes = (guint8 *)g_malloc(sizeof(guint8) * 4); + if (!read(bytes, 4)) { + g_free(bytes); + return false; + } + + guint32 signature = UNPACK_UB4(bytes, 0); + g_free(bytes); + +#ifdef DEBUG + std::printf("signature is %x\n", signature); +#endif + + if (signature == 0x08074b50) { + //skip data descriptor + bytes = (guint8 *)malloc(sizeof(guint8) * 12); + if (!read(bytes, 12)) { + g_free(bytes); + return false; + } + } else if (signature == 0x02014b50 || signature == 0x04034b50) { + return true; + } else { + return false; + } + return false; +} + +guint32 JarFile::get_crc(guint8 *bytes, guint16 flags) +{ + guint32 crc = 0; + //no data descriptor + if (!(flags & 0x0008)) { + crc = UNPACK_UB4(bytes, LOC_CRC); + +#ifdef DEBUG + std::printf("CRC from file is %x\n", crc); +#endif + } + + return crc; +} + +guint8 *JarFile::read_filename(guint16 filename_length) +{ + guint8 *filename = (guint8 *)g_malloc(sizeof(guint8) + * (filename_length+1)); + if (!read(filename, filename_length)) { + g_free(filename); + return NULL; + } + filename[filename_length] = '\0'; + +#ifdef DEBUG + std::printf("Filename is %s\n", filename); +#endif + + return filename; +} + +bool JarFile::check_compression_method(guint16 method, guint16 flags) +{ + return !(method != 8 && flags & 0x0008); +} + +GByteArray *JarFile::get_next_file_contents() +{ + guint8 *bytes; + GByteArray *gba = g_byte_array_new(); + + read_signature(); + + //get compressed size + bytes = (guint8 *)g_malloc(sizeof(guint8) * 30); + if (!read(bytes+4, 26)) { + g_free(bytes); + return NULL; + } + guint32 compressed_size = UNPACK_UB4(bytes, LOC_CSIZE); + guint16 filename_length = UNPACK_UB2(bytes, LOC_FNLEN); + guint16 eflen = UNPACK_UB2(bytes, LOC_EFLEN); + guint16 flags = UNPACK_UB2(bytes, LOC_EXTRA); + guint16 method = UNPACK_UB2(bytes, LOC_COMP); + + if (filename_length == 0) { + g_byte_array_free(gba, TRUE); + if (_last_filename != NULL) + g_free(_last_filename); + _last_filename = NULL; + return NULL; + } + + +#ifdef DEBUG + 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 = get_crc(bytes, flags); + + gchar *filename = (gchar *)read_filename(filename_length); + g_free(bytes); + + if (filename == NULL) + return NULL; + + if (_last_filename != NULL) + g_free(_last_filename); + _last_filename = filename; + + //check if this is a directory and skip + + char *c_ptr; + if ((c_ptr = std::strrchr(filename, '/')) != NULL) { + if (*(++c_ptr) == '\0') { + return NULL; + } + } + + if (!check_compression_method(method, flags)) { + std::fprintf(stderr, "error in jar file\n"); + return NULL; + } + + if (method == 8 || flags & 0x0008) { + unsigned int file_length = 0;//uncompressed file length + lseek(fd, eflen, SEEK_CUR); + guint8 *file_data = get_compressed_file(compressed_size, file_length, + crc, flags); + if (file_data == NULL) { + g_byte_array_free(gba, FALSE); + return NULL; + } + g_byte_array_append(gba, file_data, file_length); + } else if (method == 0) { + guint8 *file_data = get_uncompressed_file(compressed_size, crc, + eflen, flags); + + if (file_data == NULL) { + g_byte_array_free(gba, TRUE); + return NULL; + } + g_byte_array_append(gba, file_data, compressed_size); + } else { + lseek(fd, compressed_size+eflen, SEEK_CUR); + g_byte_array_free(gba, FALSE); + return NULL; + } + + + return gba; +} + +guint8 *JarFile::get_uncompressed_file(guint32 compressed_size, guint32 crc, + guint16 eflen, guint16 flags) +{ + GByteArray *gba = g_byte_array_new(); + unsigned int out_a = 0; + unsigned int in_a = compressed_size; + guint8 *bytes; + guint32 crc2 = 0; + + crc2 = crc32(crc2, NULL, 0); + + bytes = (guint8 *)g_malloc(sizeof(guint8) * RDSZ); + while(out_a < compressed_size){ + unsigned int nbytes = (in_a > RDSZ ? RDSZ : in_a); + + if (!(nbytes = read(bytes, nbytes))) { + g_free(bytes); + return NULL; + } + + crc2 = crc32(crc2, (Bytef*)bytes, nbytes); + + g_byte_array_append (gba, bytes, nbytes); + out_a += nbytes; + in_a -= nbytes; + +#ifdef DEBUG + std::printf("%d bytes written\n", out_a); +#endif + } + lseek(fd, eflen, SEEK_CUR); + g_free(bytes); + + if (!check_crc(crc, crc2, flags)) { + bytes = gba->data; + g_byte_array_free(gba, FALSE);//FALSE argument does not free actual data + return NULL; + } + + return bytes; +} + +int JarFile::read(guint8 *buf, int count) +{ + int nbytes; + if ((nbytes = ::read(fd, buf, count)) != count) { + fprintf(stderr, "read error\n"); + exit(1); + return 0; + } + return nbytes; +} + +/* FIXME: this could probably use ZlibBuffer */ +guint8 *JarFile::get_compressed_file(guint32 compressed_size, + unsigned int& file_length, + guint32 oldcrc, guint16 flags) +{ + if (compressed_size == 0) + return NULL; + + guint8 in_buffer[RDSZ]; + guint8 out_buffer[RDSZ]; + int nbytes; + unsigned int leftover_in = compressed_size; + GByteArray *gba = g_byte_array_new(); + + _zs.avail_in = 0; + guint32 crc = crc32(0, Z_NULL, 0); + + do { + + if (!_zs.avail_in) { + + if ((nbytes = ::read(fd, in_buffer, + (leftover_in < RDSZ ? leftover_in : RDSZ))) + < 0) { + fprintf(stderr, "jarfile read error"); + } + _zs.avail_in = nbytes; + _zs.next_in = in_buffer; + crc = crc32(crc, in_buffer, _zs.avail_in); + leftover_in -= RDSZ; + } + _zs.next_out = out_buffer; + _zs.avail_out = RDSZ; + + int ret = inflate(&_zs, Z_NO_FLUSH); + if (RDSZ != _zs.avail_out) { + unsigned int tmp_len = RDSZ - _zs.avail_out; + guint8 *tmp_bytes = (guint8 *)g_malloc(sizeof(guint8) + * tmp_len); + memcpy(tmp_bytes, out_buffer, tmp_len); + g_byte_array_append(gba, tmp_bytes, tmp_len); + } + + if (ret == Z_STREAM_END) { + break; + } + if (ret != Z_OK) + std::printf("decompression error %d\n", ret); + } while (_zs.total_in < compressed_size); + + file_length = _zs.total_out; +#ifdef DEBUG + std::printf("done inflating\n"); + std::printf("%d bytes left over\n", _zs.avail_in); + std::printf("CRC is %x\n", crc); +#endif + + guint8 *ret_bytes; + if (check_crc(oldcrc, crc, flags) && gba->len > 0) + ret_bytes = gba->data; + else + ret_bytes = NULL; + g_byte_array_free(gba, FALSE); + + inflateReset(&_zs); + return ret_bytes; +} + +bool JarFile::check_crc(guint32 oldcrc, guint32 crc, guint16 flags) +{ + //fixme: does not work yet + + if(flags & 0x0008) { + guint8 *bytes = (guint8 *)g_malloc(sizeof(guint8) * 16); + if (!read(bytes, 16)) { + g_free(bytes); + return false; + } + + guint32 signature = UNPACK_UB4(bytes, 0); + g_free(bytes); + if(signature != 0x08074b50) { + fprintf(stderr, "missing data descriptor!\n"); + } + + crc = UNPACK_UB4(bytes, 4); + + } + if (oldcrc != crc) { +#ifdef DEBUG + std::fprintf(stderr, "Error! CRCs do not match! Got %x, expected %x\n", + oldcrc, crc); +#endif + } + return true; +} + +JarFile::JarFile(JarFile const& rhs) +{ + *this = rhs; +} + +JarFile& JarFile::operator=(JarFile const& rhs) +{ + if (this == &rhs) + return *this; + + _zs = rhs._zs;//fixme + if (_filename == NULL) + _filename = NULL; + else + _filename = strdup(rhs._filename); + if (_last_filename == NULL) + _last_filename = NULL; + else + _last_filename = strdup(rhs._last_filename); + fd = rhs.fd; + + return *this; +} + + +///////////////////////// +// JarFileReader // +///////////////////////// + +GByteArray *JarFileReader::get_next_file() +{ + if (_state == CLOSED) { + _jarfile.open(); + _state = OPEN; + } + + return _jarfile.get_next_file_contents(); +} + +JarFileReader& JarFileReader::operator=(JarFileReader const& rhs) +{ + if (&rhs == this) + return *this; + + _jarfile = rhs._jarfile; + _state = rhs._state; + + return *this; +} + +/* + * If the filename gets reset, a jarfile object gets generated again, + * ready to be opened for reading. + */ +void JarFileReader::set_filename(gchar const *new_filename) +{ + _jarfile.close(); + _jarfile = JarFile(new_filename); +} + +void JarFileReader::set_jarfile(JarFile const& new_jarfile) +{ + _jarfile = new_jarfile; +} + +JarFileReader::JarFileReader(JarFileReader const& rhs) +{ + *this = rhs; +} + +} // namespace Inkjar + + +#if 0 //testing code +#include "jar.h" +/* + * This program writes all the files from a jarfile to stdout and inflates + * where needed. + */ +int main(int argc, char *argv[]) +{ + gchar *filename; + if (argc < 2) { + filename = "./ide.jar\0"; + } else { + filename = argv[1]; + } + + Inkjar::JarFileReader jar_file_reader(filename); + + for (;;) { + GByteArray *gba = jar_file_reader.get_next_file(); + if (gba == NULL) { + char *c_ptr; + gchar *last_filename = jar_file_reader.get_last_filename(); + if (last_filename == NULL) + break; + if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) { + if (*(++c_ptr) == '\0') { + g_free(last_filename); + continue; + } + } + } else if (gba->len > 0) + ::write(1, gba->data, gba->len); + else + break; + } + return 0; +} +#endif diff --git a/src/inkjar/jar.h b/src/inkjar/jar.h new file mode 100644 index 000000000..2340a74c7 --- /dev/null +++ b/src/inkjar/jar.h @@ -0,0 +1,151 @@ +#ifndef __INKJAR_JAR_H_ +#define __INKJAR_JAR_H_ +/* + * Copyright (C) 1999 Bryan Burns + * Copyright (C) 2004 Johan Ceuppens + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <glib/garray.h> +#include <glib/gtypes.h> +#include <zlib.h> +#include <inttypes.h> + +namespace Inkjar { + +unsigned const RDSZ = 4096; + +//#define DEBUG 1 //uncommment for debug messages + +enum JarFileReaderState {CLOSED, OPEN}; + +//fixme: The following will be removed +typedef uint8_t ub1; +typedef uint16_t ub2; +typedef uint32_t ub4; + +#define LOC_EXTRA 6 /* extra bytes */ +#define LOC_COMP 8 /* compression method */ +#define LOC_MODTIME 10 /* last modification time */ +#define LOC_MODDATE 12 /* last modification date */ +#define LOC_CRC 14 /* CRC */ +#define LOC_CSIZE 18 /* compressed size */ +#define LOC_USIZE 22 /* uncompressed size */ +#define LOC_FNLEN 26 /* filename length */ +#define LOC_EFLEN 28 /* extra-field length */ + +#define CEN_COMP 10 /* compression method */ +#define CEN_MODTIME 12 +#define CEN_MODDATE 14 +#define CEN_CRC 16 +#define CEN_CSIZE 20 +#define CEN_USIZE 24 +#define CEN_FNLEN 28 +#define CEN_EFLEN 30 +#define CEN_COMLEN 32 +#define CEN_OFFSET 42 + + +/* macros */ +#define PACK_UB4(d, o, v) d[o] = (ub1)((v) & 0x000000ff); \ + d[o + 1] = (ub1)(((v) & 0x0000ff00) >> 8); \ + d[o + 2] = (ub1)(((v) & 0x00ff0000) >> 16); \ + d[o + 3] = (ub1)(((v) & 0xff000000) >> 24) + +#define PACK_UB2(d, o, v) d[o] = (ub1)((v) & 0x00ff); \ + d[o + 1] = (ub1)(((v) & 0xff00) >> 8) + +#define UNPACK_UB4(s, o) (ub4)s[o] + (((ub4)s[o + 1]) << 8) +\ + (((ub4)s[o + 2]) << 16) + (((ub4)s[o + 3]) << 24) + +#define UNPACK_UB2(s, o) (ub2)s[o] + (((ub2)s[o + 1]) << 8) + + + +/* + * JarFile: + * + * This is a wrapper class for canonical jarfile functions like reading, + * writing, seeking etc. JarFile is a dumb class with no state information. + * + * All memory allocations are done with g_malloc. + */ + +class JarFile { +public: + + JarFile() : fd(-1), _filename(NULL), _last_filename(NULL) {} + virtual ~JarFile(); + JarFile(gchar const *new_filename); + + GByteArray *get_next_file_contents(); + gchar *get_last_filename() const; + bool open(); + bool close(); + int read(guint8 *buf, int count); + + JarFile(JarFile const &rhs); + JarFile &operator=(JarFile const &rhs); + +private: + + int fd; + gchar *_filename; + z_stream _zs; + gchar *_last_filename; + + bool init_inflation(); + bool read_signature(); + guint32 get_crc(guint8 *bytes, guint16 flags); + guint8 *read_filename(guint16 filename_length); + bool check_compression_method(guint16 method, guint16 flags); + bool check_crc(guint32 oldcrc, guint32 crc, guint16 flags); + guint8 *get_compressed_file(guint32 compressed_size, + unsigned int &file_length, + guint32 oldcrc, guint16 flags); + guint8 *get_uncompressed_file(guint32 compressed_szie, guint32 crc, + guint16 eflen, guint16 flags); +}; // class JarFile + + +/* + * JarFileReader: + * + * This provides some smarter functions for operating on a jarfile object + * It should be able to grep for files or return the contents of a specific + * file. + */ + +class JarFileReader { +public: + + JarFileReader(gchar const *new_filename) + : _state(CLOSED), _jarfile(new_filename) {} + JarFileReader() : _state(CLOSED) {} + virtual ~JarFileReader() { if (_state == OPEN) _jarfile.close(); } + //fixme return types are incorrect + GByteArray *get_next_file();//fixme clean up return type + void set_filename(gchar const *new_filename); + void set_jarfile(JarFile const &new_jarfile); + gchar *get_last_filename() const { return _jarfile.get_last_filename(); }; + JarFileReader(JarFileReader const &rhs); + JarFileReader &operator=(JarFileReader const &rhs); +private: + JarFileReaderState _state; + JarFile _jarfile; + +}; // class JarFileReader + +} // namespace Inkjar +#endif // header guard + +/* + 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 : diff --git a/src/inkjar/makefile.in b/src/inkjar/makefile.in new file mode 100644 index 000000000..0ccb68b59 --- /dev/null +++ b/src/inkjar/makefile.in @@ -0,0 +1,17 @@ +# Convenience stub makefile to call the real Makefile. + +@SET_MAKE@ + +# Explicit so that it's the default rule. +all: + cd .. && $(MAKE) inkjar/all + +clean %.a %.o: + cd .. && $(MAKE) inkjar/$@ + +.PHONY: all clean + +OBJEXT = @OBJEXT@ + +.SUFFIXES: +.SUFFIXES: .a .$(OBJEXT) |
