Select Git revision
module.pmod.in
-
Marcus Comstedt authored
Rev: src/modules/Gz/configure.in:1.25 Rev: src/modules/Gz/module.pmod.in:1.9 Rev: src/modules/Gz/zlibmod.c:1.63
Marcus Comstedt authoredRev: src/modules/Gz/configure.in:1.25 Rev: src/modules/Gz/module.pmod.in:1.9 Rev: src/modules/Gz/zlibmod.c:1.63
module.pmod.in 8.02 KiB
// $Id: module.pmod.in,v 1.9 2003/04/14 17:10:57 marcus Exp $
#pike __REAL_VERSION__
inherit @module@;
//! Low-level implementation of read/write support for GZip files
class _file {
static private Stdio.Stream f;
static private inflate inf;
static private deflate def;
static private int level, strategy;
static private string read_buf;
static private int file_pos, crc, write_mode;
constant SEEK_SET = 0;
constant SEEK_CUR = 1;
constant SEEK_END = 2;
static int check_header()
{
int magic1, magic2, method, flags, len;
if(sscanf(f->read(4), "%1c%1c%1c%1c", magic1, magic2, method, flags)!=4 ||
magic1 != 0x1f || magic2 != 0x8b)
return 0;
if(method != 8 || (flags & 0xe0))
return 0;
if(sizeof(f->read(6)) != 6)
return 0;
if(flags & 4)
if(sscanf(f->read(2), "%-2c", len) != 1 ||
sizeof(f->read(len)) != len)
return 0;
if(flags & 8)
loop: for(;;)
switch(f->read(1)) {
case 0: case "": return 0;
case "\0": break loop;
}
if(flags & 16)
loop: for(;;)
switch(f->read(1)) {
case 0: case "": return 0;
case "\0": break loop;
}
if(flags & 2)
if(sizeof(f->read(2)) != 2)
return 0;
return 1;
}
static int make_header()
{
return f->write(sprintf("%1c%1c%1c%1c%4c%1c%1c",
0x1f, 0x8b, 8, 0, 0, 0, 3)) == 10;
}
//! Opens a file for I/O.
//!
//! @param file
//! The filename or an open filedescriptor or Stream for the GZip
//! file to use.
//! @param mode
//! Mode for the fileoperations. Defaults to read only.
//!
//! @note
//! If the object already has been opened, it will first be closed.
int open(string|int|Stdio.Stream file, void|string mode)
{
close();
write_mode = 0;
level = 6;
strategy = DEFAULT_STRATEGY;
if(mode) {
mode = filter(mode, lambda(int n) {
if(n == 'w' || n == 'a')
write_mode = 1;
if(n >= '0' && n <= '9')
level = n - '0';
else if(n == 'f')
strategy = FILTERED;
else if(n == 'h')
strategy = HUFFMAN_ONLY;
else
return 1;
});
if(write_mode) {
if(!has_value(mode, 'a'))
mode += "t";
mode += "c";
}
}
file_pos = 0;
if(objectp(file))
f = file;
else {
f = Stdio.File();
if(!f->open(file, mode||"rb"))
return 0;
}
return write_mode? make_header() : check_header();
}
//! Opens a gzip file for reading.
static void create(void|string|Stdio.Stream gzFile, void|string mode)
{
if(!zero_type(gzFile) && !open(gzFile, mode))
error("Failed to open file.\n");
}
//! closes the file
//! @returns
//! 1 if successful
int close()
{
if(def) {
string s = def->deflate("", FINISH);
if(sizeof(s) && f->write(s) != sizeof(s))
return 0;
if(f->write(sprintf("%-4c%-4c", crc, file_pos)) != 8)
return 0;
}
inf = 0;
def = 0;
read_buf = "";
Stdio.File oldf = f;
f = 0;
return !oldf || oldf->close();
}
//! Reads len (uncompressed) bytes from the file.
//! If read is unsuccessful, 0 is returned.
int|string read(int len)
{
if(!inf) inf = inflate(-15);
while(sizeof(read_buf) < len) {
string r = f->read(16384);
if(!sizeof(r))
break;
read_buf += inf->inflate(r);
}
string res = read_buf[..len-1];
read_buf = read_buf[len..];
file_pos += sizeof(res);
return res;
}
//! Writes the data to the file.
//! @returns
//! the number of bytes written to the file.
int write(string data)
{
if(!def) { def = deflate(-level, strategy); crc = crc32(""); }
string comp = def->deflate(data, NO_FLUSH);
if(f->write(comp) != sizeof(comp))
return 0;
else {
file_pos += sizeof(data);
crc = crc32(data, crc);
return sizeof(data);
}
}
//! Seeks within the file.
//! @param pos
//! Position relative to the searchtype.
//! @param type
//! SEEK_SET = set current position in file to pos
//! SEEK_CUR = new position is current+pos
//! SEEK_END is not supported.
//! @returns
//! New position or negative number if seek failed.
int seek(int pos, void|int type)
{
if(type != SEEK_SET && type != SEEK_CUR)
return -1;
if(write_mode) {
if(type == SEEK_SET)
pos -= file_pos;
if(pos < 0)
return -1;
while(pos > 0) {
int n = write("\0"*(pos>16384? 16384:pos));
if(!n)
return -1;
pos -= n;
}
return file_pos;
} else {
if(type == SEEK_CUR)
pos += file_pos;
if(pos < 0)
return -1;
if(!f->seek || f->seek(0)<0)
return -1;
file_pos = 0;
read_buf = "";
while(pos > 0) {
string r = read(pos>16384? 16384:pos);
if(!sizeof(r))
return -1;
pos -= sizeof(r);
}
return file_pos;
}
}
//! @returns
//! the current position within the file.
int tell()
{
return file_pos;
}
//! @returns
//! 1 if EOF has been reached.
int(0..1) eof()
{
if(def || sizeof(read_buf)) return 0;
if(!inf) inf = inflate(-15);
string r = f->read(16384);
if(!sizeof(r))
return 1;
read_buf = inf->inflate(r);
return !sizeof(read_buf);
}
//! Sets the encoding level and strategy
//! @param level
//! Level of the compression.
//! 0 is the least compression, 9 is max. 8 is default.
//! @param strategy
//! Set strategy for encoding to one of the following:
//! DEFAULT_STRATEGY
//! FILTERED
//! HUFFMAN_ONLY
int setparams(int level, int strategy)
{
if(def) {
string s = def->deflate("", FINISH);
if(sizeof(s) && f->write(s) != sizeof(s))
return 0;
def = 0;
}
_file::level = level;
_file::strategy = strategy;
return 1;
}
}
//! Allows the user to open a Gzip archive and read and write
//! it's contents in an uncompressed form, emulating the @[Stdio.File]
//! interface.
//! @note
//! An important limitation on this class is that it may only be used
//! for reading @b{or@} writing, not both at the same time.
//! Please also note that if you want to reopen a file for reading
//! after a write, you must close the file before calling open or
//! strange effects might be the result.
class File {
inherit _file;
private int is_open = 0;
//! @decl void create(void|string|int|Stdio.Stream file, void|string mode)
//! @param file
//! Filename or filedescriptor of the gzip file to open, or an already
//! open Stream.
//! @param mode
//! mode for the file. Defaults to "rb".
//! @seealso
//! @[open] @[Stdio.File]
static void create(mixed ... args) {
::create();
if(sizeof(args)) {
open(@args);
}
}
static string _sprintf(int t)
{
switch(t) {
case 'O':
return sprintf("Gz.File(/*%s open */)", is_open ? "" : " not");
case 't':
return "Gz.File";
default:
return UNDEFINED;
}
}
int close()
{
is_open = 0;
return ::close();
}
static void destroy() {
close();
}
//! @param file
//! Filename or filedescriptor of the gzip file to open, or an already
//! open Stream.
//! @param mode
//! mode for the file. Defaults to "rb".
//! May be one of the following:
//! @dl
//! @item rb
//! read mode
//! @item wb
//! write mode
//! @item ab
//! append mode
//! @enddl
//! For the wb and ab mode, additional parameters may
//! be specified. Please se zlib manual for more info.
//! @returns
//! non-zero if successful.
int open(string|int|Stdio.Stream file, void|string mode) {
string open_mode="rb";
if (is_open) {
::close();
}
if (stringp(mode)) {
open_mode = lower_case(mode);
}
is_open = ::open(file, open_mode);
return is_open;
}
//! Reads data from the file.
//! If no argument is given, the whole file is read.
int|string read(void|int length) {
if (!is_open) {
return 0;
}
if (!zero_type(length))
return ::read(length);
String.Buffer buf = String.Buffer();
string data;
do {
if (!(data = ::read(1024*64))) break;
buf->add(data);
} while (sizeof(data));
return (string)buf;
}
}