class Zip::Archive

Public Class Methods

decrypt(p1, p2) click to toggle source
static VALUE zipruby_archive_s_decrypt(VALUE self, VALUE path, VALUE password) {
  int res;
  int errorp, wrongpwd;
  long pwdlen;

  Check_Type(path, T_STRING);
  Check_Type(password, T_STRING);
  pwdlen = RSTRING_LEN(password);

  if (pwdlen < 1) {
    rb_raise(Error, "Decrypt archive failed - %s: Password is empty", RSTRING_PTR(path));
  } else if (pwdlen > 0xff) {
    rb_raise(Error, "Decrypt archive failed - %s: Password is too long", RSTRING_PTR(path));
  }

  res = zip_decrypt(RSTRING_PTR(path), RSTRING_PTR(password), pwdlen, &errorp, &wrongpwd);

  if (res == -1) {
    if (wrongpwd) {
      rb_raise(Error, "Decrypt archive failed - %s: Wrong password", RSTRING_PTR(path));
    } else {
      char errstr[ERRSTR_BUFSIZE];
      zip_error_to_str(errstr, ERRSTR_BUFSIZE, errorp, errno);
      rb_raise(Error, "Decrypt archive failed - %s: %s", RSTRING_PTR(path), errstr);
    }
  }

  return (res > 0) ? Qtrue : Qfalse;
}
encrypt(p1, p2) click to toggle source
static VALUE zipruby_archive_s_encrypt(VALUE self, VALUE path, VALUE password) {
  int res;
  int errorp;
  long pwdlen;

  Check_Type(path, T_STRING);
  Check_Type(password, T_STRING);
  pwdlen = RSTRING_LEN(password);

  if (pwdlen < 1) {
    rb_raise(Error, "Encrypt archive failed - %s: Password is empty", RSTRING_PTR(path));
  } else if (pwdlen > 0xff) {
    rb_raise(Error, "Encrypt archive failed - %s: Password is too long", RSTRING_PTR(path));
  }

  res = zip_encrypt(RSTRING_PTR(path), RSTRING_PTR(password), pwdlen, &errorp);

  if (res == -1) {
    char errstr[ERRSTR_BUFSIZE];
    zip_error_to_str(errstr, ERRSTR_BUFSIZE, errorp, errno);
    rb_raise(Error, "Encrypt archive failed - %s: %s", RSTRING_PTR(path), errstr);
  }

  return (res > 0) ? Qtrue : Qfalse;
}
open(p1, p2 = v2, p3 = v3) click to toggle source
static VALUE zipruby_archive_s_open(int argc, VALUE *argv, VALUE self) {
  VALUE path, flags, comp_level;
  VALUE archive;
  struct zipruby_archive *p_archive;
  int i_flags = 0;
  int errorp;
  int i_comp_level = Z_BEST_COMPRESSION;

  rb_scan_args(argc, argv, "12", &path, &flags, &comp_level);
  Check_Type(path, T_STRING);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  if (!NIL_P(comp_level)) {
    i_comp_level = NUM2INT(comp_level);

    if (i_comp_level != Z_DEFAULT_COMPRESSION && i_comp_level != Z_NO_COMPRESSION && (i_comp_level < Z_BEST_SPEED || Z_BEST_COMPRESSION < i_comp_level)) {
      rb_raise(rb_eArgError, "Wrong compression level %d", i_comp_level);
    }
  }

  archive = rb_funcall(Archive, rb_intern("new"), 0);
  Data_Get_Struct(archive, struct zipruby_archive, p_archive);

  if ((p_archive->archive = zip_open(RSTRING_PTR(path), i_flags, &errorp)) == NULL) {
    char errstr[ERRSTR_BUFSIZE];
    zip_error_to_str(errstr, ERRSTR_BUFSIZE, errorp, errno);
    rb_raise(Error, "Open archive failed - %s: %s", RSTRING_PTR(path), errstr);
  }

  p_archive->archive->comp_level = i_comp_level;
  p_archive->path = path;
  p_archive->flags = i_flags;
  p_archive->sources = rb_ary_new();

  if (rb_block_given_p()) {
    VALUE retval;
    int status;

    retval = rb_protect(rb_yield, archive, &status);
    zipruby_archive_close(archive);

    if (status != 0) {
      rb_jump_tag(status);
    }

    return retval;
  } else {
    return archive;
  }
}
open_buffer(p1 = v1, p2 = v2, p3 = v3) click to toggle source
static VALUE zipruby_archive_s_open_buffer(int argc, VALUE *argv, VALUE self) {
  VALUE buffer, flags, comp_level;
  VALUE archive;
  struct zipruby_archive *p_archive;
  void *data = NULL;
  int len = 0, i_flags = 0;
  int errorp;
  int i_comp_level = Z_BEST_COMPRESSION;
  int buffer_is_temporary = 0;

  rb_scan_args(argc, argv, "03", &buffer, &flags, &comp_level);

  if (FIXNUM_P(buffer) && NIL_P(comp_level)) {
    comp_level = flags;
    flags = buffer;
    buffer = Qnil;
  }

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  if (!NIL_P(comp_level)) {
    i_comp_level = NUM2INT(comp_level);

    if (i_comp_level != Z_DEFAULT_COMPRESSION && i_comp_level != Z_NO_COMPRESSION && (i_comp_level < Z_BEST_SPEED || Z_BEST_COMPRESSION < i_comp_level)) {
      rb_raise(rb_eArgError, "Wrong compression level %d", i_comp_level);
    }
  }

  if (i_flags & ZIP_CREATE) {
    if (!NIL_P(buffer)) {
      Check_Type(buffer, T_STRING);
    } else {
      buffer = rb_str_new("", 0);
      buffer_is_temporary = 1;
    }

    i_flags = (i_flags | ZIP_TRUNC);
  } else if (TYPE(buffer) == T_STRING) {
    data = RSTRING_PTR(buffer);
    len = RSTRING_LEN(buffer);
  } else if (rb_obj_is_instance_of(buffer, rb_cProc)) {
    data = (void *) buffer;
    len = -1;
  } else {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Proc)", rb_class2name(CLASS_OF(buffer)));
  }

  archive = rb_funcall(Archive, rb_intern("new"), 0);
  Data_Get_Struct(archive, struct zipruby_archive, p_archive);

  if ((p_archive->tmpfilnam = zipruby_tmpnam(data, len)) == NULL) {
    rb_raise(Error, "Open archive failed: Failed to create temporary file");
  }

  if ((p_archive->archive = zip_open(p_archive->tmpfilnam, i_flags, &errorp)) == NULL) {
    char errstr[ERRSTR_BUFSIZE];
    zip_error_to_str(errstr, ERRSTR_BUFSIZE, errorp, errno);
    rb_raise(Error, "Open archive failed: %s", errstr);
  }

  p_archive->archive->comp_level = i_comp_level;
  p_archive->path = rb_str_new2(p_archive->tmpfilnam);
  p_archive->flags = i_flags;
  p_archive->buffer = buffer;
  p_archive->sources = rb_ary_new();

  if (rb_block_given_p()) {
    VALUE retval;
    int status;

    retval = rb_protect(rb_yield, archive, &status);
    zipruby_archive_close(archive);

    if (status != 0) {
      rb_jump_tag(status);
    }

    return buffer_is_temporary ? buffer : retval;
  } else {
    return archive;
  }
}

