lz_string 0.1.0

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 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: []