seven_zip_ruby 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee5048a454954a7610658f10e463febaa31ecb93
4
- data.tar.gz: 70cf302be7166790d2af569eb6b4a109d78934bc
3
+ metadata.gz: 576e8ef01f360932073896eb2ada1386f998f644
4
+ data.tar.gz: 1ec0d7e51e795d61062c969126c206025e6734d4
5
5
  SHA512:
6
- metadata.gz: 3d94b6a533f37ddae5ca51d8882289884494b7ed783dee966cf3b5e060d0f7c404096bfd2212dc0d29a32125075acfc4e7a11af82aca33eaf65d178b47b25300
7
- data.tar.gz: 96635e6baac1b98fed6f7321b4cb039abeddc81f2dada7fcdfc6dd053be9c0a3125fe3d47852a4347fda0dee38b303132b81b9083b0b0b9f6ca27f1f417caa78
6
+ metadata.gz: d46d87711429c1cdf191efdf8bed3c0077de239fe7934b8d1fa619f9fcadedd11d026b9b38dfd8a3ecf44af27e85e9be563a8df0432a24cc03939d9308e684be
7
+ data.tar.gz: 4164be8cbd6877ee638369385027c5ac232db25d3c784a11d9a4d80413076f8fedef31fdae86fce7ee5933ad7047ec41d853e504e39729b6a324b5aa198a7d83
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.rbc
2
2
  *.o
3
+ *.obj
3
4
  *.so
4
5
  *.bundle
5
6
  *.bak
data/.travis.yml CHANGED
@@ -1,6 +1,15 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - "2.0.0"
4
+ - "2.1.0"
5
+ - "rbx"
6
+ - "ruby-head"
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: "rbx"
10
+ - rvm: "ruby-head"
11
+ notifications:
12
+ email: false
4
13
  cache:
5
14
  - apt
6
15
  before_install:
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # SevenZipRuby ![Logo](https://raw.github.com/masamitsu-murase/seven_zip_ruby/master/resources/seven_zip_ruby_logo.png)
2
2
 
