类 Zlib::Inflate

Zlib::Inflate 是用于解压缩压缩数据的类。与 Zlib::Deflate 不同,此类的实例无法自我复制(克隆、dup)。

公共类方法

inflate(string) 点击切换源代码
Zlib::Inflate.inflate(string)

解压缩 string。如果解压缩需要预设字典,则会引发 Zlib::NeedDict 异常。

此方法几乎等同于以下代码

def inflate(string)
  zstream = Zlib::Inflate.new
  buf = zstream.inflate(string)
  zstream.finish
  zstream.close
  buf
end

另请参见 Zlib.deflate

static VALUE
rb_inflate_s_inflate(VALUE obj, VALUE src)
{
    struct zstream z;
    VALUE dst, args[2];
    int err;

    StringValue(src);
    zstream_init_inflate(&z);
    err = inflateInit(&z.stream);
    if (err != Z_OK) {
        raise_zlib_error(err, z.stream.msg);
    }
    ZSTREAM_READY(&z);

    args[0] = (VALUE)&z;
    args[1] = src;
    dst = rb_ensure(inflate_run, (VALUE)args, zstream_ensure_end, (VALUE)&z);

    return dst;
}
Zlib::Inflate.new(window_bits = Zlib::MAX_WBITS) 点击切换源代码

创建一个新的 inflate 流用于解压缩。window_bits 设置历史缓冲区的大小,可以取以下值

0

让 inflate 使用压缩流的 zlib 头部的窗口大小。

(8..15)

覆盖压缩流中 inflate 头部的窗口大小。窗口大小必须大于或等于压缩流的窗口大小。

大于 15

在 window_bits 中添加 32 以启用 zlib 和 gzip 解码,并自动检测头部,或添加 16 以仅解码 gzip 格式(对于非 gzip 流将引发 Zlib::DataError)。

(-8..-15)

启用原始 deflate 模式,该模式不会生成校验值,也不会在流末尾查找任何校验值以进行比较。

这适用于使用 deflate 压缩数据格式的其他格式,例如 zip,它们提供自己的校验值。

示例

open "compressed.file" do |compressed_io|
  zi = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)

  begin
    open "uncompressed.file", "w+" do |uncompressed_io|
      uncompressed_io << zi.inflate(compressed_io.read)
    end
  ensure
    zi.close
  end
end
static VALUE
rb_inflate_initialize(int argc, VALUE *argv, VALUE obj)
{
    struct zstream *z;
    VALUE wbits;
    int err;

    rb_scan_args(argc, argv, "01", &wbits);
    TypedData_Get_Struct(obj, struct zstream, &zstream_data_type, z);

    err = inflateInit2(&z->stream, ARG_WBITS(wbits));
    if (err != Z_OK) {
        raise_zlib_error(err, z->stream.msg);
    }
    ZSTREAM_READY(z);

    return obj;
}

公共实例方法

<<(p1) 点击切换源代码

与 IO 相同。

static VALUE
rb_inflate_addstr(VALUE obj, VALUE src)
{
    struct zstream *z = get_zstream(obj);

    if (ZSTREAM_IS_FINISHED(z)) {
        if (!NIL_P(src)) {
            StringValue(src);
            zstream_append_buffer2(z, src);
        }
    }
    else {
        do_inflate(z, src);
        if (ZSTREAM_IS_FINISHED(z)) {
            zstream_passthrough_input(z);
        }
    }

    return obj;
}
add_dictionary(string) 点击切换源代码

为 inflate 流提供一个字典,该字典可能在将来需要。可以提供多个字典。inflate 流将根据流所需的字典自动选择正确用户提供的字典。

static VALUE
rb_inflate_add_dictionary(VALUE obj, VALUE dictionary)
{
    VALUE dictionaries = rb_ivar_get(obj, id_dictionaries);
    VALUE checksum = do_checksum(1, &dictionary, adler32);

    rb_hash_aset(dictionaries, checksum, dictionary);

    return obj;
}
inflate(deflate_string, buffer: nil) → String 点击切换源代码
inflate(deflate_string, buffer: nil) { |chunk| ... } → nil

deflate_string 输入 inflate 流并返回流的输出。调用此方法,流的输入和输出缓冲区都将被刷新。如果字符串为 nil,则此方法将完成流,就像 Zlib::ZStream#finish 一样。

如果给定一个块,则来自 deflate_string 的连续膨胀块将被传递给该块,并返回 nil