Public Instance Methods

<<(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_add_io(int argc, VALUE *argv, VALUE self) {
  VALUE name, file, mtime;
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  struct read_io *z;

  rb_scan_args(argc, argv, "11", &name, &file);

  if (NIL_P(file)) {
    file = name;
    name = Qnil;
  }

  Check_IO(file);

  if (NIL_P(name)) {
    if (rb_obj_is_kind_of(file, rb_cFile)) {
      name = rb_funcall(rb_cFile, rb_intern("basename"), 1, rb_funcall(file, rb_intern("path"), 0));
    } else {
      rb_raise(rb_eRuntimeError, "Add io failed - %s: Entry name is not given", RSTRING(rb_inspect(file)));
    }
  }

  if (rb_obj_is_kind_of(file, rb_cFile)) {
    mtime = rb_funcall(file, rb_intern("mtime"), 0);
  } else {
    mtime = rb_funcall(rb_cTime, rb_intern("now"), 0);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive); 
  Check_Archive(p_archive);

  if ((z = malloc(sizeof(struct read_io))) == NULL) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(rb_eRuntimeError, "Add io failed - %s: Cannot allocate memory", RSTRING(rb_inspect(file)));
  }

  z->io = file;
  rb_ary_push(p_archive->sources, file);
  z->mtime = TIME2LONG(mtime);

  if ((zsource = zip_source_io(p_archive->archive, z)) == NULL) {
    free(z);
    rb_raise(Error, "Add io failed - %s: %s", RSTRING(rb_inspect(file)), zip_strerror(p_archive->archive));
  }

  if (zip_add(p_archive->archive, RSTRING_PTR(name), zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Add io failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
add(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_add_function(int argc, VALUE *argv, VALUE self) {
  VALUE name, mtime;
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  struct read_proc *z;

  rb_scan_args(argc, argv, "11", &name, &mtime);
  rb_need_block();
  Check_Type(name, T_STRING);

  if (NIL_P(mtime)) {
    mtime = rb_funcall(rb_cTime, rb_intern("now"), 0);
  } else if (!rb_obj_is_instance_of(mtime, rb_cTime)) {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected Time)", rb_class2name(CLASS_OF(mtime)));
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive); 
  Check_Archive(p_archive);

  if ((z = malloc(sizeof(struct read_proc))) == NULL) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(rb_eRuntimeError, "Add failed - %s: Cannot allocate memory", RSTRING_PTR(name));
  }

  z->proc = rb_block_proc();
  rb_ary_push(p_archive->sources, z->proc);
  z->mtime = TIME2LONG(mtime);

  if ((zsource = zip_source_proc(p_archive->archive, z)) == NULL) {
    free(z);
    rb_raise(Error, "Add failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  if (zip_add(p_archive->archive, RSTRING_PTR(name), zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Add file failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
add_buffer(p1, p2) click to toggle source
static VALUE zipruby_archive_add_buffer(VALUE self, VALUE name, VALUE source) {
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  char *data;
  size_t len;

  Check_Type(name, T_STRING);
  Check_Type(source, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  len = RSTRING_LEN(source);

  if ((data = malloc(len)) == NULL) {
    rb_raise(rb_eRuntimeError, "Add file failed: Cannot allocate memory");
  }

  memset(data, 0, len);
  memcpy(data, RSTRING_PTR(source), len);

  if ((zsource = zip_source_buffer(p_archive->archive, data, len, 1)) == NULL) {
    free(data);
    rb_raise(Error, "Add file failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  if (zip_add(p_archive->archive, RSTRING_PTR(name), zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Add file failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
add_dir(p1) click to toggle source
static VALUE zipruby_archive_add_dir(VALUE self, VALUE name) {
  struct zipruby_archive *p_archive;

  Check_Type(name, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_add_dir(p_archive->archive, RSTRING_PTR(name)) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Add dir failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
add_file(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_add_file(int argc, VALUE *argv, VALUE self) {
  VALUE name, fname;
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;

  rb_scan_args(argc, argv, "11", &name, &fname);

  if (NIL_P(fname)) {
    fname = name;
    name = Qnil;
  }

  Check_Type(fname, T_STRING);

  if (NIL_P(name)) {
    name = rb_funcall(rb_cFile, rb_intern("basename"), 1, fname);
  }

  Check_Type(name, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if ((zsource = zip_source_file(p_archive->archive, RSTRING_PTR(fname), 0, -1)) == NULL) {
    rb_raise(Error, "Add file failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  if (zip_add(p_archive->archive, RSTRING_PTR(name), zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Add file failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
add_io(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_add_io(int argc, VALUE *argv, VALUE self) {
  VALUE name, file, mtime;
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  struct read_io *z;

  rb_scan_args(argc, argv, "11", &name, &file);

  if (NIL_P(file)) {
    file = name;
    name = Qnil;
  }

  Check_IO(file);

  if (NIL_P(name)) {
    if (rb_obj_is_kind_of(file, rb_cFile)) {
      name = rb_funcall(rb_cFile, rb_intern("basename"), 1, rb_funcall(file, rb_intern("path"), 0));
    } else {
      rb_raise(rb_eRuntimeError, "Add io failed - %s: Entry name is not given", RSTRING(rb_inspect(file)));
    }
  }

  if (rb_obj_is_kind_of(file, rb_cFile)) {
    mtime = rb_funcall(file, rb_intern("mtime"), 0);
  } else {
    mtime = rb_funcall(rb_cTime, rb_intern("now"), 0);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive); 
  Check_Archive(p_archive);

  if ((z = malloc(sizeof(struct read_io))) == NULL) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(rb_eRuntimeError, "Add io failed - %s: Cannot allocate memory", RSTRING(rb_inspect(file)));
  }

  z->io = file;
  rb_ary_push(p_archive->sources, file);
  z->mtime = TIME2LONG(mtime);

  if ((zsource = zip_source_io(p_archive->archive, z)) == NULL) {
    free(z);
    rb_raise(Error, "Add io failed - %s: %s", RSTRING(rb_inspect(file)), zip_strerror(p_archive->archive));
  }

  if (zip_add(p_archive->archive, RSTRING_PTR(name), zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Add io failed - %s: %s", RSTRING_PTR(name), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
add_or_replace(p1, p2 = v2, p3 = v3) click to toggle source
static VALUE zipruby_archive_add_or_replace_function(int argc, VALUE *argv, VALUE self) {
  VALUE name, mtime, flags;
  struct zipruby_archive *p_archive;
  int index, i_flags = 0;

  rb_scan_args(argc, argv, "12", &name, &mtime, &flags);

  if (NIL_P(flags) && FIXNUM_P(mtime)) {
    flags = mtime;
    mtime = Qnil;
  }

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Check_Type(name, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  index = zip_name_locate(p_archive->archive, RSTRING_PTR(name), i_flags);

  if (index >= 0) {
    VALUE _args[] = { INT2NUM(index), mtime };
    return zipruby_archive_replace_function(2, _args, self);
  } else {
    VALUE _args[] = { name, mtime };
    return zipruby_archive_add_function(2, _args, self);
  }
}
add_or_replace_buffer(p1, p2, p3 = v3) click to toggle source
static VALUE zipruby_archive_add_or_replace_buffer(int argc, VALUE *argv, VALUE self) {
  struct zipruby_archive *p_archive;
  VALUE name, source, flags;
  int index, i_flags = 0;

  rb_scan_args(argc, argv, "21", &name, &source, &flags);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Check_Type(name, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  index = zip_name_locate(p_archive->archive, RSTRING_PTR(name), i_flags);

  if (index >= 0) {
    VALUE _args[] = { INT2NUM(index), source };
    return zipruby_archive_replace_buffer(2, _args, self);
  } else {
    return zipruby_archive_add_buffer(self, name, source);
  }
}
add_or_replace_file(p1, p2 = v2, p3 = v3) click to toggle source
static VALUE zipruby_archive_add_or_replace_file(int argc, VALUE *argv, VALUE self) {
  VALUE name, fname, flags;
  struct zipruby_archive *p_archive;
  int index, i_flags = 0;

  rb_scan_args(argc, argv, "12", &name, &fname, &flags);

  if (NIL_P(flags) && FIXNUM_P(fname)) {
    flags = fname;
    fname = Qnil;
  }

  if (NIL_P(fname)) {
    fname = name;
    name = Qnil;
  }

  Check_Type(fname, T_STRING);

  if (NIL_P(name)) {
    name = rb_funcall(rb_cFile, rb_intern("basename"), 1, fname);
  }

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Check_Type(name, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  index = zip_name_locate(p_archive->archive, RSTRING_PTR(name), i_flags);

  if (index >= 0) {
    VALUE _args[] = { INT2NUM(index), fname };
    return zipruby_archive_replace_file(2, _args, self);
  } else {
    VALUE _args[] = { name, fname };
    return zipruby_archive_add_file(2, _args, self);
  }
}
add_or_replace_io(p1, p2, p3 = v3) click to toggle source
static VALUE zipruby_archive_add_or_replace_io(int argc, VALUE *argv, VALUE self) {
  VALUE name, io, flags;
  struct zipruby_archive *p_archive;
  int index, i_flags = 0;

  rb_scan_args(argc, argv, "21", &name, &io, &flags);
  Check_IO(io);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Check_Type(name, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  index = zip_name_locate(p_archive->archive, RSTRING_PTR(name), i_flags);

  if (index >= 0) {
    VALUE _args[] = {INT2NUM(index), io, flags};
    return zipruby_archive_replace_io(2, _args, self);
  } else {
    VALUE _args[2] = { name, io };
    return zipruby_archive_add_io(2, _args, self);
  }
}
close() click to toggle source
static VALUE zipruby_archive_close(VALUE self) {
  struct zipruby_archive *p_archive;
  int changed, survivors;

  if (!zipruby_archive_is_open(self)) {
    return Qfalse;
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  changed = _zip_changed(p_archive->archive, &survivors);

  if (zip_close(p_archive->archive) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Close archive failed: %s", zip_strerror(p_archive->archive));
  }

  if (!NIL_P(p_archive->sources)){
    rb_ary_clear(p_archive->sources);
  }

  if (!NIL_P(p_archive->buffer) && changed) {
    rb_funcall(p_archive->buffer, rb_intern("replace"), 1, rb_funcall(self, rb_intern("read"), 0));
  }

  zipruby_rmtmp(p_archive->tmpfilnam);
  p_archive->archive = NULL;
  p_archive->flags = 0;

  return Qtrue;
}
comment(p1 = v1) click to toggle source
static VALUE zipruby_archive_get_comment(int argc, VALUE *argv, VALUE self) {
  VALUE flags;
  struct zipruby_archive *p_archive;
  const char *comment;
  int lenp, i_flags = 0;

  rb_scan_args(argc, argv, "01", &flags);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  // XXX: How is the error checked?
  comment = zip_get_archive_comment(p_archive->archive, &lenp, i_flags);

  return comment ? rb_str_new(comment, lenp) : Qnil;
}
comment=(p1) click to toggle source
static VALUE zipruby_archive_set_comment(VALUE self, VALUE comment) {
  struct zipruby_archive *p_archive;
  const char *s_comment = NULL;
  int len = 0;

  if (!NIL_P(comment)) {
    Check_Type(comment, T_STRING);
    s_comment = RSTRING_PTR(comment);
    len = RSTRING_LEN(comment);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_set_archive_comment(p_archive->archive, s_comment, len) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Comment archived failed: %s", zip_strerror(p_archive->archive));
  }

  return Qnil;
}
commit() click to toggle source
static VALUE zipruby_archive_commit(VALUE self) {
  struct zipruby_archive *p_archive;
  int changed, survivors;
  int errorp;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  changed = _zip_changed(p_archive->archive, &survivors);

  if (zip_close(p_archive->archive) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Commit archive failed: %s", zip_strerror(p_archive->archive));
  }

  if (!NIL_P(p_archive->sources)){
    rb_ary_clear(p_archive->sources);
  }

  if (!NIL_P(p_archive->buffer) && changed) {
    rb_funcall(p_archive->buffer, rb_intern("replace"), 1, rb_funcall(self, rb_intern("read"), 0));
  }

  p_archive->archive = NULL;
  p_archive->flags = (p_archive->flags & ~(ZIP_CREATE | ZIP_EXCL));

  if ((p_archive->archive = zip_open(RSTRING_PTR(p_archive->path), p_archive->flags, &errorp)) == NULL) {
    char errstr[ERRSTR_BUFSIZE];
    zip_error_to_str(errstr, ERRSTR_BUFSIZE, errorp, errno);
    rb_raise(Error, "Commit archive failed: %s", errstr);
  }

  return Qnil;
}
decrypt(p1) click to toggle source
static VALUE zipruby_archive_decrypt(VALUE self, VALUE password) {
  VALUE retval;
  struct zipruby_archive *p_archive;
  long pwdlen;
  int changed, survivors;
  int errorp;

  Check_Type(password, T_STRING);
  pwdlen = RSTRING_LEN(password);

  if (pwdlen < 1) {
    rb_raise(Error, "Decrypt archive failed: Password is empty");
  } else if (pwdlen > 0xff) {
    rb_raise(Error, "Decrypt archive failed: Password is too long");
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  changed = _zip_changed(p_archive->archive, &survivors);

  if (zip_close(p_archive->archive) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Decrypt archive failed: %s", zip_strerror(p_archive->archive));
  }

  if (!NIL_P(p_archive->buffer) && changed) {
    rb_funcall(p_archive->buffer, rb_intern("replace"), 1, rb_funcall(self, rb_intern("read"), 0));
  }

  p_archive->archive = NULL;
  p_archive->flags = (p_archive->flags & ~(ZIP_CREATE | ZIP_EXCL));

  retval = zipruby_archive_s_decrypt(Archive, p_archive->path, password);

  if ((p_archive->archive = zip_open(RSTRING_PTR(p_archive->path), p_archive->flags, &errorp)) == NULL) {
    char errstr[ERRSTR_BUFSIZE];
    zip_error_to_str(errstr, ERRSTR_BUFSIZE, errorp, errno);
    rb_raise(Error, "Decrypt archive failed: %s", errstr);
  }

  return retval;
}
each() click to toggle source
static VALUE zipruby_archive_each(VALUE self) {
  struct zipruby_archive *p_archive;
  int i, num_files;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);
  num_files = zip_get_num_files(p_archive->archive);

  for (i = 0; i < num_files; i++) {
    VALUE file;
    int status;

    file = rb_funcall(File, rb_intern("new"), 2, self, INT2NUM(i));
    rb_protect(rb_yield, file, &status);
    rb_funcall(file, rb_intern("close"), 0);

    if (status != 0) {
      rb_jump_tag(status);
    }
  }

  return Qnil;
}
encrypt(p1) click to toggle source
static VALUE zipruby_archive_encrypt(VALUE self, VALUE password) {
  VALUE retval;
  struct zipruby_archive *p_archive;
  long pwdlen;
  int changed, survivors;
  int errorp;

  Check_Type(password, T_STRING);
  pwdlen = RSTRING_LEN(password);

  if (pwdlen < 1) {
    rb_raise(Error, "Encrypt archive failed: Password is empty");
  } else if (pwdlen > 0xff) {
    rb_raise(Error, "Encrypt archive failed: Password is too long");
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  changed = _zip_changed(p_archive->archive, &survivors);

  if (zip_close(p_archive->archive) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Encrypt archive failed: %s", zip_strerror(p_archive->archive));
  }

  if (!NIL_P(p_archive->buffer) && changed) {
    rb_funcall(p_archive->buffer, rb_intern("replace"), 1, rb_funcall(self, rb_intern("read"), 0));
  }

  p_archive->archive = NULL;
  p_archive->flags = (p_archive->flags & ~(ZIP_CREATE | ZIP_EXCL));

  retval = zipruby_archive_s_encrypt(Archive, p_archive->path, password);

  if ((p_archive->archive = zip_open(RSTRING_PTR(p_archive->path), p_archive->flags, &errorp)) == NULL) {
    char errstr[ERRSTR_BUFSIZE];
    zip_error_to_str(errstr, ERRSTR_BUFSIZE, errorp, errno);
    rb_raise(Error, "Encrypt archive failed: %s", errstr);
  }

  return retval;
}
fdelete(p1) click to toggle source
static VALUE zipruby_archive_fdelete(VALUE self, VALUE index) {
  struct zipruby_archive *p_archive;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_delete(p_archive->archive, NUM2INT(index)) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Delete file failed at %d: %s", NUM2INT(index), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
fopen(p1, p2 = v2, p3 = v3) click to toggle source
static VALUE zipruby_archive_fopen(int argc, VALUE *argv, VALUE self) {
  VALUE index, flags, stat_flags, file;

  rb_scan_args(argc, argv, "12", &index, &flags, &stat_flags);
  file = rb_funcall(File, rb_intern("new"), 4, self, index, flags, stat_flags);

  if (rb_block_given_p()) {
    VALUE retval;
    int status;

    retval = rb_protect(rb_yield, file, &status);
    rb_funcall(file, rb_intern("close"), 0);

    if (status != 0) {
      rb_jump_tag(status);
    }

    return retval;
  } else {
    return file;
  }
}
frename(p1, p2) click to toggle source
static VALUE zipruby_archive_frename(VALUE self, VALUE index, VALUE name) {
  struct zipruby_archive *p_archive;

  Check_Type(name, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_rename(p_archive->archive, NUM2INT(index), RSTRING_PTR(name)) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Rename file failed at %d: %s", NUM2INT(index), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
frevert(p1) click to toggle source
static VALUE zipruby_archive_unchange(VALUE self) {
  struct zipruby_archive *p_archive;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_unchange_archive(p_archive->archive) == -1) {
    rb_raise(Error, "Unchange archive failed: %s", zip_strerror(p_archive->archive));
  }

  return Qnil;
}
funchange(p1) click to toggle source
static VALUE zipruby_archive_funchange(VALUE self, VALUE index) {
  struct zipruby_archive *p_archive;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_unchange(p_archive->archive, NUM2INT(index)) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Unchange file failed at %d: %s", NUM2INT(index), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
funchange_all() click to toggle source
static VALUE zipruby_archive_funchange_all(VALUE self) {
  struct zipruby_archive *p_archive;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_unchange_all(p_archive->archive) == -1) {
    rb_raise(Error, "Unchange all file failed: %s", zip_strerror(p_archive->archive));
  }

  return Qnil;
}
get_comment(p1 = v1) click to toggle source
static VALUE zipruby_archive_get_comment(int argc, VALUE *argv, VALUE self) {
  VALUE flags;
  struct zipruby_archive *p_archive;
  const char *comment;
  int lenp, i_flags = 0;

  rb_scan_args(argc, argv, "01", &flags);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  // XXX: How is the error checked?
  comment = zip_get_archive_comment(p_archive->archive, &lenp, i_flags);

  return comment ? rb_str_new(comment, lenp) : Qnil;
}
get_fcomment(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_get_fcomment(int argc, VALUE *argv, VALUE self) {
  VALUE index, flags;
  struct zipruby_archive *p_archive;
  const char *comment;
  int lenp, i_flags = 0;

  rb_scan_args(argc, argv, "11", &index, &flags);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  // XXX: How is the error checked?
  comment = zip_get_file_comment(p_archive->archive, NUM2INT(index), &lenp, i_flags);

  return comment ? rb_str_new(comment, lenp) : Qnil;
}
get_name(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_get_name(int argc, VALUE *argv, VALUE self) {
  VALUE index, flags;
  struct zipruby_archive *p_archive;
  int i_flags = 0;
  const char *name;

  rb_scan_args(argc, argv, "11", &index, &flags);
  Check_Type(index, T_FIXNUM);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if ((name = zip_get_name(p_archive->archive, NUM2INT(index), i_flags)) == NULL) {
    rb_raise(Error, "Get name failed at %d: %s", index, zip_strerror(p_archive->archive));
  }

  return (name != NULL) ? rb_str_new2(name) : Qnil;
}
get_stat(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_get_stat(int argc, VALUE *argv, VALUE self) {
  VALUE index, flags;

  rb_scan_args(argc, argv, "11", &index, &flags);

  return rb_funcall(Stat, rb_intern("new"), 3, self, index, flags);
}
locate_name(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_locate_name(int argc, VALUE *argv, VALUE self) {
  VALUE fname, flags;
  struct zipruby_archive *p_archive;
  int i_flags = 0;

  rb_scan_args(argc, argv, "11", &fname, &flags);
  Check_Type(fname, T_STRING);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  return INT2NUM(zip_name_locate(p_archive->archive, RSTRING_PTR(fname), i_flags));
}
num_files() click to toggle source
static VALUE zipruby_archive_num_files(VALUE self) {
  struct zipruby_archive *p_archive;
  int num_files;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);
  num_files = zip_get_num_files(p_archive->archive);

  return INT2NUM(num_files);
}
open?() click to toggle source
static VALUE zipruby_archive_is_open(VALUE self) {
  struct zipruby_archive *p_archive;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  return (p_archive->archive != NULL) ? Qtrue : Qfalse;
}
read() click to toggle source
static VALUE zipruby_archive_read(VALUE self) {
  VALUE retval = Qnil;
  struct zipruby_archive *p_archive;
  FILE *fzip;
  char buf[DATA_BUFSIZE];
  ssize_t n;
  int block_given;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);

  if (NIL_P(p_archive->path)) {
    rb_raise(rb_eRuntimeError, "invalid Zip::Archive");
  }

#ifdef _WIN32
  if (fopen_s(&fzip, RSTRING_PTR(p_archive->path), "rb") != 0) {
    rb_raise(Error, "Read archive failed: Cannot open archive");
  }
#else
  if ((fzip = fopen(RSTRING_PTR(p_archive->path), "rb")) == NULL) {
    rb_raise(Error, "Read archive failed: Cannot open archive");
  }
#endif

  block_given = rb_block_given_p();

  while ((n = fread(buf, 1, sizeof(buf), fzip)) > 0) {
    if (block_given) {
      rb_yield(rb_str_new(buf, n));
    } else {
      if (NIL_P(retval)) {
        retval = rb_str_new(buf, n);
      } else {
        rb_str_buf_cat(retval, buf, n);
      }
    }
  }

#if defined(RUBY_VM) && defined(_WIN32)
  _fclose_nolock(fzip);
#elif defined(RUBY_WIN32_H)
#undef fclose
  fclose(fzip);
#define fclose(f) rb_w32_fclose(f)
#else
  fclose(fzip);
#endif

  if (n == -1) {
    rb_raise(Error, "Read archive failed");
  }

  return retval;
}
replace(p1, p2 = v2, p3 = v3) click to toggle source
static VALUE zipruby_archive_replace_function(int argc, VALUE *argv, VALUE self) {
  VALUE index, flags, mtime;
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  struct read_proc *z;
  int i_index, i_flags = 0;

  rb_scan_args(argc, argv, "12", &index, &mtime, &flags);
  rb_need_block();

  if (TYPE(index) != T_STRING && !FIXNUM_P(index)) {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or String)", rb_class2name(CLASS_OF(index)));
  }

  if (NIL_P(mtime)) {
    mtime = rb_funcall(rb_cTime, rb_intern("now"), 0);
  } else if (!rb_obj_is_instance_of(mtime, rb_cTime)) {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected Time)", rb_class2name(CLASS_OF(mtime)));
  }

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive); 
  Check_Archive(p_archive);

  if (FIXNUM_P(index)) {
    i_index = NUM2INT(index);
  } else if ((i_index = zip_name_locate(p_archive->archive, RSTRING_PTR(index), i_flags)) == -1) {
    rb_raise(Error, "Replace file failed - %s: Archive does not contain a file", RSTRING_PTR(index));
  }

  if ((z = malloc(sizeof(struct read_proc))) == NULL) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(rb_eRuntimeError, "Replace failed at %d: Cannot allocate memory", i_index);
  }

  z->proc = rb_block_proc();
  rb_ary_push(p_archive->sources, z->proc);
  z->mtime = TIME2LONG(mtime);

  if ((zsource = zip_source_proc(p_archive->archive, z)) == NULL) {
    free(z);
    rb_raise(Error, "Replace failed at %d: %s", i_index, zip_strerror(p_archive->archive));
  }

  if (zip_replace(p_archive->archive, i_index, zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Replace failed at %d: %s", i_index, zip_strerror(p_archive->archive));
  }

  return Qnil;
}
replace_buffer(p1, p2, p3 = v3) click to toggle source
static VALUE zipruby_archive_replace_buffer(int argc, VALUE *argv, VALUE self) {
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  VALUE index, source, flags;
  int i_index, i_flags = 0;
  char *data;
  size_t len;

  rb_scan_args(argc, argv, "21", &index, &source, &flags);

  if (TYPE(index) != T_STRING && !FIXNUM_P(index)) {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or String)", rb_class2name(CLASS_OF(index)));
  }

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Check_Type(source, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (FIXNUM_P(index)) {
    i_index = NUM2INT(index);
  } else if ((i_index = zip_name_locate(p_archive->archive, RSTRING_PTR(index), i_flags)) == -1) {
    rb_raise(Error, "Replace file failed - %s: Archive does not contain a file", RSTRING_PTR(index));
  }

  len = RSTRING_LEN(source);

  if ((data = malloc(len)) == NULL) {
    rb_raise(rb_eRuntimeError, "Replace file failed: Cannot allocate memory");
  }

  memcpy(data, RSTRING_PTR(source), len);

  if ((zsource = zip_source_buffer(p_archive->archive, data, len, 1)) == NULL) {
    free(data);
    rb_raise(Error, "Replace file failed at %d: %s", i_index, zip_strerror(p_archive->archive));
  }

  if (zip_replace(p_archive->archive, i_index, zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Replace file failed at %d: %s", i_index, zip_strerror(p_archive->archive));
  }

  return Qnil;
}
replace_file(p1, p2, p3 = v3) click to toggle source
static VALUE zipruby_archive_replace_file(int argc, VALUE* argv, VALUE self) {
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  VALUE index, fname, flags;
  int i_index, i_flags = 0;

  rb_scan_args(argc, argv, "21", &index, &fname, &flags);

  if (TYPE(index) != T_STRING && !FIXNUM_P(index)) {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or String)", rb_class2name(CLASS_OF(index)));
  }

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Check_Type(fname, T_STRING);
  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (FIXNUM_P(index)) {
    i_index = NUM2INT(index);
  } else if ((i_index = zip_name_locate(p_archive->archive, RSTRING_PTR(index), i_flags)) == -1) {
    rb_raise(Error, "Replace file failed - %s: Archive does not contain a file", RSTRING_PTR(index));
  }

  if ((zsource = zip_source_file(p_archive->archive, RSTRING_PTR(fname), 0, -1)) == NULL) {
    rb_raise(Error, "Replace file failed at %d: %s", i_index, zip_strerror(p_archive->archive));
  }

  if (zip_replace(p_archive->archive, i_index, zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Replace file failed at %d: %s", i_index, zip_strerror(p_archive->archive));
  }

  return Qnil;
}
replace_io(p1, p2, p3 = v3) click to toggle source
static VALUE zipruby_archive_replace_io(int argc, VALUE *argv, VALUE self) {
  VALUE file, index, flags, mtime;
  struct zipruby_archive *p_archive;
  struct zip_source *zsource;
  struct read_io *z;
  int i_index, i_flags = 0;

  rb_scan_args(argc, argv, "21", &index, &file, &flags);

  if (TYPE(index) != T_STRING && !FIXNUM_P(index)) {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected Fixnum or String)", rb_class2name(CLASS_OF(index)));
  }

  Check_IO(file);

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  if (rb_obj_is_kind_of(file, rb_cFile)) {
    mtime = rb_funcall(file, rb_intern("mtime"), 0);
  } else {
    mtime = rb_funcall(rb_cTime, rb_intern("now"), 0);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (FIXNUM_P(index)) {
    i_index = NUM2INT(index);
  } else if ((i_index = zip_name_locate(p_archive->archive, RSTRING_PTR(index), i_flags)) == -1) {
    rb_raise(Error, "Replace io failed - %s: Archive does not contain a file", RSTRING_PTR(index));
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive); 
  Check_Archive(p_archive);

  if ((z = malloc(sizeof(struct read_io))) == NULL) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(rb_eRuntimeError, "Replace io failed at %d - %s: Cannot allocate memory", i_index, RSTRING(rb_inspect(file)));
  }

  z->io = file;
  rb_ary_push(p_archive->sources, file);
  z->mtime = TIME2LONG(mtime);

  if ((zsource = zip_source_io(p_archive->archive, z)) == NULL) {
    free(z);
    rb_raise(Error, "Replace io failed at %d - %s: %s", i_index, RSTRING(rb_inspect(file)), zip_strerror(p_archive->archive));
  }

  if (zip_replace(p_archive->archive, i_index, zsource) == -1) {
    zip_source_free(zsource);
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Replace io failed at %d - %s: %s", i_index, RSTRING(rb_inspect(file)), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
revert() click to toggle source
static VALUE zipruby_archive_revert(VALUE self) {
  zipruby_archive_funchange_all(self);
  zipruby_archive_unchange(self);

  return Qnil;
}
set_fcomment(p1, p2) click to toggle source
static VALUE zipruby_archive_set_fcomment(VALUE self, VALUE index, VALUE comment) {
  struct zipruby_archive *p_archive;
  char *s_comment = NULL;
  int len = 0;

  if (!NIL_P(comment)) {
    Check_Type(comment, T_STRING);
    s_comment = RSTRING_PTR(comment);
    len = RSTRING_LEN(comment);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_set_file_comment(p_archive->archive, NUM2INT(index), s_comment, len) == -1) {
    zip_unchange_all(p_archive->archive);
    zip_unchange_archive(p_archive->archive);
    rb_raise(Error, "Comment file failed at %d: %s", NUM2INT(index), zip_strerror(p_archive->archive));
  }

  return Qnil;
}
unchange() click to toggle source
static VALUE zipruby_archive_unchange(VALUE self) {
  struct zipruby_archive *p_archive;

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);

  if (zip_unchange_archive(p_archive->archive) == -1) {
    rb_raise(Error, "Unchange archive failed: %s", zip_strerror(p_archive->archive));
  }

  return Qnil;
}
update(p1, p2 = v2) click to toggle source
static VALUE zipruby_archive_update(int argc, VALUE *argv, VALUE self) {
  struct zipruby_archive *p_archive, *p_srcarchive;
  VALUE srcarchive, flags;
  int i, num_files, i_flags = 0;

  rb_scan_args(argc, argv, "11", &srcarchive, &flags);

  if (!rb_obj_is_instance_of(srcarchive, Archive)) {
    rb_raise(rb_eTypeError, "wrong argument type %s (expected Zip::Archive)", rb_class2name(CLASS_OF(srcarchive)));
  }

  if (!NIL_P(flags)) {
    i_flags = NUM2INT(flags);
  }

  Data_Get_Struct(self, struct zipruby_archive, p_archive);
  Check_Archive(p_archive);
  Data_Get_Struct(srcarchive, struct zipruby_archive, p_srcarchive);
  Check_Archive(p_srcarchive);

  num_files = zip_get_num_files(p_srcarchive->archive);

  for (i = 0; i < num_files; i++) {
    struct zip_source *zsource;
    struct zip_file *fzip;
    struct zip_stat sb;
    char *buf;
    const char *name;
    int index, error;

    zip_stat_init(&sb);

    if (zip_stat_index(p_srcarchive->archive, i, 0, &sb)) {
      zip_unchange_all(p_archive->archive);
      zip_unchange_archive(p_archive->archive);
      rb_raise(Error, "Update archive failed: %s", zip_strerror(p_srcarchive->archive));
    }

    if ((buf = malloc(sb.size)) == NULL) {
      zip_unchange_all(p_archive->archive);
      zip_unchange_archive(p_archive->archive);
      rb_raise(rb_eRuntimeError, "Update archive failed: Cannot allocate memory");
    }

    fzip = zip_fopen_index(p_srcarchive->archive, i, 0);

    if (fzip == NULL) {
      free(buf);
      zip_unchange_all(p_archive->archive);
      zip_unchange_archive(p_archive->archive);
      rb_raise(Error, "Update archive failed: %s", zip_strerror(p_srcarchive->archive));
    }

    if (zip_fread(fzip, buf, sb.size) == -1) {
      free(buf);
      zip_fclose(fzip);
      zip_unchange_all(p_archive->archive);
      zip_unchange_archive(p_archive->archive);
      rb_raise(Error, "Update archive failed: %s", zip_file_strerror(fzip));
    }

    if ((error = zip_fclose(fzip)) != 0) {
      char errstr[ERRSTR_BUFSIZE];
      free(buf);
      zip_unchange_all(p_archive->archive);
      zip_unchange_archive(p_archive->archive);
      zip_error_to_str(errstr, ERRSTR_BUFSIZE, error, errno);
      rb_raise(Error, "Update archive failed: %s", errstr);
    }

    if ((zsource = zip_source_buffer(p_archive->archive, buf, sb.size, 1)) == NULL) {
      free(buf);
      zip_unchange_all(p_archive->archive);
      zip_unchange_archive(p_archive->archive);
      rb_raise(Error, "Update archive failed: %s", zip_strerror(p_archive->archive));
    }

    if ((name = zip_get_name(p_srcarchive->archive, i, 0)) == NULL) {
      zip_source_free(zsource);
      zip_unchange_all(p_archive->archive);
      zip_unchange_archive(p_archive->archive);
      rb_raise(Error, "Update archive failed: %s", zip_strerror(p_srcarchive->archive));
    }

    index = zip_name_locate(p_archive->archive, name, i_flags);

    if (index >= 0) {
      if (zip_replace(p_archive->archive, i, zsource) == -1) {
        zip_source_free(zsource);
        zip_unchange_all(p_archive->archive);
        zip_unchange_archive(p_archive->archive);
        rb_raise(Error, "Update archive failed: %s", zip_strerror(p_archive->archive));
      }
    } else {
      if (zip_add(p_archive->archive, name, zsource) == -1) {
        zip_source_free(zsource);
        zip_unchange_all(p_archive->archive);
        zip_unchange_archive(p_archive->archive);
        rb_raise(Error, "Update archive failed: %s", zip_strerror(p_archive->archive));
      }
    }
  }

  return Qnil;
}