3
- [![Build Status](https://travis-ci.org/masamitsu-murase/seven_zip_ruby.png?branch=master)](https://travis-ci.org/masamitsu-murase/seven_zip_ruby)
3
+ [![Build Status](https://travis-ci.org/masamitsu-murase/seven_zip_ruby.png?branch=master)](https://travis-ci.org/masamitsu-murase/seven_zip_ruby) [![Gem Version](https://badge.fury.io/rb/seven_zip_ruby.png)](http://badge.fury.io/rb/seven_zip_ruby)
4
4
 
5
- This is a Ruby gem library to handle [7-Zip](http://www.7-zip.org) archives.
5
+ This is a Ruby gem library to extract/compress [7-Zip](http://www.7-zip.org) archives.
6
6
 
7
7
  This extension calls the native library, 7z.dll or 7z.so, internally and it is included in this gem.
8
8
 
@@ -86,12 +86,19 @@ File.open("filename.7z", "wb") do |file|
86
86
  end
87
87
  ```
88
88
 
89
- ## Supported platforms
89
+ ## Supported environment
90
+
91
+ SevenZipRuby supports the following platforms.
90
92
 
91
93
  * Windows
92
94
  * Linux
93
95
  * Mac OSX
94
96
 
97
+ SevenZipRuby supports the following Ruby engines on each platform.
98
+
99
+ * MRI 2.0.0 and later
100
+ * Rubinius 2.2.1 and later
101
+
95
102
  ## More examples
96
103
 
97
104
  ### Extract partially
@@ -180,7 +187,7 @@ LGPL and unRAR license. Please refer to LICENSE.txt.
180
187
 
181
188
  ## Releases
182
189
 
183
- * 1.1.0
190
+ * 1.1.0
184
191
  Raise error when wrong password is specified.
185
192
  * 1.0.0
186
193
  Initial release.
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  require "fileutils"
2
+ require "tempfile"
2
3
  require "bundler/gem_tasks"
3
4
 
4
5
  BINARY_FILES = [ "seven_zip_archive.so", "seven_zip_archive.bundle" ]
@@ -32,7 +33,18 @@ end
32
33
  task :build_binary do
33
34
  Dir.chdir "ext/seven_zip_ruby" do
34
35
  FileUtils.rmtree BINARY_FILES
35
- sh "ruby extconf.rb"
36
+
37
+ Tempfile.open([ "site", ".rb" ], Dir.pwd) do |temp|
38
+ temp.puts <<"EOS"
39
+ require('rbconfig')
40
+ RbConfig::CONFIG['sitearchdir'] = "../../lib"
41
+ EOS
42
+ temp.flush
43
+
44
+ sh "ruby -r#{File.expand_path(temp.path)} extconf.rb"
45
+ temp.unlink
46
+ end
47
+
36
48
  sh "#{MAKE}"
37
49
  end
38
50
  end
@@ -4,6 +4,8 @@ require("mkmf")
4
4
  require("rbconfig")
5
5
 
6
6
 
7
+ SO_TARGET_DIR = File.expand_path(File.join(RbConfig::CONFIG["sitearchdir"], "seven_zip_ruby"))
8
+
7
9
  def create_p7zip_makefile(type)
8
10
  config = RbConfig::CONFIG
9
11
 
@@ -64,7 +66,6 @@ def sample_cpp_source
64
66
  #include <iostream>
65
67
 
66
68
  #include <ruby.h>
67
- #include <ruby/thread.h>
68
69
 
69
70
  void test()
70
71
  {
@@ -87,11 +88,49 @@ void test()
87
88
  EOS
88
89
  end
89
90
 
91
+ def sample_for_rb_thread_call_without_gvl(have_ruby_thread_h)
92
+ header = "#include <ruby.h>\n"
93
+ header += "#include <ruby/thread.h>\n" if (have_ruby_thread_h)
94
+ body = <<'EOS'
95
+
96
+ #include <stdio.h>
97
+
98
+ int main(int argc, char *argv[])
99
+ {
100
+ printf("%p\n", rb_thread_call_without_gvl);
101
+ return 0;
102
+ }
103
+ EOS
104
+ return header + body
105
+ end
106
+
107
+ def sample_for_nullptr
108
+ return <<'EOS'
109
+ #include <stdio.h>
110
+ int main(int argc, char *argv[])
111
+ {
112
+ printf("%p\n", nullptr);
113
+ return 0;
114
+ }
115
+ EOS
116
+ end
117
+
90
118
  def main
119
+ base_flag = ""
120
+
121
+ th_h = have_header("ruby/thread.h")
122
+
123
+ unless (try_compile(sample_for_rb_thread_call_without_gvl(th_h)))
124
+ base_flag += " -DNO_RB_THREAD_CALL_WITHOUT_GVL"
125
+ end
126
+ unless (try_compile(sample_for_nullptr))
127
+ base_flag += " -DNO_NULLPTR"
128
+ end
129
+
91
130
  if (RUBY_PLATFORM.include?("mswin"))
92
131
  # mswin32
93
132
  $LIBS = "oleaut32.lib"
94
- $CPPFLAGS = "/I.. /EHsc /DNDEBUG"
133
+ $CPPFLAGS = "/I.. /EHsc /DNDEBUG /DUSE_WIN32_FILE_API #{base_flag} "
95
134
  elsif (RUBY_PLATFORM.include?("mingw"))
96
135
  # MinGW
97
136
  $LIBS = "-loleaut32 -static-libgcc -static-libstdc++"
@@ -101,14 +140,14 @@ def main
101
140
  end
102
141
  raise "C++11 is not supported by the compiler." unless (cpp0x_flag)
103
142
 
104
- $CPPFLAGS = "-I.. #{cpp0x_flag} -DNDEBUG "
143
+ $CPPFLAGS = "-I.. #{cpp0x_flag} -DNDEBUG -DUSE_WIN32_FILE_API #{base_flag} "
105
144
  else
106
145
  cpp0x_flag = [ "", "-std=c++11", "-std=gnu++11", "-std=c++0x", "-std=gnu++0x" ].find do |opt|
107
146
  next (try_compile(sample_cpp_source, "#{opt} -x c++ ") || try_compile(sample_cpp_source, "#{opt} "))
108
147
  end
109
148
  raise "C++11 is not supported by the compiler." unless (cpp0x_flag)
110
149
 
111
- $CPPFLAGS = "-I.. -I../CPP/include_windows -I../CPP #{cpp0x_flag} -DNDEBUG "
150
+ $CPPFLAGS = "-I.. -I../CPP/include_windows -I../CPP #{cpp0x_flag} -DNDEBUG #{base_flag} "
112
151
 
113
152
 
114
153
  ostype = check_ostype
@@ -119,7 +158,9 @@ def main
119
158
  make_success = system("make 7zso")
120
159
  raise "Failed to make p7zip" unless (make_success)
121
160
 
122
- FileUtils.mv("./bin/7z.so", "../../lib/seven_zip_ruby/7z.so")
161
+ FileUtils.mkpath(SO_TARGET_DIR)
162
+ FileUtils.cp("./bin/7z.so", SO_TARGET_DIR)
163
+
123
164
  system("make clean_7zso")
124
165
  end
125
166
  end
@@ -18,6 +18,8 @@
18
18
  namespace SevenZip
19
19
  {
20
20
 
21
+ using namespace RubyCppUtil;
22
+
21
23
 
22
24
  typedef UINT32 (WINAPI * CreateObjectFunc)(
23
25
  const GUID *clsID,
@@ -38,7 +40,8 @@ ArchiveBase::RubyAction ArchiveBase::ACTION_END = [](){};
38
40
 
39
41
  ArchiveBase::ArchiveBase()
40
42
  : m_action_tuple(nullptr),
41
- m_event_loop_running(false)
43
+ m_event_loop_running(false),
44
+ m_self(Qnil)
42
45
  {
43
46
  m_action_result.clear();
44
47
  }
@@ -47,6 +50,16 @@ ArchiveBase::~ArchiveBase()
47
50
  {
48
51
  }
49
52
 
53
+ void ArchiveBase::setSelf(VALUE self)
54
+ {
55
+ m_self = self;
56
+ }
57
+
58
+ VALUE ArchiveBase::self()
59
+ {
60
+ return m_self;
61
+ }
62
+
50
63
  void ArchiveBase::rubyEventLoop()
51
64
  {
52
65
  m_action_mutex.lock();
@@ -54,7 +67,7 @@ void ArchiveBase::rubyEventLoop()
54
67
  m_action_mutex.unlock();
55
68
 
56
69
  RubyActionTuple end_tuple = std::make_pair(&ACTION_END, false);
57
- RubyActionTuple *action_tuple = nullptr;
70
+ RubyActionTuple * volatile action_tuple = nullptr;
58
71
 
59
72
  bool success = runNativeFuncProtect([&](){
60
73
  MutexLocker locker(&m_action_mutex);
@@ -95,6 +108,12 @@ void ArchiveBase::rubyEventLoop()
95
108
 
96
109
  m_action_mutex.lock();
97
110
  m_event_loop_running = event_loop_running;
111
+ // if (m_action_tuple && m_action_tuple != &end_tuple && m_action_tuple != action_tuple){
112
+ // // Someone overrode m_action_tuple.
113
+ // // It might be killEventLoopThread. Otherwise, it might a bug.
114
+ // // Therefore, terminate event loop for safety.
115
+ // m_event_loop_running = false;
116
+ // }
98
117
  m_action_tuple = nullptr;
99
118
  m_action_cond_var.broadcast();
100
119
  }
@@ -111,6 +130,8 @@ VALUE ArchiveBase::runProtectedRubyAction(VALUE p)
111
130
  VALUE ArchiveBase::staticRubyEventLoop(void *p)
112
131
  {
113
132
  ArchiveBase *self = reinterpret_cast<ArchiveBase*>(p);
133
+ VALUE gc_guard = self->self();
134
+ RB_GC_GUARD(gc_guard);
114
135
  self->rubyEventLoop();
115
136
  return Qnil;
116
137
  }
@@ -125,19 +146,21 @@ void ArchiveBase::startEventLoopThread()
125
146
  rb_thread_create(RUBY_METHOD_FUNC(staticRubyEventLoop), this);
126
147
  }
127
148
 
128
- void ArchiveBase::cancelAction(void *p)
149
+ void ArchiveBase::cancelAction()
129
150
  {
130
- if (!p){
131
- return;
132
- }
133
-
134
- ArchiveBase *self = reinterpret_cast<ArchiveBase*>(p);
135
- self->cancelAction();
151
+ // killEventLoopThread();
152
+ setErrorState();
136
153
  }
137
154
 
138
- void ArchiveBase::cancelAction()
155
+ void ArchiveBase::killEventLoopThread()
139
156
  {
140
- setErrorState();
157
+ MutexLocker locker(&m_action_mutex);
158
+ if (m_event_loop_running){
159
+ static RubyActionTuple end_tuple;
160
+ end_tuple = std::make_pair(&ACTION_END, false);
161
+ m_action_tuple = &end_tuple; // override.
162
+ m_action_cond_var.broadcast();
163
+ }
141
164
  }
142
165
 
143
166
  bool ArchiveBase::runRubyActionImpl(RubyAction *action)
@@ -168,8 +191,10 @@ bool ArchiveBase::runRubyActionImpl(RubyAction *action)
168
191
  return (tuple.second && m_event_loop_running);
169
192
  }
170
193
 
171
- bool ArchiveBase::runRubyAction(RubyAction action)
194
+ template<typename T>
195
+ bool ArchiveBase::runRubyAction(T t)
172
196
  {
197
+ RubyAction action = t;
173
198
  return runRubyActionImpl(&action);
174
199
  }
175
200
 
@@ -180,6 +205,7 @@ void ArchiveBase::finishRubyAction()
180
205
 
181
206
  void ArchiveBase::mark()
182
207
  {
208
+ rb_gc_mark(m_self);
183
209
  m_action_result.mark();
184
210
  }
185
211
 
@@ -199,8 +225,8 @@ void ArchiveBase::terminateEventLoopThread()
199
225
 
200
226
  ////////////////////////////////////////////////////////////////
201
227
  ArchiveReader::ArchiveReader(const GUID &format_guid)
202
- : m_rb_callback_proc(Qnil), m_rb_out_stream(Qnil), m_rb_in_stream(Qnil),
203
- m_processing_index((UInt32)(Int32)-1),
228
+ : m_rb_callback_proc(Qnil), m_rb_out_stream(Qnil),
229
+ m_processing_index((UInt32)(Int32)-1), m_rb_in_stream(Qnil),
204
230
  m_format_guid(format_guid),
205
231
  m_password_specified(false),
206
232
  m_state(STATE_INITIAL)
@@ -258,7 +284,10 @@ VALUE ArchiveReader::open(VALUE in_stream, VALUE param)
258
284
  m_rb_out_stream = Qnil;
259
285
  m_rb_entry_info_list.clear();
260
286
 
261
- VALUE password = rb_hash_aref(param, ID2SYM(INTERN("password")));
287
+ VALUE password;
288
+ runRubyFunction([&](){
289
+ password = rb_hash_aref(param, ID2SYM(INTERN("password")));
290
+ });
262
291
  if (NIL_P(password)){
263
292
  m_password_specified = false;
264
293
  }else{
@@ -365,13 +394,17 @@ VALUE ArchiveReader::getArchiveProperty()
365
394
 
366
395
  checkState(STATE_OPENED, "getArchiveProperty error");
367
396
 
368
- VALUE archive_info = rb_const_get(gSevenZipModule, INTERN("ArchiveInfo"));
369
- ID new_id = INTERN("new");
397
+ VALUE ret;
370
398
  VALUE value_list[size];
371
- for (unsigned int i=0; i<size; i++){
372
- value_list[i] = ConvertPropToValue(variant_list[i]);
373
- }
374
- return rb_funcall2(archive_info, new_id, size, value_list);
399
+ runRubyFunction([&](){
400
+ VALUE archive_info = rb_const_get(gSevenZipModule, INTERN("ArchiveInfo"));
401
+ ID new_id = INTERN("new");
402
+ for (unsigned int i=0; i<size; i++){
403
+ value_list[i] = ConvertPropToValue(variant_list[i]);
404
+ }
405
+ ret = rb_funcall2(archive_info, new_id, size, value_list);
406
+ });
407
+ return ret;
375
408
  }
376
409
 
377
410
  VALUE ArchiveReader::getEntryInfo(VALUE index)
@@ -384,7 +417,10 @@ VALUE ArchiveReader::getEntryInfo(VALUE index)
384
417
 
385
418
  checkState(STATE_OPENED, "getEntryInfo error");
386
419
 
387
- UInt32 idx = NUM2ULONG(index);
420
+ UInt32 idx;
421
+ runRubyFunction([&](){
422
+ idx = NUM2ULONG(index);
423
+ });
388
424
  return entryInfo(idx);
389
425
  }
390
426
 
@@ -407,7 +443,11 @@ VALUE ArchiveReader::getAllEntryInfo()
407
443
 
408
444
  checkState(STATE_OPENED, "getAllEntryInfo error");
409
445
 
410
- return rb_ary_new4(m_rb_entry_info_list.size(), &m_rb_entry_info_list[0]);
446
+ VALUE ret;
447
+ runRubyFunction([&](){
448
+ ret = rb_ary_new4(m_rb_entry_info_list.size(), &m_rb_entry_info_list[0]);
449
+ });
450
+ return ret;
411
451
  }
412
452
 
413
453
  VALUE ArchiveReader::setFileAttribute(VALUE path, VALUE attrib)
@@ -433,7 +473,10 @@ VALUE ArchiveReader::extract(VALUE index, VALUE callback_proc)
433
473
 
434
474
  fillEntryInfo();
435
475
 
436
- UInt32 i = NUM2ULONG(index);
476
+ UInt32 i;
477
+ runRubyFunction([&](){
478
+ i = NUM2ULONG(index);
479
+ });
437
480
  HRESULT ret;
438
481
  runNativeFunc([&](){
439
482
  ArchiveExtractCallback *extract_callback = createArchiveExtractCallback();
@@ -541,35 +584,37 @@ VALUE ArchiveReader::testAll(VALUE detail)
541
584
  }
542
585
 
543
586
  if (RTEST(detail)){
544
- using namespace NArchive::NExtract::NOperationResult;
587
+ VALUE ary;
588
+ runRubyFunction([&](){
589
+ using namespace NArchive::NExtract::NOperationResult;
545
590
 
546
- VALUE unsupportedMethod = ID2SYM(INTERN("UnsupportedMethod"));
547
- VALUE dataError = ID2SYM(INTERN("DataError"));
548
- VALUE crcError = ID2SYM(INTERN("CrcError"));
549
-
550
- VALUE ary = rb_ary_new2(num);
551
- rb_ary_resize(ary, m_test_result.size());
552
- for (unsigned int i=0; i<m_test_result.size(); i++){
553
- VALUE v;
554
- switch(m_test_result[i]){
555
- case kOK:
556
- v = Qtrue;
557
- break;
558
- case kUnSupportedMethod:
559
- v = unsupportedMethod;
560
- break;
561
- case kDataError:
562
- v = dataError;
563
- break;
564
- case kCRCError:
565
- v = crcError;
566
- break;
567
- default:
568
- v = Qnil;
569
- break;
591
+ VALUE unsupportedMethod = ID2SYM(INTERN("UnsupportedMethod"));
592
+ VALUE dataError = ID2SYM(INTERN("DataError"));
593
+ VALUE crcError = ID2SYM(INTERN("CrcError"));
594
+
595
+ ary = rb_ary_new2(num);
596
+ for (unsigned int i=0; i<m_test_result.size(); i++){
597
+ VALUE v;
598
+ switch(m_test_result[i]){
599
+ case kOK:
600
+ v = Qtrue;
601
+ break;
602
+ case kUnSupportedMethod:
603
+ v = unsupportedMethod;
604
+ break;
605
+ case kDataError:
606
+ v = dataError;
607
+ break;
608
+ case kCRCError:
609
+ v = crcError;
610
+ break;
611
+ default:
612
+ v = Qnil;
613
+ break;
614
+ }
615
+ rb_ary_store(ary, (long)i, v);
570
616
  }
571
- RARRAY_PTR(ary)[i] = v;
572
- }
617
+ });
573
618
  return ary;
574
619
  }else{
575
620
  using namespace NArchive::NExtract::NOperationResult;
@@ -643,17 +688,19 @@ void ArchiveReader::fillEntryInfo()
643
688
  throw RubyCppUtil::RubyException("Cannot get property of items");
644
689
  }
645
690
 
646
- VALUE entry_info = rb_const_get(gSevenZipModule, INTERN("EntryInfo"));
647
- ID new_id = INTERN("new");
648
691
  m_rb_entry_info_list.resize(variant_list.size(), Qnil);
649
- for (UInt32 i=0; i<m_rb_entry_info_list.size(); i++){
650
- VALUE value_list[size + 1];
651
- value_list[0] = ULONG2NUM(i);
652
- for (unsigned int j=0; j<size; j++){
653
- value_list[j+1] = ConvertPropToValue(variant_list[i][j]);
692
+ VALUE value_list[size + 1];
693
+ runRubyFunction([&](){
694
+ VALUE entry_info = rb_const_get(gSevenZipModule, INTERN("EntryInfo"));
695
+ ID new_id = INTERN("new");
696
+ for (UInt32 i=0; i<m_rb_entry_info_list.size(); i++){
697
+ value_list[0] = ULONG2NUM(i);
698
+ for (unsigned int j=0; j<size; j++){
699
+ value_list[j+1] = ConvertPropToValue(variant_list[i][j]);
700
+ }
701
+ m_rb_entry_info_list[i] = rb_funcall2(entry_info, new_id, size + 1, value_list);
654
702
  }
655
- m_rb_entry_info_list[i] = rb_funcall2(entry_info, new_id, size + 1, value_list);
656
- }
703
+ });
657
704
  }
658
705
 
659
706
  void ArchiveReader::mark()
@@ -728,7 +775,10 @@ VALUE ArchiveWriter::open(VALUE out_stream, VALUE param)
728
775
  m_rb_in_stream = Qnil;
729
776
  std::vector<VALUE>().swap(m_rb_update_list);
730
777
 
731
- VALUE password = rb_hash_aref(param, ID2SYM(INTERN("password")));
778
+ VALUE password;
779
+ runRubyFunction([&](){
780
+ password = rb_hash_aref(param, ID2SYM(INTERN("password")));
781
+ });
732
782
  if (NIL_P(password)){
733
783
  m_password_specified = false;
734
784
  }else{
@@ -999,7 +1049,7 @@ VALUE SevenZipWriter::method()
999
1049
 
1000
1050
  VALUE SevenZipWriter::setLevel(VALUE level)
1001
1051
  {
1002
- level = rb_check_to_int(level);
1052
+ level = rb_check_to_integer(level, "to_int");
1003
1053
  if (NIL_P(level)){
1004
1054
  throw RubyCppUtil::RubyException(rb_exc_new2(rb_eArgError, "level should be Integer"));
1005
1055
  }
@@ -1094,11 +1144,19 @@ ArchiveOpenCallback::ArchiveOpenCallback(ArchiveReader *archive, const std::stri
1094
1144
 
1095
1145
  STDMETHODIMP ArchiveOpenCallback::SetTotal(const UInt64 *files, const UInt64 *bytes)
1096
1146
  {
1147
+ // This function is called periodically, so use this function as a check function of interrupt.
1148
+ if (m_archive->isErrorState()){
1149
+ return E_ABORT;
1150
+ }
1097
1151
  return S_OK;
1098
1152
  }
1099
1153
 
1100
1154
  STDMETHODIMP ArchiveOpenCallback::SetCompleted(const UInt64 *files, const UInt64 *bytes)
1101
1155
  {
1156
+ // This function is called periodically, so use this function as a check function of interrupt.
1157
+ if (m_archive->isErrorState()){
1158
+ return E_ABORT;
1159
+ }
1102
1160
  return S_OK;
1103
1161
  }
1104
1162
 
@@ -1128,6 +1186,10 @@ ArchiveExtractCallback::ArchiveExtractCallback(ArchiveReader *archive, const std
1128
1186
 
1129
1187
  STDMETHODIMP ArchiveExtractCallback::SetTotal(UInt64 size)
1130
1188
  {
1189
+ // This function is called periodically, so use this function as a check function of interrupt.
1190
+ if (m_archive->isErrorState()){
1191
+ return E_ABORT;
1192
+ }
1131
1193
  return S_OK;
1132
1194
  }
1133
1195
 
@@ -1135,7 +1197,7 @@ STDMETHODIMP ArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
1135
1197
  {
1136
1198
  // This function is called periodically, so use this function as a check function of interrupt.
1137
1199
  if (m_archive->isErrorState()){
1138
- return E_FAIL;
1200
+ return E_ABORT;
1139
1201
  }
1140
1202
  return S_OK;
1141
1203
  }
@@ -1243,13 +1305,18 @@ ArchiveUpdateCallback::ArchiveUpdateCallback(ArchiveWriter *archive, const std::
1243
1305
 
1244
1306
  STDMETHODIMP ArchiveUpdateCallback::SetTotal(UInt64 size)
1245
1307
  {
1308
+ // This function is called periodically, so use this function as a check function of interrupt.
1309
+ if (m_archive->isErrorState()){
1310
+ return E_ABORT;
1311
+ }
1246
1312
  return S_OK;
1247
1313
  }
1248
1314
 
1249
1315
  STDMETHODIMP ArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
1250
1316
  {
1317
+ // This function is called periodically, so use this function as a check function of interrupt.
1251
1318
  if (m_archive->isErrorState()){
1252
- return E_FAIL;
1319
+ return E_ABORT;
1253
1320
  }
1254
1321
  return S_OK;
1255
1322
  }
@@ -1338,6 +1405,9 @@ STDMETHODIMP ArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PRO
1338
1405
  break;
1339
1406
  }
1340
1407
  });
1408
+ if (!ret){
1409
+ return E_FAIL;
1410
+ }
1341
1411
 
1342
1412
  return S_OK;
1343
1413
  }
@@ -1345,10 +1415,25 @@ STDMETHODIMP ArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PRO
1345
1415
  STDMETHODIMP ArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
1346
1416
  {
1347
1417
  VALUE rb_stream;
1418
+ std::string filepath;
1348
1419
  VALUE proc = m_archive->callbackProc();
1349
1420
  bool ret = m_archive->runRubyAction([&](){
1350
1421
  VALUE info = m_archive->itemInfo(index);
1351
- rb_stream = rb_funcall(proc, INTERN("call"), 2, ID2SYM(INTERN("stream")), info);
1422
+ VALUE ret_array = rb_funcall(proc, INTERN("call"), 2, ID2SYM(INTERN("stream")), info);
1423
+ if (NIL_P(ret_array)){
1424
+ rb_stream = Qnil;
1425
+ return;
1426
+ }
1427
+
1428
+ // ret_array[0]: true: filepath
1429
+ // false: io
1430
+ if (RTEST(rb_ary_entry(ret_array, 0))){
1431
+ rb_stream = Qnil;
1432
+ VALUE path = rb_ary_entry(ret_array, 1);
1433
+ filepath = std::string(RSTRING_PTR(path), RSTRING_LEN(path));
1434
+ }else{
1435
+ rb_stream = rb_ary_entry(ret_array, 1);
1436
+ }
1352
1437
  });
1353
1438
  if (!ret){
1354
1439
  m_archive->clearProcessingStream();
@@ -1357,9 +1442,15 @@ STDMETHODIMP ArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream
1357
1442
 
1358
1443
  m_archive->setProcessingStream(rb_stream, index);
1359
1444
 
1360
- InStream *stream = new InStream(rb_stream, m_archive);
1361
- CMyComPtr<InStream> ptr(stream);
1362
- *inStream = ptr.Detach();
1445
+ if (NIL_P(rb_stream) && !(filepath.empty())){
1446
+ FileInStream *stream = new FileInStream(filepath, m_archive);
1447
+ CMyComPtr<FileInStream> ptr(stream);
1448
+ *inStream = ptr.Detach();
1449
+ }else{
1450
+ InStream *stream = new InStream(rb_stream, m_archive);
1451
+ CMyComPtr<InStream> ptr(stream);
1452
+ *inStream = ptr.Detach();
1453
+ }
1363
1454
 
1364
1455
  return S_OK;
1365
1456
  }
@@ -1449,11 +1540,138 @@ STDMETHODIMP InStream::Read(void *data, UInt32 size, UInt32 *processedSize)
1449
1540
  *processedSize = (NIL_P(str) ? 0 : RSTRING_LEN(str));
1450
1541
  }
1451
1542
  });
1543
+ if (!ret){
1544
+ if (processedSize){
1545
+ *processedSize = 0;
1546
+ }
1547
+ return E_FAIL;
1548
+ }
1549
+
1550
+ return S_OK;
1551
+ }
1552
+
1553
+ ////////////////////////////////////////////////////////////////
1554
+ FileInStream::FileInStream(const std::string &filename, ArchiveBase *archive)
1555
+ : m_archive(archive)
1556
+ #ifdef USE_WIN32_FILE_API
1557
+ , m_file_handle(INVALID_HANDLE_VALUE)
1558
+ #else
1559
+ , m_file(filename.c_str(), std::ios::binary)
1560
+ #endif
1561
+ {
1562
+ #ifdef USE_WIN32_FILE_API
1563
+ BSTR name = ConvertStringToBstr(filename);
1564
+ m_file_handle = CreateFileW(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
1565
+ FILE_ATTRIBUTE_NORMAL, NULL);
1566
+ SysFreeString(name);
1567
+ #else
1568
+ // Nothing to do
1569
+ #endif
1570
+ }
1571
+
1572
+ FileInStream::~FileInStream()
1573
+ {
1574
+ #ifdef USE_WIN32_FILE_API
1575
+ if (m_file_handle == INVALID_HANDLE_VALUE){
1576
+ return;
1577
+ }
1578
+
1579
+ CloseHandle(m_file_handle);
1580
+ m_file_handle = INVALID_HANDLE_VALUE;
1581
+ #else
1582
+ // Nothing to do
1583
+ #endif
1584
+ }
1585
+
1586
+ STDMETHODIMP FileInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
1587
+ {
1588
+ #ifdef USE_WIN32_FILE_API
1589
+ if (m_file_handle == INVALID_HANDLE_VALUE){
1590
+ return E_FAIL;
1591
+ }
1592
+
1593
+ DWORD method;
1594
+ switch(seekOrigin){
1595
+ case 0:
1596
+ method = FILE_BEGIN;
1597
+ break;
1598
+ case 1:
1599
+ method = FILE_CURRENT;
1600
+ break;
1601
+ case 2:
1602
+ method = FILE_END;
1603
+ break;
1604
+ default:
1605
+ return E_FAIL;
1606
+ }
1607
+
1608
+ DWORD low, high;
1609
+ low = (DWORD)(offset & 0xFFFFFFFFUL);
1610
+ high = (DWORD)((offset >> 32) & 0xFFFFFFFFUL);
1611
+ DWORD new_low = SetFilePointer(m_file_handle, (LONG)low, (PLONG)&high, method);
1612
+
1613
+ if (newPosition){
1614
+ *newPosition = (((UInt64)high) << 32) + ((UInt64)new_low);
1615
+ }
1616
+ return S_OK;
1617
+ #else
1618
+ if (!m_file.is_open()){
1619
+ return E_FAIL;
1620
+ }
1621
+
1622
+ std::ios::seekdir method;
1623
+ switch(seekOrigin){
1624
+ case 0:
1625
+ method = std::ios::beg;
1626
+ break;
1627
+ case 1:
1628
+ method = std::ios::cur;
1629
+ break;
1630
+ case 2:
1631
+ method = std::ios::end;
1632
+ break;
1633
+ default:
1634
+ return E_FAIL;
1635
+ }
1636
+
1637
+ std::streamoff sto = offset;
1638
+ m_file.seekg(sto, method);
1639
+ if (newPosition){
1640
+ *newPosition = m_file.tellg();
1641
+ }
1642
+ return S_OK;
1643
+ #endif
1644
+ }
1645
+
1646
+ STDMETHODIMP FileInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
1647
+ {
1648
+ #ifdef USE_WIN32_FILE_API
1649
+ if (m_file_handle == INVALID_HANDLE_VALUE){
1650
+ return E_FAIL;
1651
+ }
1652
+
1653
+ DWORD processed_size;
1654
+ BOOL ret = ReadFile(m_file_handle, data, size, &processed_size, NULL);
1452
1655
  if (!ret){
1453
1656
  return E_FAIL;
1454
1657
  }
1455
1658
 
1659
+ if (processedSize){
1660
+ *processedSize = processed_size;
1661
+ }
1662
+
1456
1663
  return S_OK;
1664
+ #else
1665
+ if (!m_file.is_open()){
1666
+ return E_FAIL;
1667
+ }
1668
+
1669
+ m_file.read(reinterpret_cast<char*>(data), size);
1670
+ if (processedSize){
1671
+ *processedSize = m_file.gcount();
1672
+ }
1673
+ return S_OK;
1674
+ #endif
1457
1675
  }
1458
1676
 
1459
1677
  ////////////////////////////////////////////////////////////////
@@ -1476,6 +1694,16 @@ STDMETHODIMP OutStream::Write(const void *data, UInt32 size, UInt32 *processedSi
1476
1694
  }
1477
1695
  });
1478
1696
  if (!ret){
1697
+ if (processedSize){
1698
+ *processedSize = 0;
1699
+ }
1700
+ // When killEventLoopThread is called in cancelAction
1701
+ // return S_OK even if error occurs.
1702
+ //
1703
+ // Detail:
1704
+ // It seems that BZip2Encoder has a bug.
1705
+ // If Write method returns E_FAIL, some Events are not set in that file
1706
+ // because OutBuffer throws an exception in Encoder->WriteBytes.
1479
1707
  return E_FAIL;
1480
1708
  }
1481
1709
 
@@ -1570,7 +1798,7 @@ extern "C" void Init_seven_zip_archive(void)
1570
1798
 
1571
1799
  cls = rb_define_wrapped_cpp_class_under<SevenZipReader>(mod, "SevenZipReader", rb_cObject);
1572
1800
  rb_define_method_ext(cls, "open_impl", READER_FUNC(open, 2));
1573
- rb_define_method_ext(cls, "close", READER_FUNC(close, 0));
1801
+ rb_define_method_ext(cls, "close_impl", READER_FUNC(close, 0));
1574
1802
  rb_define_method_ext(cls, "entry_num", READER_FUNC(entryNum, 0));
1575
1803
  rb_define_method_ext(cls, "extract_impl", READER_FUNC(extract, 2));
1576
1804
  rb_define_method_ext(cls, "extract_files_impl", READER_FUNC(extractFiles, 2));
@@ -1593,7 +1821,7 @@ extern "C" void Init_seven_zip_archive(void)
1593
1821
  rb_define_method_ext(cls, "open_impl", WRITER_FUNC(open, 2));
1594
1822
  rb_define_method_ext(cls, "add_item", WRITER_FUNC(addItem, 1));
1595
1823
  rb_define_method_ext(cls, "compress_impl", WRITER_FUNC(compress, 1));
1596
- rb_define_method_ext(cls, "close", WRITER_FUNC(close, 0));
1824
+ rb_define_method_ext(cls, "close_impl", WRITER_FUNC(close, 0));
1597
1825
  rb_define_method_ext(cls, "get_file_attribute", WRITER_FUNC(getFileAttribute, 1));
1598
1826
 
1599
1827
  rb_define_method_ext(cls, "method=", WRITER_FUNC2(setMethod, 1));