#include "libarchive_internal.h" extern VALUE rb_mArchive; VALUE rb_cArchiveWriter; extern VALUE rb_eArchiveError; extern VALUE rb_cArchiveEntry; static void rb_libarchive_writer_close0(struct rb_libarchive_archive_container *p) { archive_write_close(p->ar); archive_write_finish(p->ar); p->ar = NULL; } /* */ static VALUE rb_libarchive_writer_close(VALUE self) { struct rb_libarchive_archive_container *p; Data_Get_Struct(self, struct rb_libarchive_archive_container, p); Check_Archive(p); rb_libarchive_writer_close0(p); return Qnil; } static VALUE rb_libarchive_writer_s_open0(int (*archive_open)(struct rb_libarchive_archive_container *, void *), void *arg, int compression, int format, const char *cmd) { VALUE writer; struct rb_libarchive_archive_container *p; int r; writer = rb_funcall(rb_cArchiveWriter, rb_intern("new"), 0); Data_Get_Struct(writer, struct rb_libarchive_archive_container, p); if ((p->ar = archive_write_new()) == NULL) { rb_raise(rb_eArchiveError, "Open writer failed: %s", strerror(errno)); } if (cmd != NULL) { r = archive_write_set_compression_program(p->ar, cmd); } else { r = archive_write_set_compression(p->ar, compression); } if (r != ARCHIVE_OK) { char error_string[BUFSIZ]; archive_copy_error_string(p->ar, error_string, BUFSIZ); rb_libarchive_writer_close0(p); rb_raise(rb_eArchiveError, "Set compression failed: %s", error_string); } if (archive_write_set_format(p->ar, format) != ARCHIVE_OK) { char error_string[BUFSIZ]; archive_copy_error_string(p->ar, error_string, BUFSIZ); rb_libarchive_writer_close0(p); rb_raise(rb_eArchiveError, "Set format failed: %s", error_string); } if (archive_open(p, arg) != ARCHIVE_OK) { char error_string[BUFSIZ]; archive_copy_error_string(p->ar, error_string, BUFSIZ); rb_libarchive_writer_close0(p); rb_raise(rb_eArchiveError, "Open writer failed: %s", error_string); } if (rb_block_given_p()) { VALUE retval; int status; retval = rb_protect(rb_yield, writer, &status); rb_libarchive_writer_close0(p); if (status != 0) { rb_jump_tag(status); } return retval; } else { return writer; } } static int rb_libarchive_writer_s_open_filename0(struct rb_libarchive_archive_container *p, void *arg) { const char *filename = (const char *) arg; return archive_write_open_filename(p->ar, filename); } /* */ static VALUE rb_libarchive_writer_s_open_filename(VALUE self, VALUE v_filename, VALUE v_compression, VALUE v_format) { const char *filename = NULL; int compression, format; const char *cmd = NULL; Check_Type(v_filename, T_STRING); if (RSTRING_LEN(v_filename) < 1) { rb_raise(rb_eArchiveError, "Open writer failed: No such file or directory"); } filename = RSTRING_PTR(v_filename); if (T_STRING == TYPE(v_compression)) { compression = -1; cmd = RSTRING_PTR(v_compression); } else { compression = NUM2INT(v_compression); } format = NUM2INT(v_format); return rb_libarchive_writer_s_open0(rb_libarchive_writer_s_open_filename0, (void *) filename, compression, format, cmd); } static int rb_libarchive_writer_s_open_memory0(struct rb_libarchive_archive_container *p, void *arg) { VALUE str = (VALUE) arg; p->memory = str; return archive_write_open_rb_str(p->ar, str); } /* */ static VALUE rb_libarchive_writer_s_open_memory(VALUE self, VALUE v_memory, VALUE v_compression, VALUE v_format) { int compression, format; const char *cmd = NULL; Check_Type(v_memory, T_STRING); if (T_STRING == TYPE(v_compression)) { compression = -1; cmd = RSTRING_PTR(v_compression); } else { compression = NUM2INT(v_compression); } format = NUM2INT(v_format); return rb_libarchive_writer_s_open0(rb_libarchive_writer_s_open_memory0, (void *) v_memory, compression, format, cmd); } /* */ static VALUE rb_libarchive_writer_new_entry(VALUE self) { VALUE entry; struct rb_libarchive_archive_container *p; struct archive_entry *ae; Data_Get_Struct(self, struct rb_libarchive_archive_container, p); Check_Archive(p); if ((ae = archive_entry_new()) == NULL) { rb_raise(rb_eArchiveError, "New entry failed: %s", strerror(errno)); } entry = rb_libarchive_entry_new(ae, 1); if (rb_block_given_p()) { VALUE retval; int status; retval = rb_protect(rb_yield, entry, &status); rb_libarchive_entry_close(entry); if (status != 0) { rb_jump_tag(status); } return retval; } else { return entry; } } /* */ static VALUE rb_libarchive_writer_write_header(VALUE self, VALUE v_entry) { struct rb_libarchive_archive_container *pa; struct rb_libarchive_entry_container *pae; Check_Class(v_entry, rb_cArchiveEntry); Data_Get_Struct(self, struct rb_libarchive_archive_container, pa); Check_Archive(pa); Data_Get_Struct(v_entry, struct rb_libarchive_entry_container, pae); Check_Entry(pae); if (archive_write_header(pa->ar, pae->ae) != ARCHIVE_OK) { rb_raise(rb_eArchiveError, "Write header failed: %s", archive_error_string(pa->ar)); } return Qnil; } static ssize_t rb_libarchive_writer_write_data0(struct archive *ar, VALUE v_buff) { const char *buff; size_t size; ssize_t n; if (NIL_P(v_buff)) { return 0; } Check_Type(v_buff, T_STRING); buff = RSTRING_PTR(v_buff); size = RSTRING_LEN(v_buff); if (size < 1) { return 0; } if ((n = archive_write_data(ar, buff, size)) < 0) { rb_raise(rb_eArchiveError, "Write data failed: %s", archive_error_string(ar)); } return n; } /* */ static VALUE rb_libarchive_writer_write_data(int argc, VALUE *argv, VALUE self) { struct rb_libarchive_archive_container *p; Data_Get_Struct(self, struct rb_libarchive_archive_container, p); Check_Archive(p); if (rb_block_given_p()) { ssize_t len = 0; if (argc > 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } while(1) { VALUE retval; ssize_t n; retval = rb_yield(Qnil); if ((n = rb_libarchive_writer_write_data0(p->ar, retval)) < 1) { return LONG2NUM(len); } len += n; } } else { VALUE v_buff; ssize_t n; rb_scan_args(argc, argv, "10", &v_buff); n = rb_libarchive_writer_write_data0(p->ar, v_buff); return LONG2NUM(n); } } void Init_libarchive_writer() { rb_cArchiveWriter = rb_define_class_under(rb_mArchive, "Writer", rb_cObject); rb_define_alloc_func(rb_cArchiveWriter, rb_libarchive_archive_alloc); rb_funcall(rb_cArchiveWriter, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new"))); rb_define_singleton_method(rb_cArchiveWriter, "open_filename", rb_libarchive_writer_s_open_filename, 3); rb_define_singleton_method(rb_mArchive, "write_open_filename", rb_libarchive_writer_s_open_filename, 3); rb_define_singleton_method(rb_cArchiveWriter, "open_memory", rb_libarchive_writer_s_open_memory, 3); rb_define_singleton_method(rb_mArchive, "write_open_memory", rb_libarchive_writer_s_open_memory, 3); rb_define_method(rb_cArchiveWriter, "close", rb_libarchive_writer_close, 0); rb_define_method(rb_cArchiveWriter, "new_entry", rb_libarchive_writer_new_entry, 0); rb_define_method(rb_cArchiveWriter, "write_header", rb_libarchive_writer_write_header, 1); rb_define_method(rb_cArchiveWriter, "write_data", rb_libarchive_writer_write_data, -1); }