ffi-chm 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +2 -0
- data/lib/ffi-chm.rb +1 -1
- data/lib/ffi-chm/chm_file.rb +3 -3
- data/lib/ffi-chm/chm_file/aux.rb +103 -3
- data/lib/ffi-chm/com8ble.rb +3 -0
- data/lib/ffi-chm/struct.rb +6 -0
- data/lib/ffi-chm/struct/encint.rb +11 -0
- data/lib/ffi-chm/struct/fulltext_index.rb +84 -0
- data/lib/ffi-chm/struct/fulltext_index/index.rb +16 -0
- data/lib/ffi-chm/struct/fulltext_index/index/index_record.rb +11 -0
- data/lib/ffi-chm/struct/fulltext_index/leaf.rb +17 -0
- data/lib/ffi-chm/struct/fulltext_index/leaf/leaf_record.rb +16 -0
- data/lib/ffi-chm/struct/hhx_document.rb +1 -1
- data/lib/ffi-chm/struct/sr.rb +30 -0
- data/lib/ffi-chm/struct/system.rb +11 -8
- data/lib/ffi-chm/struct/system/{record.rb → system_record.rb} +1 -1
- data/lib/ffi-chm/struct/topics.rb +27 -0
- data/lib/ffi-chm/struct/topics/topics_record.rb +24 -0
- data/lib/ffi-chm/struct/url_string.rb +7 -0
- data/lib/ffi-chm/struct/url_table.rb +6 -0
- data/lib/ffi-chm/struct/url_table/url_table_block.rb +8 -0
- data/lib/ffi-chm/struct/url_table/url_table_record.rb +9 -0
- data/lib/ffi-chm/struct/wlc.rb +16 -0
- data/test/test_sr.rb +54 -0
- metadata +28 -12
data/README.txt
CHANGED
@@ -10,6 +10,7 @@ Ruby bindings for the libchm via FFI.
|
|
10
10
|
|
11
11
|
* Provides basic access to the CHM files.
|
12
12
|
* Some functionalities to access to internal structure.
|
13
|
+
* Fulltext search.
|
13
14
|
* Currently developed on MRI 1.8.7 / 1.9.2
|
14
15
|
|
15
16
|
== SYNOPSIS:
|
@@ -25,6 +26,7 @@ Ruby bindings for the libchm via FFI.
|
|
25
26
|
* Ruby
|
26
27
|
* libffi
|
27
28
|
* libchm
|
29
|
+
* Nokogiri >= 1.5.0
|
28
30
|
|
29
31
|
== INSTALL:
|
30
32
|
|
data/lib/ffi-chm.rb
CHANGED
data/lib/ffi-chm/chm_file.rb
CHANGED
@@ -47,6 +47,7 @@ module FFI::Chm
|
|
47
47
|
if UnitInfo === ui
|
48
48
|
buf = FFI::Buffer.new ui[:length]
|
49
49
|
API.chm_retrieve_object @h, ui, buf, 0, ui[:length]
|
50
|
+
# use read_string for JRuby
|
50
51
|
buf.read_bytes buf.size
|
51
52
|
else
|
52
53
|
retrieve_object resolve_object(ui)
|
@@ -55,13 +56,12 @@ module FFI::Chm
|
|
55
56
|
raise RetrieveError, ui
|
56
57
|
end
|
57
58
|
|
58
|
-
require 'enumerator'
|
59
59
|
def enumerate(*what, &block)
|
60
60
|
if block_given?
|
61
61
|
API.chm_enumerate @h, to_flags(what), enum_func(&block), nil
|
62
62
|
self
|
63
63
|
else
|
64
|
-
|
64
|
+
Com8ble::Enumerator.new self, :enumerate, to_flags(what)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -70,7 +70,7 @@ module FFI::Chm
|
|
70
70
|
API.chm_enumerate_dir @h, prefix, to_flags(what), enum_func(&block), nil
|
71
71
|
self
|
72
72
|
else
|
73
|
-
|
73
|
+
Com8ble::Enumerator.new self, :enumerate_dir, prefix, to_flags(what)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
data/lib/ffi-chm/chm_file/aux.rb
CHANGED
@@ -4,8 +4,16 @@ require 'ffi-chm/com8ble'
|
|
4
4
|
module FFI::Chm::ChmFile::Aux
|
5
5
|
include FFI::Chm
|
6
6
|
|
7
|
+
# /#SYSTEM
|
7
8
|
def system
|
8
|
-
@system ||= Struct::System.new.read
|
9
|
+
@system ||= Struct::System.new.read retrieve_object("/#SYSTEM")
|
10
|
+
end
|
11
|
+
|
12
|
+
# /#TOPICS
|
13
|
+
def topics
|
14
|
+
@topics ||= Struct::Topics.new.read retrieve_object("/#TOPICS")
|
15
|
+
@topics.set_context self
|
16
|
+
@topics
|
9
17
|
end
|
10
18
|
|
11
19
|
def encoding
|
@@ -18,7 +26,7 @@ module FFI::Chm::ChmFile::Aux
|
|
18
26
|
|
19
27
|
def contents(cache=true)
|
20
28
|
return @contents if @contents
|
21
|
-
xml =
|
29
|
+
xml = retrieve_object("/#{self.system.record(6).data.compiled_file}.hhc").com8ble.force_encoding(encoding).encode("UTF-8")
|
22
30
|
doc = Struct::HHXDocument.new(Struct::HHC::Entry)
|
23
31
|
Nokogiri::HTML::SAX::Parser.new(doc).parse(xml)
|
24
32
|
|
@@ -29,11 +37,103 @@ module FFI::Chm::ChmFile::Aux
|
|
29
37
|
|
30
38
|
def index(cache=true)
|
31
39
|
return @index if @index
|
32
|
-
xml =
|
40
|
+
xml = retrieve_object("/#{self.system.record(6).data.compiled_file}.hhk").com8ble.force_encoding(encoding).encode("UTF-8")
|
33
41
|
doc = Struct::HHXDocument.new(Struct::HHK::Entry)
|
34
42
|
Nokogiri::HTML::SAX::Parser.new(doc).parse(xml)
|
35
43
|
doc.root.flatten.tap do |v|
|
36
44
|
@index = v if cache
|
37
45
|
end
|
38
46
|
end
|
47
|
+
|
48
|
+
# /$FIftiMain
|
49
|
+
def fulltext_index
|
50
|
+
@fulltext_index ||= Struct::FulltextIndex.new.read retrieve_object("/$FIftiMain")
|
51
|
+
end
|
52
|
+
|
53
|
+
# /#STRINGS
|
54
|
+
def string(offset)
|
55
|
+
@string ||= {}
|
56
|
+
if @string.has_key? offset
|
57
|
+
@string[offset]
|
58
|
+
else
|
59
|
+
io = StringIO.new raw_strings
|
60
|
+
io.seek offset
|
61
|
+
@string[offset] = BinData::Stringz.new.read(io).to_s.com8ble.force_encoding(encoding).encode("UTF-8")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# /#URLTBL
|
66
|
+
def url_table(offset)
|
67
|
+
io = StringIO.new raw_urltbl
|
68
|
+
io.seek offset
|
69
|
+
Struct::URLTable::URLTableRecord.new.read(io)
|
70
|
+
end
|
71
|
+
|
72
|
+
# /#URLSTR
|
73
|
+
def url_string(offset)
|
74
|
+
io = StringIO.new raw_urlstr
|
75
|
+
io.seek offset
|
76
|
+
FFI::Chm::Struct::URLString.new.read io
|
77
|
+
end
|
78
|
+
|
79
|
+
def fulltext_search(pattern, options={}, &block)
|
80
|
+
pattern = pattern.com8ble.force_encoding('UTF-8').encode(self.encoding).force_encoding("ASCII-8BIT")
|
81
|
+
context =
|
82
|
+
case options[:context]
|
83
|
+
when :title
|
84
|
+
0
|
85
|
+
when :body
|
86
|
+
1
|
87
|
+
end
|
88
|
+
|
89
|
+
case fulltext_index.depth.to_i
|
90
|
+
when 1
|
91
|
+
search_inner_prefix fulltext_index.root.to_a, pattern, context, &block
|
92
|
+
when 2
|
93
|
+
search_inner_prefix fulltext_index.root.records, pattern, context, &block
|
94
|
+
else
|
95
|
+
raise "Index tree is too deep(#{fulltext_index.depth})."
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def raw_strings
|
101
|
+
@strings ||= retrieve_object("/#STRINGS").freeze
|
102
|
+
end
|
103
|
+
|
104
|
+
def raw_urltbl
|
105
|
+
@urltbl ||= retrieve_object("/#URLTBL").freeze
|
106
|
+
end
|
107
|
+
|
108
|
+
def raw_urlstr
|
109
|
+
@urlstr ||= retrieve_object("/#URLSTR").freeze
|
110
|
+
end
|
111
|
+
|
112
|
+
def search_inner_prefix(records, pattern, context, &block)
|
113
|
+
word = ""
|
114
|
+
records.each do |r|
|
115
|
+
word = word[0, r.position] + r.word
|
116
|
+
len = pattern.length
|
117
|
+
#len = [pattern.length, word.length].min
|
118
|
+
comp = word[0, len] <=> pattern[0, len]
|
119
|
+
|
120
|
+
case r
|
121
|
+
when Struct::FulltextIndex::Leaf::LeafRecord
|
122
|
+
case comp
|
123
|
+
when -1
|
124
|
+
next
|
125
|
+
when 1
|
126
|
+
break
|
127
|
+
else
|
128
|
+
next if context && context == r.context
|
129
|
+
#block.call fulltext_index.wlcs(r) if context == r.context
|
130
|
+
block.call r
|
131
|
+
end
|
132
|
+
when Struct::FulltextIndex::Index::IndexRecord
|
133
|
+
next if comp == -1
|
134
|
+
search_inner_prefix(fulltext_index.leaf(r.offset_of_leaf).records, pattern, context, &block)
|
135
|
+
break if comp == 1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
39
139
|
end
|
data/lib/ffi-chm/com8ble.rb
CHANGED
data/lib/ffi-chm/struct.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
require 'bindata'
|
2
2
|
|
3
3
|
module FFI::Chm::Struct
|
4
|
+
autoload :FulltextIndex, 'ffi-chm/struct/fulltext_index'
|
5
|
+
autoload :Topics, 'ffi-chm/struct/topics'
|
4
6
|
autoload :System, 'ffi-chm/struct/system'
|
5
7
|
autoload :HHK, 'ffi-chm/struct/hhk/entry'
|
6
8
|
autoload :HHC, 'ffi-chm/struct/hhc/entry'
|
7
9
|
autoload :HHXDocument, 'ffi-chm/struct/hhx_document'
|
10
|
+
autoload :URLTable, 'ffi-chm/struct/url_table'
|
11
|
+
autoload :URLString, 'ffi-chm/struct/url_string'
|
12
|
+
autoload :SR, 'ffi-chm/struct/sr'
|
13
|
+
autoload :WLC, 'ffi-chm/struct/wlc'
|
8
14
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
class FFI::Chm::Struct::FulltextIndex < BinData::Record
|
2
|
+
endian :little
|
3
|
+
|
4
|
+
hide :unknown1, :unknown2, :unknown3, :unknown4, :unknown5, :unknown6, :unknown7, :unknown8, :unknown9, :unknown10, :rest
|
5
|
+
hide :document_scale, :code_count_scale, :location_code_scale
|
6
|
+
|
7
|
+
uint32 :unknown1
|
8
|
+
uint32 :num_files
|
9
|
+
uint32 :offset_to_root
|
10
|
+
uint32 :unknown2, :check_value => 0
|
11
|
+
uint32 :num_nodes
|
12
|
+
uint32 :unknown3, :check_value => :offset_to_root
|
13
|
+
uint16 :depth
|
14
|
+
uint32 :unknown4
|
15
|
+
uint8 :document_scale
|
16
|
+
uint8 :document_root
|
17
|
+
uint8 :code_count_scale
|
18
|
+
uint8 :code_count_root
|
19
|
+
uint8 :location_code_scale
|
20
|
+
uint8 :location_code_root
|
21
|
+
string :unknown5, :read_length => 10
|
22
|
+
uint32 :node_size
|
23
|
+
uint32 :unknown6
|
24
|
+
uint32 :word_index_of_last_duplicate
|
25
|
+
uint32 :char_index_of_last_duplicate
|
26
|
+
uint32 :longest_word
|
27
|
+
uint32 :num_words
|
28
|
+
uint32 :num_unique_words
|
29
|
+
uint32 :length_of_words1
|
30
|
+
uint32 :length_of_words2
|
31
|
+
uint32 :length_of_unique_words
|
32
|
+
uint32 :length_of_null_bytes
|
33
|
+
uint32 :unknown7
|
34
|
+
uint32 :unknown8
|
35
|
+
string :unknown9, :read_length => 24
|
36
|
+
|
37
|
+
# http://en.wikipedia.org/wiki/Windows_code_page
|
38
|
+
uint32 :codepage
|
39
|
+
|
40
|
+
# http://msdn.microsoft.com/en-us/library/0h88fahh.aspx
|
41
|
+
uint32 :lcid
|
42
|
+
string :unknown10, :read_length => 894
|
43
|
+
|
44
|
+
rest :rest
|
45
|
+
|
46
|
+
require 'ffi-chm/struct/fulltext_index/leaf'
|
47
|
+
require 'ffi-chm/struct/fulltext_index/index'
|
48
|
+
|
49
|
+
def nodedata(offset, size=node_size)
|
50
|
+
rest[offset - 1024, size]
|
51
|
+
end
|
52
|
+
|
53
|
+
def leaf(offset)
|
54
|
+
FFI::Chm::Struct::FulltextIndex::Leaf.new.read(self.nodedata(offset))
|
55
|
+
end
|
56
|
+
|
57
|
+
def single_leaf?
|
58
|
+
self.depth == 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def root
|
62
|
+
@root ||= (single_leaf? ? Leaf : Index).new.read(self.nodedata(self.offset_to_root))
|
63
|
+
end
|
64
|
+
|
65
|
+
def wlc_params
|
66
|
+
{
|
67
|
+
:document_root => self.document_root,
|
68
|
+
:code_count_root => self.code_count_root,
|
69
|
+
:location_code_root => self.location_code_root
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def wlcs(leaf)
|
74
|
+
@wlcs ||= {}
|
75
|
+
if @wlcs.has_key? leaf.offset_of_wlcs
|
76
|
+
@wlcs[leaf.offset_of_wlcs]
|
77
|
+
else
|
78
|
+
data = BinData::IO.new self.nodedata(leaf.offset_of_wlcs, leaf.length_of_wlcs)
|
79
|
+
@wlcs[leaf.offset_of_wlcs] = leaf.num_wlcs.times.map do
|
80
|
+
FFI::Chm::Struct::WLC.new(self.wlc_params).read(data)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class FFI::Chm::Struct::FulltextIndex::Index < BinData::Record
|
2
|
+
endian :little
|
3
|
+
|
4
|
+
uint16 :freespace
|
5
|
+
|
6
|
+
count_bytes_remaining :bytes_remaining
|
7
|
+
string :rawdata, :read_length => lambda {bytes_remaining - freespace}
|
8
|
+
|
9
|
+
hide :rawdata
|
10
|
+
|
11
|
+
require 'ffi-chm/struct/fulltext_index/index/index_record'
|
12
|
+
|
13
|
+
def records
|
14
|
+
@records ||= BinData::Array.new(:type => :index_record, :read_until => :eof).read self.rawdata
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class FFI::Chm::Struct::FulltextIndex::Index::IndexRecord < BinData::Record
|
2
|
+
endian :little
|
3
|
+
|
4
|
+
uint8 :length_of_word
|
5
|
+
uint8 :position
|
6
|
+
string :word, :read_length => lambda {length_of_word - 1}
|
7
|
+
uint32 :offset_of_leaf
|
8
|
+
uint16 :unknown, :check_value => 0
|
9
|
+
|
10
|
+
hide :length_of_word, :unknown
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class FFI::Chm::Struct::FulltextIndex::Leaf < BinData::Record
|
2
|
+
endian :little
|
3
|
+
|
4
|
+
uint32 :offset_to_next
|
5
|
+
uint16 :unknown, :check_value => 0
|
6
|
+
uint16 :freespace
|
7
|
+
|
8
|
+
hide :rawdata
|
9
|
+
count_bytes_remaining :bytes_remaining
|
10
|
+
string :rawdata, :read_length => lambda {bytes_remaining - freespace}
|
11
|
+
|
12
|
+
require 'ffi-chm/struct/fulltext_index/leaf/leaf_record'
|
13
|
+
|
14
|
+
def records
|
15
|
+
@records ||= BinData::Array.new(:type => :leaf_record, :read_until => :eof).read self.rawdata
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class FFI::Chm::Struct::FulltextIndex::Leaf::LeafRecord < BinData::Record
|
2
|
+
require 'ffi-chm/struct/encint'
|
3
|
+
|
4
|
+
endian :little
|
5
|
+
|
6
|
+
uint8 :length_of_word
|
7
|
+
uint8 :position
|
8
|
+
string :word, :read_length => lambda {length_of_word - 1}
|
9
|
+
uint8 :context # 0: body, 1: title
|
10
|
+
encint :num_wlcs
|
11
|
+
uint32 :offset_of_wlcs
|
12
|
+
uint16 :unknown, :check_value => 0
|
13
|
+
encint :length_of_wlcs
|
14
|
+
|
15
|
+
hide :length_of_word, :unknown
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class FFI::Chm::Struct::SR < BinData::Primitive
|
2
|
+
# s = 2
|
3
|
+
mandatory_parameter :r
|
4
|
+
|
5
|
+
array :prefix, :type => :bit1, :read_until => lambda { element.zero? }
|
6
|
+
array :bits, :type => :bit1, :initial_length => :num_bits
|
7
|
+
|
8
|
+
def num_bits
|
9
|
+
eval_parameter(:r) + [0, prefix.size - 2].max
|
10
|
+
end
|
11
|
+
|
12
|
+
def get
|
13
|
+
size = prefix.size
|
14
|
+
ret = bits.inject(0){|r, v| r << 1 | v}
|
15
|
+
ret += 2 << (eval_parameter(:r) + size - 3) if size > 1
|
16
|
+
ret
|
17
|
+
end
|
18
|
+
|
19
|
+
module Shortcut
|
20
|
+
def prefix
|
21
|
+
@struct[:prefix]
|
22
|
+
end
|
23
|
+
|
24
|
+
def bits
|
25
|
+
@struct[:bits]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
include Shortcut
|
30
|
+
end
|
@@ -1,23 +1,26 @@
|
|
1
1
|
class FFI::Chm::Struct::System < BinData::Record
|
2
|
-
|
2
|
+
class NoRecordError < StandardError;end
|
3
|
+
|
4
|
+
require 'ffi-chm/struct/system/system_record'
|
3
5
|
|
4
6
|
endian :little
|
5
7
|
|
6
8
|
uint32 :version
|
7
|
-
array :records, :type => :
|
9
|
+
array :records, :type => :system_record, :read_until => :eof
|
8
10
|
|
9
11
|
|
10
12
|
def record(code)
|
11
13
|
@memo ||= Hash[*records.map{|v|[v.code.to_i, v]}.flatten]
|
14
|
+
raise NoRecordError, "/#SYSTEM has no record code:#{code}" unless @memo.has_key? code
|
12
15
|
@memo[code]
|
13
16
|
end
|
14
17
|
|
18
|
+
LCID2ENCODING = {
|
19
|
+
1041 => "CP932", # SJIS
|
20
|
+
2052 => "CP936" # GB2313
|
21
|
+
}
|
22
|
+
|
15
23
|
def encoding
|
16
|
-
|
17
|
-
when 1041
|
18
|
-
"CP932"
|
19
|
-
else
|
20
|
-
"UTF-8"
|
21
|
-
end
|
24
|
+
LCID2ENCODING[self.record(4).data.lcid.to_i] || "CP1252" # ANSI
|
22
25
|
end
|
23
26
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class FFI::Chm::Struct::Topics < BinData::Record
|
2
|
+
require 'ffi-chm/struct/topics/topics_record'
|
3
|
+
|
4
|
+
rest :rawdata
|
5
|
+
|
6
|
+
def records
|
7
|
+
Com8ble::Enumerator.new self, :each_record
|
8
|
+
end
|
9
|
+
|
10
|
+
def each_record
|
11
|
+
(rawdata.size >> 4).times do |i|
|
12
|
+
yield record(i)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def record(index)
|
17
|
+
io = StringIO.new rawdata
|
18
|
+
io.seek index << 4
|
19
|
+
r = TopicsRecord.new.read io
|
20
|
+
r.set_context @chm
|
21
|
+
r
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_context(chm)# :nodoc:
|
25
|
+
@chm = chm
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class FFI::Chm::Struct::Topics::TopicsRecord < BinData::Record
|
2
|
+
endian :little
|
3
|
+
|
4
|
+
uint32 :offset_in_tocidx
|
5
|
+
uint32 :offset_in_strings
|
6
|
+
uint32 :offset_in_urltbl
|
7
|
+
uint16 :in_contents # 2: not in contents, 6: in contents
|
8
|
+
uint16 :unknown
|
9
|
+
|
10
|
+
hide :unknown
|
11
|
+
|
12
|
+
def title
|
13
|
+
@chm.string(offset_in_strings) rescue nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def local
|
17
|
+
table = @chm.url_table(offset_in_urltbl)
|
18
|
+
@chm.url_string(table.offset_in_urlstr).local
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_context(chm)# :nodoc:
|
22
|
+
@chm = chm
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class FFI::Chm::Struct::WLC < BinData::Record
|
2
|
+
require 'ffi-chm/struct/sr'
|
3
|
+
|
4
|
+
mandatory_parameter :document_root, :code_count_root, :location_code_root
|
5
|
+
|
6
|
+
sr :document_index, :r => :document_root
|
7
|
+
sr :code_count, :r => :code_count_root
|
8
|
+
|
9
|
+
array :locations, :initial_length => :code_count do
|
10
|
+
sr :location_code, :r => :location_code_root
|
11
|
+
end
|
12
|
+
|
13
|
+
hide :code_count
|
14
|
+
|
15
|
+
resume_byte_alignment
|
16
|
+
end
|
data/test/test_sr.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "ffi-chm"
|
3
|
+
|
4
|
+
class TestSR < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@testset = [
|
7
|
+
[2, 3, '011----'],
|
8
|
+
[2, 4, '1000----'],
|
9
|
+
[3, 0, '0000----'],
|
10
|
+
[3, 1, '0001----'],
|
11
|
+
[3, 2, '0010----'],
|
12
|
+
[3, 7, '0111----'],
|
13
|
+
[3, 8, '10000---'],
|
14
|
+
[3, 9, '10001---'],
|
15
|
+
[3, 10, '10010---'],
|
16
|
+
[3, 15, '10111---'],
|
17
|
+
[3, 16, '1100000-'],
|
18
|
+
[3, 17, '1100001-'],
|
19
|
+
[3, 18, '1100010-'],
|
20
|
+
[3, 30, '1101110-'],
|
21
|
+
[3, 31, '1101111-'],
|
22
|
+
[3, 32, '111000000-------'],
|
23
|
+
[3, 33, '111000001-------'],
|
24
|
+
[3, 34, '111000010-------'],
|
25
|
+
[3, 62, '111011110-------'],
|
26
|
+
[3, 63, '111011111-------'],
|
27
|
+
[3, 64, '11110000000-----'],
|
28
|
+
[5, 31, '011111----------'],
|
29
|
+
[5, 63, '1011111----------'],
|
30
|
+
[5, 512, '111110000000000-']
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_sr
|
35
|
+
@testset.each{|set|set.last.gsub!('-', '0')}
|
36
|
+
@testset.each do |r, expect, bits|
|
37
|
+
sr = FFI::Chm::Struct::SR.new(:r => r).read [bits].pack("B*")
|
38
|
+
assert_equal expect, sr.get
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_sr_byte_aligned
|
43
|
+
@testset.each{|set|set.last.delete!('-')}
|
44
|
+
|
45
|
+
rs, expects, bits = @testset.transpose
|
46
|
+
bits = bits.join
|
47
|
+
bits += "0" * bits.size % 8
|
48
|
+
wlcs = BinData::IO.new [bits].pack("B*")
|
49
|
+
|
50
|
+
values = rs.map{|r| FFI::Chm::Struct::SR.new(:r => r).read(wlcs)}
|
51
|
+
|
52
|
+
assert_equal expects, values
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-chm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-09-09 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
16
|
-
requirement: &
|
16
|
+
requirement: &70226425573140 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70226425573140
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: bindata
|
27
|
-
requirement: &
|
27
|
+
requirement: &70226425572700 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,21 +32,21 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70226425572700
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: nokogiri
|
38
|
-
requirement: &
|
38
|
+
requirement: &70226425572120 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
43
|
+
version: 1.5.0
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70226425572120
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: hoe
|
49
|
-
requirement: &
|
49
|
+
requirement: &70226425571580 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '2.10'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70226425571580
|
58
58
|
description: Ruby bindings for the libchm via FFI.
|
59
59
|
email:
|
60
60
|
- nanki@dotswitch.net
|
@@ -69,17 +69,32 @@ files:
|
|
69
69
|
- lib/ffi-chm/chm_file.rb
|
70
70
|
- lib/ffi-chm/com8ble.rb
|
71
71
|
- lib/ffi-chm/const.rb
|
72
|
+
- lib/ffi-chm/struct/encint.rb
|
73
|
+
- lib/ffi-chm/struct/fulltext_index/index/index_record.rb
|
74
|
+
- lib/ffi-chm/struct/fulltext_index/index.rb
|
75
|
+
- lib/ffi-chm/struct/fulltext_index/leaf/leaf_record.rb
|
76
|
+
- lib/ffi-chm/struct/fulltext_index/leaf.rb
|
77
|
+
- lib/ffi-chm/struct/fulltext_index.rb
|
72
78
|
- lib/ffi-chm/struct/hhc/entry.rb
|
73
79
|
- lib/ffi-chm/struct/hhk/entry.rb
|
74
80
|
- lib/ffi-chm/struct/hhx_document.rb
|
81
|
+
- lib/ffi-chm/struct/sr.rb
|
75
82
|
- lib/ffi-chm/struct/system/code3.rb
|
76
83
|
- lib/ffi-chm/struct/system/code4.rb
|
77
84
|
- lib/ffi-chm/struct/system/code6.rb
|
78
|
-
- lib/ffi-chm/struct/system/
|
85
|
+
- lib/ffi-chm/struct/system/system_record.rb
|
79
86
|
- lib/ffi-chm/struct/system.rb
|
87
|
+
- lib/ffi-chm/struct/topics/topics_record.rb
|
88
|
+
- lib/ffi-chm/struct/topics.rb
|
89
|
+
- lib/ffi-chm/struct/url_string.rb
|
90
|
+
- lib/ffi-chm/struct/url_table/url_table_block.rb
|
91
|
+
- lib/ffi-chm/struct/url_table/url_table_record.rb
|
92
|
+
- lib/ffi-chm/struct/url_table.rb
|
93
|
+
- lib/ffi-chm/struct/wlc.rb
|
80
94
|
- lib/ffi-chm/struct.rb
|
81
95
|
- lib/ffi-chm/unit_info.rb
|
82
96
|
- lib/ffi-chm.rb
|
97
|
+
- test/test_sr.rb
|
83
98
|
- test/test_ffi_chm.rb
|
84
99
|
- .gemtest
|
85
100
|
homepage: http://github.com/nanki/ffi-chm
|
@@ -110,3 +125,4 @@ specification_version: 3
|
|
110
125
|
summary: Ruby bindings for the libchm via FFI.
|
111
126
|
test_files:
|
112
127
|
- test/test_ffi_chm.rb
|
128
|
+
- test/test_sr.rb
|