seven_zip_ruby 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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));