sso-elements-fmk 0.1.1
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 +7 -0
- data/.idea/.gitignore +8 -0
- data/.idea/modules.xml +8 -0
- data/.idea/sso-elements-fmk.iml +59 -0
- data/.idea/vcs.xml +6 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +165 -0
- data/README.md +39 -0
- data/Rakefile +8 -0
- data/lib/sso/elements/collection.rb +248 -0
- data/lib/sso/elements/config.rb +91 -0
- data/lib/sso/elements/configs/PW_1.0.2_v150.cfg +1227 -0
- data/lib/sso/elements/configs/PW_1.0.2_v152.cfg +1232 -0
- data/lib/sso/elements/element.rb +112 -0
- data/lib/sso/elements/field.rb +22 -0
- data/lib/sso/elements/fmk/version.rb +9 -0
- data/lib/sso/elements/fmk.rb +12 -0
- data/lib/sso/elements/samples/elements.data +0 -0
- data/sig/sso/elements/element.rbs +9 -0
- data/sig/sso/elements/fmk.rbs +8 -0
- data/sig/sso/elements/test_fmk.rbs +7 -0
- metadata +66 -0
@@ -0,0 +1,248 @@
|
|
1
|
+
require_relative 'config'
|
2
|
+
|
3
|
+
module SSO
|
4
|
+
module Elements
|
5
|
+
class Collection
|
6
|
+
attr_accessor :version,
|
7
|
+
:signature,
|
8
|
+
:index,
|
9
|
+
:configs
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@addon_index = {}
|
13
|
+
@lists = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def table(name)
|
17
|
+
index[name]
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_index!
|
21
|
+
@index = {}
|
22
|
+
@configs.each do |config|
|
23
|
+
config_name = config.name.split(' - ').last.downcase.split('_').map(&:capitalize).join('')
|
24
|
+
@index[config_name] = config
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_elements!(path)
|
29
|
+
sstat = [ 0, 0, 0, 0, 0 ]
|
30
|
+
|
31
|
+
file = File.open(path, 'rb')
|
32
|
+
|
33
|
+
@version = file.read(2).unpack('s<').first
|
34
|
+
|
35
|
+
if @configs.nil?
|
36
|
+
puts '[INFO] No config provided. Searching in default CFG files'
|
37
|
+
if SSO::Elements::Config::CFG_AVAIL.keys.include?(@version)
|
38
|
+
puts "[INFO] Using #{SSO::Elements::Config::CFG_AVAIL[@version]}!"
|
39
|
+
load_config!(@version)
|
40
|
+
else
|
41
|
+
raise "[ERROR] No config provided and no default cfg file to match with elements version #{@version}!"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
@signature = file.read(2).unpack('s<').first
|
46
|
+
|
47
|
+
@configs.each_with_index do |config, i|
|
48
|
+
puts "[INFO] (#{i+1}/#{@configs.size}) Reading #{config.name} ... "
|
49
|
+
sstat[0] = i
|
50
|
+
|
51
|
+
if config.offset.size > 0
|
52
|
+
config.offset = file.read(config.offset.size).bytes
|
53
|
+
else
|
54
|
+
puts 'CRITICAL: NO OFFSET FOUND!'
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
|
58
|
+
config.values = Array.new(read_value(file, 'int32'))
|
59
|
+
sstat[1] = config.values.size
|
60
|
+
|
61
|
+
(0...config.values.size).each do |e|
|
62
|
+
config.values[e] = Array.new(config.types.size)
|
63
|
+
|
64
|
+
(0...config.values[e].size).each do |f|
|
65
|
+
config.values[e][f] = read_value(file, config.types[f])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
file.close
|
71
|
+
|
72
|
+
build_index!
|
73
|
+
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
def load_config!(path)
|
78
|
+
if path.is_a?(Integer)
|
79
|
+
cfg = Config::CFG_AVAIL[path]
|
80
|
+
raise "Incompatible version #{path}!" unless cfg
|
81
|
+
dir = File.dirname(__FILE__)
|
82
|
+
path = File.expand_path("./configs/#{cfg}", dir)
|
83
|
+
end
|
84
|
+
|
85
|
+
buffer = File.readlines(path, chomp: true)
|
86
|
+
|
87
|
+
lists_size = buffer.shift.to_i
|
88
|
+
|
89
|
+
lists = []
|
90
|
+
@conversation_list_index = buffer.shift.to_i
|
91
|
+
@conversation_list_index = 58 if @conversation_list_index == 0
|
92
|
+
|
93
|
+
lists_size.times do
|
94
|
+
line = ''
|
95
|
+
|
96
|
+
loop do
|
97
|
+
line = buffer.shift
|
98
|
+
break unless line == ''
|
99
|
+
end
|
100
|
+
|
101
|
+
offset = buffer.shift
|
102
|
+
|
103
|
+
list = Config.new
|
104
|
+
list.name = line
|
105
|
+
list.offset = Array.new(offset.to_i) if offset != 'AUTO'
|
106
|
+
list.fields = buffer.shift.split(';')
|
107
|
+
list.types = buffer.shift.split(';')
|
108
|
+
lists << list
|
109
|
+
end
|
110
|
+
|
111
|
+
@configs = lists
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
def load_rules(path)
|
116
|
+
buffer = File.readlines(path, chomp: true)
|
117
|
+
|
118
|
+
result = {}
|
119
|
+
|
120
|
+
buffer.each do |line|
|
121
|
+
next if line.empty? || line[0] == '#'
|
122
|
+
|
123
|
+
if line.include?('|')
|
124
|
+
key, value = line.split('|')
|
125
|
+
else
|
126
|
+
key = line
|
127
|
+
value = ''
|
128
|
+
end
|
129
|
+
|
130
|
+
result[key] = value
|
131
|
+
end
|
132
|
+
|
133
|
+
result['SETCONVERSATIONLISTINDEX'] ||= 58
|
134
|
+
|
135
|
+
result
|
136
|
+
end
|
137
|
+
|
138
|
+
def save!(path)
|
139
|
+
File.delete(path) if File.exist?(path)
|
140
|
+
file = File.open(path, 'wb')
|
141
|
+
|
142
|
+
file.write([@version].pack('s<'))
|
143
|
+
file.write([@signature].pack('s<'))
|
144
|
+
|
145
|
+
@configs.each_with_index do |config, index|
|
146
|
+
puts "[INFO] (#{index+1}/#{@configs.size}) Saving #{config.name} ... "
|
147
|
+
file.write(config.offset.pack("C*")) if config.offset.size > 0
|
148
|
+
|
149
|
+
if @conversation_list_index != index
|
150
|
+
file.write([config.values.size].pack('l<'))
|
151
|
+
end
|
152
|
+
|
153
|
+
if config.elements_loaded?
|
154
|
+
(0...config.values.size).each do |config_values_index|
|
155
|
+
config.values[config_values_index] = config.elements[config_values_index].to_value
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
config.values.each do |values|
|
160
|
+
values.each_with_index do |value, value_index|
|
161
|
+
begin
|
162
|
+
write_value(file, value, config.types[value_index])
|
163
|
+
rescue => e
|
164
|
+
pp values
|
165
|
+
raise e
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
file.close
|
172
|
+
true
|
173
|
+
rescue => e
|
174
|
+
p e
|
175
|
+
false
|
176
|
+
end
|
177
|
+
|
178
|
+
def read_value(file, type)
|
179
|
+
if type == 'int16'
|
180
|
+
file.read(2).unpack('s<')[0]
|
181
|
+
elsif type == 'int32'
|
182
|
+
file.read(4).unpack("l<")[0]
|
183
|
+
elsif type == 'int64'
|
184
|
+
file.read(8).unpack('q<')[0]
|
185
|
+
elsif type == 'float'
|
186
|
+
file.read(4).unpack('f')[0]
|
187
|
+
elsif type == 'double'
|
188
|
+
file.read(8).unpack('d')[0]
|
189
|
+
elsif type.start_with?('byte:')
|
190
|
+
byte_count = type[5..-1].to_i
|
191
|
+
file.read(byte_count)
|
192
|
+
elsif type.start_with?('wstring:')
|
193
|
+
byte_count = type[8..-1].to_i
|
194
|
+
Collection.compact_string(file.read(byte_count).force_encoding('UTF-16LE').encode('UTF-8'))
|
195
|
+
elsif type.start_with?('string:')
|
196
|
+
byte_count = type[7..-1].to_i
|
197
|
+
Collection.compact_string(file.read(byte_count).force_encoding('UTF-8'))
|
198
|
+
else
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def write_value(file, value, type)
|
204
|
+
if type == 'int16'
|
205
|
+
file.write([value.to_i].pack('s<'))
|
206
|
+
elsif type == 'int32'
|
207
|
+
file.write([value.to_i].pack('l<'))
|
208
|
+
elsif type == 'int64'
|
209
|
+
file.write([value.to_f].pack('q<'))
|
210
|
+
elsif type == 'float'
|
211
|
+
file.write([value.to_f].pack('f'))
|
212
|
+
elsif type == 'double'
|
213
|
+
file.write([value.to_f].pack('d'))
|
214
|
+
elsif type.start_with?('byte:')
|
215
|
+
file.write(value)
|
216
|
+
elsif type.start_with?('wstring:')
|
217
|
+
file.write(Collection.expand_string_utf16((value || 'BUG').encode('UTF-16LE'), type))
|
218
|
+
elsif type.start_with?('string:')
|
219
|
+
file.write(Collection.expand_string_utf8((value || 'BUG'), type))
|
220
|
+
else
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
rescue => e
|
224
|
+
pp value
|
225
|
+
pp type
|
226
|
+
raise e
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.compact_string(s)
|
230
|
+
s.gsub("\u0000", '')
|
231
|
+
end
|
232
|
+
|
233
|
+
def self.expand_string_utf16(base, type)
|
234
|
+
sz = type.split(':').last.to_i
|
235
|
+
s = base
|
236
|
+
s += "\u0000".encode('UTF-16LE') while s.bytes.size < sz
|
237
|
+
s
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.expand_string_utf8(base, type)
|
241
|
+
sz = type.split(':').last.to_i
|
242
|
+
s = base
|
243
|
+
s += "\u0000" while s.bytes.size < sz
|
244
|
+
s
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative 'element'
|
2
|
+
require_relative 'field'
|
3
|
+
|
4
|
+
module SSO
|
5
|
+
module Elements
|
6
|
+
class Config
|
7
|
+
attr_accessor :name,
|
8
|
+
:offset,
|
9
|
+
:type,
|
10
|
+
:fields,
|
11
|
+
:types,
|
12
|
+
:values
|
13
|
+
|
14
|
+
CFG_AVAIL = {
|
15
|
+
150 => 'PW_1.0.2_v150.cfg',
|
16
|
+
152 => 'PW_1.0.2_v152.cfg'
|
17
|
+
}
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@offsets = []
|
21
|
+
@fields = []
|
22
|
+
@types = []
|
23
|
+
@values = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_json
|
27
|
+
values.map do |value|
|
28
|
+
result = {}
|
29
|
+
|
30
|
+
value.each_with_index do |data, index|
|
31
|
+
result[fields[index]] = {
|
32
|
+
'data' => data,
|
33
|
+
'type' => types[index]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def elements
|
42
|
+
return @elements if @elements
|
43
|
+
|
44
|
+
@elements = values.map do |value|
|
45
|
+
Element.from_value(self, value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def elements_loaded?
|
50
|
+
!@elements.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_element(element)
|
54
|
+
@values << element.to_value
|
55
|
+
@elements << element
|
56
|
+
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_element_by_id(id)
|
61
|
+
elements.find do |element|
|
62
|
+
element.id == id
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_element_by_name(name)
|
67
|
+
elements.find do |element|
|
68
|
+
element.name.to_s.downcase == name.to_s.downcase
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_elements_by_name(name)
|
73
|
+
elements.select do |element|
|
74
|
+
element.name.to_s.downcase.include?(name.to_s.downcase)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
def grouped_field_quantity
|
78
|
+
return @fields_quantity if @fields_quantity
|
79
|
+
|
80
|
+
@fields_quantity = {}
|
81
|
+
|
82
|
+
fields.each do |field|
|
83
|
+
@fields_quantity[field] ||= 0
|
84
|
+
@fields_quantity[field] += 1
|
85
|
+
end
|
86
|
+
|
87
|
+
@fields_quantity
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|