1
1
# encoding: ASCII-8BIT
2
2
require 'delegate'
3
- require 'iconv'
3
+
4
+ begin
5
+ require 'iconv'
6
+ rescue ::LoadError
7
+ end
8
+
4
9
require 'singleton'
5
10
require 'tempfile'
6
11
require 'fileutils'
@@ -140,15 +145,13 @@ def eof
140
145
def open_entry
141
146
@currentEntry = ZipEntry . read_local_entry ( @archiveIO )
142
147
if ( @currentEntry == nil )
143
- @decompressor = NullDecompressor . instance
148
+ @decompressor = NullDecompressor . instance
144
149
elsif @currentEntry . compression_method == ZipEntry ::STORED
145
- @decompressor = PassThruDecompressor . new ( @archiveIO ,
146
- @currentEntry . size )
150
+ @decompressor = PassThruDecompressor . new ( @archiveIO , @currentEntry . size )
147
151
elsif @currentEntry . compression_method == ZipEntry ::DEFLATED
148
- @decompressor = Inflater . new ( @archiveIO )
152
+ @decompressor = Inflater . new ( @archiveIO )
149
153
else
150
- raise ZipCompressionMethodError ,
151
- "Unsupported compression method #{ @currentEntry . compression_method } "
154
+ raise ZipCompressionMethodError , "Unsupported compression method #{ @currentEntry . compression_method } "
152
155
end
153
156
flush
154
157
return @currentEntry
@@ -184,8 +187,8 @@ def initialize(inputStream)
184
187
def sysread ( numberOfBytes = nil , buf = nil )
185
188
readEverything = ( numberOfBytes == nil )
186
189
while ( readEverything || @outputBuffer . length < numberOfBytes )
187
- break if internal_input_finished?
188
- @outputBuffer << internal_produce_input ( buf )
190
+ break if internal_input_finished?
191
+ @outputBuffer << internal_produce_input ( buf )
189
192
end
190
193
return value_when_finished if @outputBuffer . length ==0 && input_finished?
191
194
endIndex = numberOfBytes ==nil ? @outputBuffer . length : numberOfBytes
@@ -194,9 +197,9 @@ def sysread(numberOfBytes = nil, buf = nil)
194
197
195
198
def produce_input
196
199
if ( @outputBuffer . empty? )
197
- return internal_produce_input
200
+ return internal_produce_input
198
201
else
199
- return @outputBuffer . slice! ( 0 ...( @outputBuffer . length ) )
202
+ return @outputBuffer . slice! ( 0 ...( @outputBuffer . length ) )
200
203
end
201
204
end
202
205
@@ -244,14 +247,14 @@ def initialize(inputStream, charsToRead)
244
247
# TODO: Specialize to handle different behaviour in ruby > 1.7.0 ?
245
248
def sysread ( numberOfBytes = nil , buf = nil )
246
249
if input_finished?
247
- hasReturnedEmptyStringVal = @hasReturnedEmptyString
248
- @hasReturnedEmptyString = true
249
- return "" unless hasReturnedEmptyStringVal
250
- return nil
250
+ hasReturnedEmptyStringVal = @hasReturnedEmptyString
251
+ @hasReturnedEmptyString = true
252
+ return "" unless hasReturnedEmptyStringVal
253
+ return nil
251
254
end
252
255
253
256
if ( numberOfBytes == nil || @readSoFar +numberOfBytes > @charsToRead )
254
- numberOfBytes = @charsToRead -@readSoFar
257
+ numberOfBytes = @charsToRead -@readSoFar
255
258
end
256
259
@readSoFar += numberOfBytes
257
260
@inputStream . read ( numberOfBytes , buf )
@@ -356,14 +359,28 @@ def name_encoding
356
359
( @gp_flags & 0b100000000000 ) != 0 ? "utf8" : "CP437//"
357
360
end
358
361
362
+
363
+ # Converts string encoding
364
+ def encode_string ( str , src , dst )
365
+ if str . respond_to? ( :encode )
366
+ str . encode ( dst , { :invalid => :replace , :undef => :replace , :replace => '' } )
367
+ else
368
+ begin
369
+ Iconv . conv ( dst , src , str )
370
+ rescue
371
+ raise ::RuntimeError , "Your installation does not support iconv (needed for utf8 conversion)"
372
+ end
373
+ end
374
+ end
375
+
359
376
# Returns the name in the encoding specified by enc
360
377
def name_in ( enc )
361
- Iconv . conv ( enc , name_encoding , @name )
378
+ encode_string ( @name , name_encoding , enc )
362
379
end
363
380
364
- # Returns the name in the encoding specified by enc
381
+ # Returns the comment in the encoding specified by enc
365
382
def comment_in ( enc )
366
- Iconv . conv ( enc , name_encoding , @name )
383
+ encode_string ( @comment , name_encoding , enc )
367
384
end
368
385
369
386
def initialize ( zipfile = "" , name = "" , comment = "" , extra = "" ,
@@ -372,7 +389,7 @@ def initialize(zipfile = "", name = "", comment = "", extra = "",
372
389
time = Time . now )
373
390
super ( )
374
391
if name . starts_with ( "/" )
375
- raise ZipEntryNameError , "Illegal ZipEntry name '#{ name } ', name must not start with /"
392
+ raise ZipEntryNameError , "Illegal ZipEntry name '#{ name } ', name must not start with /"
376
393
end
377
394
@localHeaderOffset = 0
378
395
@local_header_size = 0
@@ -484,9 +501,9 @@ def extract(destPath = @name, &onExistsProc)
484
501
onExistsProc ||= proc { false }
485
502
486
503
if directory?
487
- create_directory ( destPath , &onExistsProc )
504
+ create_directory ( destPath , &onExistsProc )
488
505
elsif file?
489
- write_file ( destPath , &onExistsProc )
506
+ write_file ( destPath , &onExistsProc )
490
507
elsif symlink?
491
508
create_symlink ( destPath , &onExistsProc )
492
509
else
@@ -520,24 +537,24 @@ def read_local_entry(io) #:nodoc:all
520
537
@localHeaderOffset = io . tell
521
538
staticSizedFieldsBuf = io . read ( LOCAL_ENTRY_STATIC_HEADER_LENGTH )
522
539
unless ( staticSizedFieldsBuf . size ==LOCAL_ENTRY_STATIC_HEADER_LENGTH )
523
- raise ZipError , "Premature end of file. Not enough data for zip entry local header"
540
+ raise ZipError , "Premature end of file. Not enough data for zip entry local header"
524
541
end
525
542
526
543
@header_signature ,
527
- @version ,
528
- @fstype ,
529
- @gp_flags ,
530
- @compression_method ,
531
- lastModTime ,
532
- lastModDate ,
533
- @crc ,
534
- @compressed_size ,
535
- @size ,
536
- nameLength ,
537
- extraLength = staticSizedFieldsBuf . unpack ( 'VCCvvvvVVVvv' )
544
+ @version ,
545
+ @fstype ,
546
+ @gp_flags ,
547
+ @compression_method ,
548
+ lastModTime ,
549
+ lastModDate ,
550
+ @crc ,
551
+ @compressed_size ,
552
+ @size ,
553
+ nameLength ,
554
+ extraLength = staticSizedFieldsBuf . unpack ( 'VCCvvvvVVVvv' )
538
555
539
556
unless ( @header_signature == LOCAL_ENTRY_SIGNATURE )
540
- raise ZipError , "Zip local header magic not found at location '#{ localHeaderOffset } '"
557
+ raise ZipError , "Zip local header magic not found at location '#{ localHeaderOffset } '"
541
558
end
542
559
set_time ( lastModDate , lastModTime )
543
560
@@ -546,7 +563,7 @@ def read_local_entry(io) #:nodoc:all
546
563
extra = io . read ( extraLength )
547
564
548
565
if ( extra && extra . length != extraLength )
549
- raise ZipError , "Truncated local zip entry header"
566
+ raise ZipError , "Truncated local zip entry header"
550
567
else
551
568
if ZipExtraField === @extra
552
569
@extra . merge ( extra )
@@ -569,17 +586,17 @@ def write_local_entry(io) #:nodoc:all
569
586
@localHeaderOffset = io . tell
570
587
571
588
io <<
572
- [ LOCAL_ENTRY_SIGNATURE ,
573
- VERSION_NEEDED_TO_EXTRACT , # version needed to extract
574
- 0 , # @gp_flags ,
575
- @compression_method ,
576
- @time . to_binary_dos_time , # @lastModTime ,
577
- @time . to_binary_dos_date , # @lastModDate ,
578
- @crc ,
579
- @compressed_size ,
580
- @size ,
581
- @name ? @name . length : 0 ,
582
- @extra ? @extra . local_length : 0 ] . pack ( 'VvvvvvVVVvv' )
589
+ [ LOCAL_ENTRY_SIGNATURE ,
590
+ VERSION_NEEDED_TO_EXTRACT , # version needed to extract
591
+ 0 , # @gp_flags ,
592
+ @compression_method ,
593
+ @time . to_binary_dos_time , # @lastModTime ,
594
+ @time . to_binary_dos_date , # @lastModDate ,
595
+ @crc ,
596
+ @compressed_size ,
597
+ @size ,
598
+ @name ? @name . length : 0 ,
599
+ @extra ? @extra . local_length : 0 ] . pack ( 'VvvvvvVVVvv' )
583
600
io << @name
584
601
io << ( @extra ? @extra . to_local_bin : "" )
585
602
end
@@ -590,33 +607,33 @@ def write_local_entry(io) #:nodoc:all
590
607
def read_c_dir_entry ( io ) #:nodoc:all
591
608
staticSizedFieldsBuf = io . read ( CDIR_ENTRY_STATIC_HEADER_LENGTH )
592
609
unless ( staticSizedFieldsBuf . size == CDIR_ENTRY_STATIC_HEADER_LENGTH )
593
- raise ZipError , "Premature end of file. Not enough data for zip cdir entry header"
610
+ raise ZipError , "Premature end of file. Not enough data for zip cdir entry header"
594
611
end
595
612
596
613
@header_signature ,
597
- @version , # version of encoding software
598
- @fstype , # filesystem type
599
- @versionNeededToExtract ,
600
- @gp_flags ,
601
- @compression_method ,
602
- lastModTime ,
603
- lastModDate ,
604
- @crc ,
605
- @compressed_size ,
606
- @size ,
607
- nameLength ,
608
- extraLength ,
609
- commentLength ,
610
- diskNumberStart ,
611
- @internalFileAttributes ,
612
- @externalFileAttributes ,
613
- @localHeaderOffset ,
614
- @name ,
615
- @extra ,
616
- @comment = staticSizedFieldsBuf . unpack ( 'VCCvvvvvVVVvvvvvVV' )
614
+ @version , # version of encoding software
615
+ @fstype , # filesystem type
616
+ @versionNeededToExtract ,
617
+ @gp_flags ,
618
+ @compression_method ,
619
+ lastModTime ,
620
+ lastModDate ,
621
+ @crc ,
622
+ @compressed_size ,
623
+ @size ,
624
+ nameLength ,
625
+ extraLength ,
626
+ commentLength ,
627
+ diskNumberStart ,
628
+ @internalFileAttributes ,
629
+ @externalFileAttributes ,
630
+ @localHeaderOffset ,
631
+ @name ,
632
+ @extra ,
633
+ @comment = staticSizedFieldsBuf . unpack ( 'VCCvvvvvVVVvvvvvVV' )
617
634
618
635
unless ( @header_signature == CENTRAL_DIRECTORY_ENTRY_SIGNATURE )
619
- raise ZipError , "Zip local header magic not found at location '#{ localHeaderOffset } '"
636
+ raise ZipError , "Zip local header magic not found at location '#{ localHeaderOffset } '"
620
637
end
621
638
set_time ( lastModDate , lastModTime )
622
639
@@ -628,7 +645,7 @@ def read_c_dir_entry(io) #:nodoc:all
628
645
end
629
646
@comment = io . read ( commentLength )
630
647
unless ( @comment && @comment . length == commentLength )
631
- raise ZipError , "Truncated cdir zip entry header"
648
+ raise ZipError , "Truncated cdir zip entry header"
632
649
end
633
650
634
651
case @fstype
0 commit comments