jphastings-unrar 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/unrar.rb +147 -0
  2. metadata +53 -0
@@ -0,0 +1,147 @@
1
+ # = Unrar
2
+ # A pure ruby implementation of unrar.
3
+ # == Features
4
+ # * Allows you to stream data from archives, even if they're not complete
5
+ # * Cross-Platform
6
+ # * No dependencies
7
+ #
8
+ # == Drawbacks
9
+ # * Doesn't yet support compression
10
+ # * Doesn't yet support encryption (though the frame work is in place - does anybody know the spec?)
11
+ # * Doesn't quite support multi-part archives (nearly there tho!)
12
+
13
+ class Unrar
14
+ # Flags (in little endian)
15
+ # Archive flags
16
+ ARCH_VOLUME = 0x0100
17
+ ARCH_LOCKED = 0x0400
18
+ ARCH_IS_SOLID = 0x0800
19
+ ARCH_NEW_NAMES = 0x1000
20
+ ARCH_RECOVERY = 0x4000
21
+ ARCH_ENC_HEAD = 0x8000
22
+ ARCH_FIRST_PART = 0x0001
23
+ # File flags
24
+ FILE_CONTINUED = 0x0100
25
+ FILE_CONTINUES = 0x0200
26
+ FILE_PASSWORDED = 0x0400
27
+ FILE_IS_SOLID = 0x1000
28
+ FILE_HIGH_PACK = 0x0001
29
+ FILE_UNICODED = 0x0002
30
+ FILE_IS_SALTED = 0x0004
31
+ FILE_EXT_TIME = 0x0010
32
+ FILE_MORE_SIZE = 0x0080
33
+ # OSes
34
+ OSes = ['MS DOS','OS/2','Win32','Unix','Mac OS','BeOS']
35
+ # Attributes
36
+ Attr = [:packed_size,:real_size,:os,:filename]
37
+
38
+ # Opens a RAR file and parses the header data
39
+ def initialize(filename)
40
+ @fh = open(File.expand_path(filename),"r")
41
+ @eof = false
42
+ # check marker header
43
+ parse_header
44
+ end
45
+
46
+ # Lists the files in this archive
47
+ def list_contents
48
+ @fh.seek(7)
49
+ parse_header # The archive header
50
+ @files = []
51
+ begin
52
+ while
53
+ file = parse_header(true)
54
+ @files.push file
55
+ # Speed past any data in the file
56
+ @fh.seek(file[:packed_size],IO::SEEK_CUR)
57
+ end
58
+ rescue EOFError
59
+ end
60
+ @files
61
+ end
62
+
63
+ # Gets the file id of the filename given in the archive
64
+ def getid(fname)
65
+ list_contents if @files.nil?
66
+ @files.each_index do |n|
67
+ if @files[n][:filename] == fname
68
+ fid = n
69
+ break
70
+ end
71
+ end
72
+ raise StandardError, "That file does not exist" if (fid >= @files.length) or fid.nil?
73
+ fid
74
+ end
75
+
76
+ # Gets you the data from a given file (by file id). Allows you to specify to start from a specific point (so you can access the contained file from any point for streaming) and how many bytes you want extracted
77
+ def extract(fid,offset = 0,amount = nil)
78
+ list_contents if @files.nil?
79
+ fid = getid(fid) if fid.class != Fixnum
80
+ raise StandardError, "That file does not exist" if fid >= @files.length
81
+ amount = @files[fid][:packed_size] - offset if amount.nil?
82
+ @fh.seek(@files[fid][:datastart] + offset)
83
+ @fh.read(amount)
84
+ end
85
+
86
+ private
87
+ def parse_header(full = false)
88
+ @fh.seek(2,IO::SEEK_CUR) # I don't use the CRC
89
+ details = {}
90
+
91
+ case @fh.readpartial(1)[0]
92
+ when 0x72
93
+ raise StandardError, "Not a valid RAR file" if @fh.readpartial(4).unpack("vv") != [6689,7]
94
+ return true
95
+ when 0x73
96
+ block = :archive
97
+ full = false
98
+ when 0x74
99
+ block = :file
100
+ when 0x7b
101
+ block = :eof
102
+ raise EOFError
103
+ return
104
+ else
105
+ raise NotImplementedError, "The HEAD_TYPE encountered is not one this library supports"
106
+ end
107
+
108
+ details[:blockstart] = @fh.pos - 3
109
+ @flags = @fh.readpartial(2).unpack("v")[0]
110
+ details[:head_size] = @fh.readpartial(2).unpack("v")[0]
111
+ details[:datastart] = details[:blockstart] + details[:head_size]
112
+
113
+ if ((@flags & FILE_MORE_SIZE != 0) or block == :file)
114
+ details[:packed_size] = @fh.readpartial(4).unpack("V")[0]
115
+ if (@flags & FILE_HIGH_PACK != 0)
116
+ # High packing used (over 2Gb size)
117
+ @fh.seek(21,IO::SEEK_CUR)
118
+ details[:packed_size] += @fh.readpartial(4).unpack("V")[0]
119
+ @fh.seek(-25,IO::SEEK_CUR)
120
+ end
121
+ else
122
+ details[:packed_size] = 0
123
+ end
124
+
125
+ if full
126
+ details[:real_size] = @fh.readpartial(4).unpack("V")[0]
127
+ details[:os] = OSes[@fh.readpartial(1).unpack("h")[0].to_i]
128
+ @fh.seek(4,IO::SEEK_CUR) # The file CRC, not used at the moment...
129
+ # DOS date/time
130
+ @fh.readpartial(4).unpack("v").collect{|t| ((t & 0xF800) >> 11) + ((t & 0x07E0) >> 5)*60 + ((t & 0x001F) * 3600)}[0] # - just the time section atm
131
+ @fh.seek(1,IO::SEEK_CUR) # RAR version, ought to check this
132
+ details[:compression_level] = @fh.readpartial(1)[0] - 0x30
133
+ fnamelength = @fh.readpartial(2).unpack("v")[0]
134
+ details[:attributes] = @fh.readpartial(4).unpack("V")[0]
135
+ if (@flags & FILE_HIGH_PACK != 0)
136
+ @fh.seek(4,IO::SEEK_CUR) # We already got the full pack size above
137
+ details[:size] += @fh.readpartial(4).unpack("V")[0] * 0x100000000
138
+ end
139
+ details[:filename] = @fh.readpartial(fnamelength).unpack("a*")[0]
140
+
141
+ end
142
+
143
+ # ff to the end of the header
144
+ @fh.seek(details[:blockstart] + details[:head_size])
145
+ return details if full
146
+ end
147
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jphastings-unrar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - JP Hastings-Spital
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Pure ruby implementation of RarLabs' Unrar software. Doesn't yet support encryption or compression. Written to allow streaming of data from archives.
17
+ email: unrar@projects.kedakai.co.uk
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - unrar.rb
26
+ has_rdoc: true
27
+ homepage: http://projects.kedakai.co.uk/unrar/
28
+ post_install_message:
29
+ rdoc_options: []
30
+
31
+ require_paths:
32
+ - .
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: "0"
38
+ version:
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ requirements: []
46
+
47
+ rubyforge_project:
48
+ rubygems_version: 1.2.0
49
+ signing_key:
50
+ specification_version: 2
51
+ summary: Pure ruby implementation of RarLabs' Unrar software. Doesn't yet support encryption or compression. Written to allow streaming of data from archives.
52
+ test_files: []
53
+