lz_string 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 536eca3d25c94ce1558bd881c8f09dfa5dab331a7d3c3da19a5166681ad2ac41
4
+ data.tar.gz: 86d3a24237c3e1654b9b3c29bf7978435e68cf4caa6a22a66b04472ac222b3df
5
+ SHA512:
6
+ metadata.gz: 311b8e802592b7c364c43f031c89b6fa104b76637c2679d6a0d7f8955ffd40e63e55d48543e9f371f64a38e23e6bdce9d1a7b3985057b10a8717ca699b89cdcb
7
+ data.tar.gz: d1e2f28b4c9ed85483254ed7d7f8f90cdb438f112b115e0f893be9a91986714990805acd1ba0a2126bf92e79a60b19660ac98c5e953903cd3c678d6511e822a6
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # lz-string
2
+ Ruby implementation of LZ-String compression algorithm
@@ -0,0 +1,397 @@
1
+ module LZString
2
+ # Base compression class.
3
+ class Base
4
+ # @param uncompressed [String]
5
+ # @param bits_per_char [Integer]
6
+ # @param get_char_from_int [Integer]
7
+ def self.compress(uncompressed, bits_per_char, get_char_from_int)
8
+ return "" if uncompressed.nil?
9
+
10
+ i, value, ii = nil
11
+ context_dictionary = {}
12
+ context_dictionary_to_create = {}
13
+ context_c = ""
14
+ context_wc = ""
15
+ context_w = ""
16
+ # Compensate for the first entry which should not count
17
+ context_enlarge_in = 2
18
+ context_dict_size = 3
19
+ context_num_bits = 2
20
+ context_data = []
21
+ context_data_val = 0
22
+ context_data_position = 0
23
+
24
+ for ii in 0...uncompressed.length do
25
+ context_c = uncompressed[ii]
26
+
27
+ if (!context_dictionary.has_key?(context_c))
28
+ context_dictionary[context_c] = context_dict_size
29
+ context_dictionary_to_create[context_c] = true
30
+ context_dict_size += 1
31
+ end
32
+
33
+ context_wc = context_w + context_c
34
+ if (context_dictionary.has_key?(context_wc))
35
+ context_w = context_wc
36
+ else
37
+ if (context_dictionary_to_create.has_key?(context_w))
38
+ if (context_w[0].ord < 256)
39
+ for i in 0...context_num_bits do
40
+ context_data_val = (context_data_val << 1)
41
+ if (context_data_position == bits_per_char - 1)
42
+ context_data_position = 0
43
+ context_data.push(get_char_from_int[context_data_val])
44
+ context_data_val = 0
45
+ else
46
+ context_data_position += 1
47
+ end
48
+ end
49
+
50
+ value = context_w[0].ord
51
+ for i in 0...8 do
52
+ context_data_val = (context_data_val << 1) | (value & 1)
53
+ if (context_data_position == bits_per_char - 1)
54
+ context_data_position = 0
55
+ context_data.push(get_char_from_int[context_data_val])
56
+ context_data_val = 0
57
+ else
58
+ context_data_position += 1
59
+ end
60
+ value = value >> 1
61
+ end
62
+ else
63
+ value = 1
64
+ for i in 0...context_num_bits do
65
+ context_data_val = (context_data_val << 1) | value
66
+ if (context_data_position == bits_per_char-1)
67
+ context_data_position = 0
68
+ context_data.push(get_char_from_int[context_data_val])
69
+ context_data_val = 0
70
+ else
71
+ context_data_position += 1
72
+ end
73
+ value = 0
74
+ end
75
+ value = context_w[0].ord
76
+ for i in 0...16 do
77
+ context_data_val = (context_data_val << 1) | (value & 1)
78
+ if (context_data_position == bits_per_char - 1)
79
+ context_data_position = 0
80
+ context_data.push(get_char_from_int[context_data_val])
81
+ context_data_val = 0
82
+ else
83
+ context_data_position += 1
84
+ end
85
+ value = value >> 1
86
+ end
87
+ end
88
+ context_enlarge_in -= 1
89
+ if (context_enlarge_in == 0)
90
+ context_enlarge_in = 2**context_num_bits
91
+ context_num_bits += 1
92
+ end
93
+ context_dictionary_to_create.delete(context_w)
94
+ else
95
+ value = context_dictionary[context_w]
96
+ for i in 0...context_num_bits do
97
+ context_data_val = (context_data_val << 1) | (value & 1)
98
+ if (context_data_position == bits_per_char - 1)
99
+ context_data_position = 0
100
+ context_data.push(get_char_from_int[context_data_val])
101
+ context_data_val = 0
102
+ else
103
+ context_data_position += 1
104
+ end
105
+ value = value >> 1
106
+ end
107
+ end
108
+
109
+ context_enlarge_in -= 1
110
+
111
+ if (context_enlarge_in == 0)
112
+ context_enlarge_in = 2**context_num_bits
113
+ context_num_bits += 1
114
+ end
115
+
116
+ # Add wc to the dictionary.
117
+ context_dictionary[context_wc] = context_dict_size
118
+ context_dict_size += 1
119
+ context_w = context_c.to_s
120
+ end
121
+ end
122
+
123
+ # Output the code for w.
124
+ if (context_w != "")
125
+ if (context_dictionary_to_create.has_key?(context_w))
126
+ if (context_w[0].ord < 256)
127
+ for i in 0...context_num_bits do
128
+ context_data_val = (context_data_val << 1)
129
+ if (context_data_position == bits_per_char-1)
130
+ context_data_position = 0
131
+ context_data.push(get_char_from_int[context_data_val])
132
+ context_data_val = 0
133
+ else
134
+ context_data_position += 1
135
+ end
136
+ end
137
+ value = context_w[0].ord
138
+ for i in 0...8 do
139
+ context_data_val = (context_data_val << 1) | (value & 1)
140
+ if (context_data_position == bits_per_char-1)
141
+ context_data_position = 0
142
+ context_data.push(get_char_from_int[context_data_val])
143
+ context_data_val = 0
144
+ else
145
+ context_data_position += 1
146
+ end
147
+ value = value >> 1
148
+ end
149
+ else
150
+ value = 1
151
+ for i in 0...context_num_bits do
152
+ context_data_val = (context_data_val << 1) | value
153
+ if (context_data_position == bits_per_char-1)
154
+ context_data_position = 0
155
+ context_data.push(get_char_from_int[context_data_val])
156
+ context_data_val = 0
157
+ else
158
+ context_data_position += 1
159
+ end
160
+ value = 0
161
+ end
162
+ value = context_w[0].ord
163
+ for i in 0...16 do
164
+ context_data_val = (context_data_val << 1) | (value & 1)
165
+ if (context_data_position == bits_per_char-1)
166
+ context_data_position = 0
167
+ context_data.push(get_char_from_int[context_data_val])
168
+ context_data_val = 0
169
+ else
170
+ context_data_position += 1
171
+ end
172
+ value = value >> 1
173
+ end
174
+ end
175
+ context_enlarge_in -= 1
176
+ if (context_enlarge_in == 0)
177
+ context_enlarge_in = 2**context_num_bits
178
+ context_num_bits += 1
179
+ end
180
+ context_dictionary_to_create.delete(context_w)
181
+ else
182
+ value = context_dictionary[context_w]
183
+ for i in 0...context_num_bits
184
+ context_data_val = (context_data_val << 1) | (value & 1)
185
+ if (context_data_position == bits_per_char-1)
186
+ context_data_position = 0
187
+ context_data.push(get_char_from_int[context_data_val])
188
+ context_data_val = 0
189
+ else
190
+ context_data_position += 1
191
+ end
192
+ value = value >> 1
193
+ end
194
+ end
195
+
196
+ context_enlarge_in -= 1
197
+ if (context_enlarge_in == 0)
198
+ context_enlarge_in = 2**context_num_bits
199
+ context_num_bits += 1
200
+ end
201
+ end
202
+
203
+ # Mark the end of the stream
204
+ value = 2
205
+ for i in 0...context_num_bits do
206
+ context_data_val = (context_data_val << 1) | (value & 1)
207
+ if (context_data_position == bits_per_char - 1)
208
+ context_data_position = 0
209
+ context_data.push(get_char_from_int[context_data_val])
210
+ context_data_val = 0
211
+ else
212
+ context_data_position += 1
213
+ end
214
+ value = value >> 1
215
+ end
216
+
217
+ # Flush the last char
218
+ while (true)
219
+ context_data_val = (context_data_val << 1)
220
+ if (context_data_position == bits_per_char-1)
221
+ context_data.push(get_char_from_int[context_data_val])
222
+ break
223
+ else
224
+ context_data_position += 1
225
+ end
226
+ end
227
+
228
+ return context_data.join("")
229
+ end
230
+
231
+ # @param length [Integer]
232
+ # @param reset_value [Integer]
233
+ # @param get_next_value [Proc]
234
+ def self.decompress(length, reset_value, get_next_value, encoding = "ASCII-8BIT")
235
+ dictionary = [0, 1, 2]
236
+ enlarge_in = 4
237
+ dict_size = 4
238
+ num_bits = 3
239
+ entry = ""
240
+ result = []
241
+ data = {
242
+ val: get_next_value[(0)],
243
+ position: reset_value,
244
+ index: 1
245
+ }
246
+ bits = 0
247
+ maxpower = 2**2
248
+ power = 1
249
+ i, w, resb, c = nil
250
+
251
+ while (power != maxpower)
252
+ resb = data[:val] & data[:position]
253
+ data[:position] >>= 1
254
+ if (data[:position] == 0)
255
+ data[:position] = reset_value
256
+ data[:val] = get_next_value[data[:index]]
257
+ data[:index] += 1
258
+ end
259
+ bits |= (resb > 0 ? 1 : 0) * power
260
+ power <<= 1
261
+ end
262
+
263
+ case(n = bits)
264
+ when 0
265
+ bits = 0
266
+ maxpower = 2**8
267
+ power = 1
268
+ while power != maxpower
269
+ resb = data[:val] & data[:position]
270
+ data[:position] >>= 1
271
+ if (data[:position] == 0)
272
+ data[:position] = reset_value
273
+ data[:val] = get_next_value[data[:index]]
274
+ data[:index] += 1
275
+ end
276
+ bits |= (resb > 0 ? 1 : 0) * power
277
+ power <<= 1
278
+ end
279
+ c = bits.chr(encoding)
280
+ when 1
281
+ bits = 0
282
+ maxpower = 2*16
283
+ power = 1
284
+ while (power != maxpower)
285
+ resb = data[:val] & data[:position]
286
+ data[:position] >>= 1
287
+ if (data[:position] == 0)
288
+ data[:position] = reset_value
289
+ data[:val] = get_next_value[data[:index]]
290
+ data[:index] += 1
291
+ end
292
+ bits |= (resb > 0 ? 1 : 0) * power
293
+ power <<= 1
294
+ end
295
+ c = bits.chr(encoding)
296
+ when 2
297
+ ""
298
+ end
299
+
300
+ dictionary[3] = c
301
+ w = c
302
+ result << c
303
+
304
+ while(true)
305
+ return "" if (data[:index] > length)
306
+
307
+ bits = 0
308
+ maxpower = 2**num_bits
309
+ power = 1
310
+ while (power != maxpower)
311
+ resb = data[:val] & data[:position]
312
+ data[:position] >>= 1
313
+ if (data[:position] == 0)
314
+ data[:position] = reset_value
315
+ data[:val] = get_next_value[data[:index]]
316
+ data[:index] += 1
317
+ end
318
+ bits |= (resb > 0 ? 1 : 0) * power
319
+ power <<= 1
320
+ end
321
+
322
+ case(c = bits)
323
+ when 0
324
+ bits = 0
325
+ maxpower = 2**8
326
+ power = 1
327
+ while (power != maxpower)
328
+ resb = data[:val] & data[:position]
329
+ data[:position] >>= 1
330
+ if (data[:position] == 0)
331
+ data[:position] = reset_value
332
+ data[:val] = get_next_value[data[:index]]
333
+ data[:index] += 1
334
+ end
335
+ bits |= (resb > 0 ? 1 : 0) * power
336
+ power <<= 1
337
+ end
338
+
339
+ dictionary[dict_size] = bits.chr(encoding)
340
+ dict_size += 1
341
+ c = dict_size - 1
342
+ enlarge_in -= 1
343
+ when 1
344
+ bits = 0
345
+ maxpower = 2**16
346
+ power = 1
347
+ while (power != maxpower)
348
+ resb = data[:val] & data[:position]
349
+ data[:position] >>= 1
350
+ if (data[:position] == 0)
351
+ data[:position] = reset_value
352
+ data[:val] = get_next_value[data[:index]]
353
+ data[:index] += 1
354
+ end
355
+ bits |= (resb > 0 ? 1 : 0) * power
356
+ power <<= 1
357
+ end
358
+ dictionary[dict_size] = bits.chr(encoding)
359
+ dict_size += 1
360
+ c = dict_size - 1
361
+ enlarge_in -= 1
362
+ when 2
363
+ return result.join("")
364
+ end
365
+
366
+ if (enlarge_in == 0)
367
+ enlarge_in = 2**num_bits
368
+ num_bits += 1
369
+ end
370
+
371
+ if (dictionary[c])
372
+ entry = dictionary[c]
373
+ else
374
+ if (c === dict_size)
375
+ entry = w + w[0]
376
+ else
377
+ return nil
378
+ end
379
+ end
380
+
381
+ result << entry
382
+
383
+ # Add w+entry[0] to the dictionary.
384
+ dictionary[dict_size] = w + entry[0]
385
+ dict_size += 1
386
+ enlarge_in -= 1
387
+
388
+ w = entry
389
+
390
+ if (enlarge_in == 0)
391
+ enlarge_in = 2**num_bits
392
+ num_bits += 1
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end
@@ -0,0 +1,51 @@
1
+ module LZString
2
+ # Base64 compressing algorithm.
3
+ class Base64
4
+ # Base64 alphabet.
5
+ KEY_STR_BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
6
+
7
+ # @param input [String]
8
+ def self.compress(input)
9
+ return "" if input.nil?
10
+
11
+ res = LZString::Base.compress(input, 6, lambda { |a| KEY_STR_BASE64[a] })
12
+
13
+ # To produce valid Base64
14
+ case (res.length % 4)
15
+ when 0 then res
16
+ when 1 then res + "==="
17
+ when 2 then res + "=="
18
+ when 3 then res + "="
19
+ end
20
+ end
21
+
22
+ # @param compressed [String]
23
+ def self.decompress(compressed)
24
+ return "" if compressed.nil?
25
+ return nil if compressed == ""
26
+
27
+ LZString::Base.decompress(
28
+ compressed.length,
29
+ 32,
30
+ lambda { |index| get_base_value(KEY_STR_BASE64, compressed[index]) }
31
+ )
32
+ end
33
+
34
+ # @param alphabet [String]
35
+ # @param character [String]
36
+ def self.get_base_value(alphabet, character)
37
+ base_reverse_dic = {}
38
+
39
+ if (!base_reverse_dic[alphabet])
40
+ base_reverse_dic[alphabet] = {}
41
+ for i in 0...alphabet.length do
42
+ base_reverse_dic[alphabet][alphabet[i]] = i
43
+ end
44
+ end
45
+
46
+ base_reverse_dic[alphabet][character]
47
+ end
48
+
49
+ private_class_method :get_base_value
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ module LZString
2
+ # UTF16 compressing algorithm.
3
+ class UTF16
4
+ # @param input [String]
5
+ def self.compress(input)
6
+ return "" if (input == nil)
7
+
8
+ LZString::Base.compress(input, 15, lambda { |a| (a + 32).chr("UTF-8") }) + " "
9
+ end
10
+
11
+ # @param compressed [String]
12
+ def self.decompress(compressed)
13
+ return "" if (compressed == nil)
14
+ return nil if (compressed == "")
15
+
16
+ LZString::Base.decompress(
17
+ compressed.length,
18
+ 16384,
19
+ lambda { |index| compressed[index].ord - 32 },
20
+ "UTF-8"
21
+ )
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ module LZString
2
+ # :nodoc:
3
+ VERSION = "0.1.0"
4
+ end
data/lib/lz_string.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "pry"
2
+ require "lz_string/base"
3
+ require "lz_string/base64"
4
+ require "lz_string/utf16"
5
+ require "lz_string/version"
6
+
7
+ # LZ-based compression algorithm.
8
+ module LZString
9
+ # @param input [String]
10
+ def self.compress(input)
11
+ return "" if input.nil?
12
+
13
+ LZString::Base.compress(input, 16, lambda { |a| a.chr("UTF-8") })
14
+ end
15
+
16
+ # @param compressed [String]
17
+ def self.decompress(compressed)
18
+ return "" if compressed.nil?
19
+ return nil if compressed == ""
20
+
21
+ LZString::Base.decompress(compressed.length, 32768, lambda { |index| compressed[index].ord })
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lz_string
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Altivi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby implementation of LZ-String compression algorithm
14
+ email:
15
+ - altivi.prog@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - lib/lz_string.rb
22
+ - lib/lz_string/base.rb
23
+ - lib/lz_string/base64.rb
24
+ - lib/lz_string/utf16.rb
25
+ - lib/lz_string/version.rb
26
+ homepage: https://github.com/Altivi/lz-string
27
+ licenses: []
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.7.6
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Ruby implementation of LZ-String compression algorithm
49
+ test_files: []