如果给定一个 :buffer 关键字参数且不为 nil

  • :buffer 关键字应该是一个字符串,并将用作输出缓冲区。使用此选项可以重用膨胀期间所需的内存。

  • 当不传递块时,返回值将与 :buffer 关键字参数相同。

  • 当传递块时,传递的块将与 :buffer 关键字参数的值相同。

如果需要预设字典来解压缩,则会引发 Zlib::NeedDict 异常。通过 Zlib::Inflate#set_dictionary 设置字典,然后使用空字符串再次调用此方法以刷新流

inflater = Zlib::Inflate.new

begin
  out = inflater.inflate compressed
rescue Zlib::NeedDict
  # ensure the dictionary matches the stream's required dictionary
  raise unless inflater.adler == Zlib.adler32(dictionary)

  inflater.set_dictionary dictionary
  inflater.inflate ''
end

# ...

inflater.close

另请参阅 Zlib::Inflate.new

static VALUE
rb_inflate_inflate(int argc, VALUE* argv, VALUE obj)
{
    struct zstream *z = get_zstream(obj);
    VALUE dst, src, opts, buffer = Qnil;

    if (OPTHASH_GIVEN_P(opts)) {
        VALUE buf;
        rb_get_kwargs(opts, &id_buffer, 0, 1, &buf);
        if (buf != Qundef && buf != Qnil) {
            buffer = StringValue(buf);
        }
    }
    if (buffer != Qnil) {
        if (!(ZSTREAM_REUSE_BUFFER_P(z) && z->buf == buffer)) {
            long len = RSTRING_LEN(buffer);
            if (len >= ZSTREAM_AVAIL_OUT_STEP_MAX) {
                rb_str_modify(buffer);
            }
            else {
                len = ZSTREAM_AVAIL_OUT_STEP_MAX - len;
                rb_str_modify_expand(buffer, len);
            }
            rb_str_set_len(buffer, 0);
            z->flags |= ZSTREAM_REUSE_BUFFER;
            z->buf = buffer;
        }
    } else if (ZSTREAM_REUSE_BUFFER_P(z)) {
        z->flags &= ~ZSTREAM_REUSE_BUFFER;
        z->buf = Qnil;
    }
    rb_scan_args(argc, argv, "10", &src);

    if (ZSTREAM_IS_FINISHED(z)) {
        if (NIL_P(src)) {
            dst = zstream_detach_buffer(z);
        }
        else {
            StringValue(src);
            zstream_append_buffer2(z, src);
            if (ZSTREAM_REUSE_BUFFER_P(z)) {
                dst = rb_str_resize(buffer, 0);
            } else {
                dst = rb_str_new(0, 0);
            }
        }
    }
    else {
        do_inflate(z, src);
        dst = zstream_detach_buffer(z);
        if (ZSTREAM_IS_FINISHED(z)) {
            zstream_passthrough_input(z);
        }
    }

    return dst;
}
set_dictionary(p1) 点击切换源代码

设置预设字典并返回 string。此方法仅在引发 Zlib::NeedDict 异常后才可用。有关详细信息,请参阅 zlib.h。

static VALUE
rb_inflate_set_dictionary(VALUE obj, VALUE dic)
{
    struct zstream *z = get_zstream(obj);
    VALUE src = dic;
    int err;

    StringValue(src);
    err = inflateSetDictionary(&z->stream,
                               (Bytef*)RSTRING_PTR(src), RSTRING_LENINT(src));
    if (err != Z_OK) {
        raise_zlib_error(err, z->stream.msg);
    }

    return dic;
}
sync(string) 点击切换源代码

string 输入输入缓冲区的末尾,并跳过数据,直到找到完整的刷新点。如果在缓冲区中找到该点,则此方法将刷新缓冲区并返回 false。否则,它将返回 true,并且完整刷新点的后续数据将保留在缓冲区中。

static VALUE
rb_inflate_sync(VALUE obj, VALUE src)
{
    struct zstream *z = get_zstream(obj);

    StringValue(src);
    return zstream_sync(z, (Bytef*)RSTRING_PTR(src), RSTRING_LEN(src));
}
sync_point?() 点击切换源代码

从原始文档中逐字引用

What is this?

:)

static VALUE
rb_inflate_sync_point_p(VALUE obj)
{
    struct zstream *z = get_zstream(obj);
    int err;

    err = inflateSyncPoint(&z->stream);
    if (err == 1) {
        return Qtrue;
    }
    if (err != Z_OK) {
        raise_zlib_error(err, z->stream.msg);
    }
    return Qfalse;
}