oneliner 0.2.7 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -6
- data/ext/extconf.rb +24 -2
- data/ext/oneliner.c +1780 -0
- data/ext/oneliner.h +4 -0
- data/tests/string_test.rb +19 -0
- data/tests/superstring_benchmark.rb +7 -5
- data/tests/superstring_test.rb +41 -32
- metadata +8 -7
- data/ext/oneliner_ext.c +0 -289
- data/lib/oneliner.rb +0 -21
- data/lib/oneliner/superstring.rb +0 -385
data/README
CHANGED
@@ -5,14 +5,15 @@ See http://en.wikipedia.org/wiki/Online_codes
|
|
5
5
|
== Dependencies:
|
6
6
|
|
7
7
|
Oneliner::SuperString:: openssl: http://www.openssl.org/
|
8
|
+
Oneliner::SuperString:: glib: http://www.gtk.org/download/
|
8
9
|
|
9
10
|
== Sub packages:
|
10
11
|
|
11
|
-
Oneliner::SuperString:: A
|
12
|
+
Oneliner::SuperString:: A class that has the super power of Online Coding.
|
12
13
|
|
13
14
|
== Usage:
|
14
15
|
|
15
|
-
You create Oneliner::SuperStrings
|
16
|
+
You create Oneliner::SuperStrings with a regular String as argument, then you use Oneliner::SuperString#encode(size_of_chunk) to get Online Coded data from them.
|
16
17
|
|
17
18
|
Then you use Oneliner::SuperString#decode!(chunk) on a new Oneliner::SuperString to recreate the data from the original String. Only a few extra percent (around 10 - my randomness seems to be suboptimal) is needed to recreate the original data this way.
|
18
19
|
|
@@ -30,8 +31,5 @@ Then you use Oneliner::SuperString#decode!(chunk) on a new Oneliner::SuperString
|
|
30
31
|
redundant_packages << s2.encode(256)
|
31
32
|
redundant_packages << s2.encode(256)
|
32
33
|
redundant_packages << s2.encode(256)
|
33
|
-
|
34
|
-
while index < redundant_packages.size && !s.decode!(redundant_packages[index])
|
35
|
-
index += 1
|
36
|
-
end
|
34
|
+
nil while s.decode!(redundant_packages.shift)
|
37
35
|
assert_equal(s2, s)
|
data/ext/extconf.rb
CHANGED
@@ -28,6 +28,28 @@ unless have_library('ssl')
|
|
28
28
|
crash "libssl needed"
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
unless find_executable("pkg-config")
|
32
|
+
crash("pkg-config needed")
|
33
|
+
end
|
34
|
+
|
35
|
+
unless have_library('glib-2.0')
|
36
|
+
crash "libglib-2.0 needed"
|
37
|
+
end
|
38
|
+
|
39
|
+
if ARGV.include?("-d")
|
40
|
+
$CFLAGS += " -D ONELINER_DEBUG"
|
41
|
+
end
|
42
|
+
|
43
|
+
if ARGV.include?("-O0")
|
44
|
+
$CFLAGS.gsub!(/-O./, "-O0")
|
45
|
+
else
|
46
|
+
$CFLAGS.gsub!(/-O./, "-O3")
|
47
|
+
end
|
48
|
+
|
49
|
+
if ARGV.include?("-gdb")
|
50
|
+
$CFLAGS += " -g -gdwarf-2 -g3"
|
51
|
+
end
|
52
|
+
|
53
|
+
$CFLAGS += " " + `pkg-config --cflags --libs glib-2.0`.strip
|
32
54
|
|
33
|
-
create_makefile("
|
55
|
+
create_makefile("oneliner")
|
data/ext/oneliner.c
ADDED
@@ -0,0 +1,1780 @@
|
|
1
|
+
// Archipelago - a distributed computing toolkit for ruby
|
2
|
+
// Copyright (C) 2007 Martin Kihlgren <zond at troja dot ath dot cx>
|
3
|
+
//
|
4
|
+
// This program is free software; you can redistribute it and/or
|
5
|
+
// modify it under the terms of the GNU General Public License
|
6
|
+
// as published by the Free Software Foundation; either version 2
|
7
|
+
// of the License, or (at your option) any later version.
|
8
|
+
//
|
9
|
+
// This program is distributed in the hope that it will be useful,
|
10
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
// GNU General Public License for more details.
|
13
|
+
//
|
14
|
+
// You should have received a copy of the GNU General Public License
|
15
|
+
// along with this program; if not, write to the Free Software
|
16
|
+
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
|
18
|
+
//
|
19
|
+
// Interested in how the hell this load of bollocks works?
|
20
|
+
// Begin by reading up on online codes at http://en.wikipedia.org/wiki/Online_codes, then
|
21
|
+
// read doc/architecture.txt in this repository.
|
22
|
+
//
|
23
|
+
|
24
|
+
#include "ruby.h"
|
25
|
+
#include <limits.h>
|
26
|
+
#include <openssl/aes.h>
|
27
|
+
#include <glib.h>
|
28
|
+
#include <stdlib.h>
|
29
|
+
#include <math.h>
|
30
|
+
#include <sys/time.h>
|
31
|
+
#include "oneliner.h"
|
32
|
+
|
33
|
+
//
|
34
|
+
// The classes
|
35
|
+
//
|
36
|
+
|
37
|
+
// The Oneliner::SuperString class, the one that does all the actual job.
|
38
|
+
static VALUE rb_superstring;
|
39
|
+
// The Oneliner::Chunk class, only for debugging purposes.
|
40
|
+
static VALUE rb_chunk;
|
41
|
+
|
42
|
+
//
|
43
|
+
// Utility macros.
|
44
|
+
//
|
45
|
+
|
46
|
+
//
|
47
|
+
// If we have debug turned on when compiling, lets do stuff with all these debug macros.
|
48
|
+
//
|
49
|
+
#ifdef ONELINER_DEBUG
|
50
|
+
// The indentation of DBEUG messages.
|
51
|
+
static guint32 DEBUG_indentation = 0;
|
52
|
+
// Only execute s if debugging.
|
53
|
+
#define IFDEBUG(s) s
|
54
|
+
// Make the indentation of normal DEBUG messages one greater.
|
55
|
+
#define INDENT indentation++;
|
56
|
+
// Make the indentation of normal DEBUG messages one less.
|
57
|
+
#define UNINDENT indentation--;
|
58
|
+
// Warn if x is NULL.
|
59
|
+
#define NULL_WARN(x) if ((x) == NULL) DEBUG("x is NULL!!!");
|
60
|
+
// Indent DEBUG_indentation spaces and print the debug message.
|
61
|
+
#define DEBUG(s, ...) { \
|
62
|
+
guint32 _indentation_tmp; \
|
63
|
+
fprintf(stderr, "DEBUG: "); \
|
64
|
+
for (indentation_tmp = 0; indentation_tmp < DEBUG_indentation; indentation_tmp++) fprintf(stderr, " "); \
|
65
|
+
fprintf(stderr, s, ## __VA_ARGS__); \
|
66
|
+
fprintf(stderr, "\n"); \
|
67
|
+
fflush(NULL); }
|
68
|
+
// Print out the byte in str of length len as zeroes and ones.
|
69
|
+
#define BITSTRING_DEBUG(msg,str,len) { \
|
70
|
+
fprintf(stderr, "DEBUG: %s: ", (msg)); \
|
71
|
+
rb_funcall(rb_const_get(rb_cObject, rb_intern("Kernel")), \
|
72
|
+
rb_intern("print"), \
|
73
|
+
1, \
|
74
|
+
rb_funcall(rb_funcall(rb_funcall(rb_str_new((gchar *) (str), (len)), \
|
75
|
+
rb_intern("unpack"), \
|
76
|
+
1, \
|
77
|
+
rb_str_new2("b*")), \
|
78
|
+
rb_intern("first"), \
|
79
|
+
0), \
|
80
|
+
rb_intern("gsub"), \
|
81
|
+
2, \
|
82
|
+
rb_funcall(rb_const_get(rb_cObject, rb_intern("Regexp")), \
|
83
|
+
rb_intern("new"), \
|
84
|
+
1, \
|
85
|
+
rb_str_new2("(.{4,4})")), \
|
86
|
+
rb_str_new2("\\1,"))); \
|
87
|
+
fprintf(stderr, "\n"); \
|
88
|
+
fflush(NULL); }
|
89
|
+
// Print out the text in str of length len as a ruby inspected string.
|
90
|
+
#define STRING_DEBUG(msg,str,len) { \
|
91
|
+
fprintf(stderr, "DEBUG: %s: ", (msg)); \
|
92
|
+
rb_funcall(rb_const_get(rb_cObject, rb_intern("Kernel")), rb_intern("print"), 1, rb_funcall(rb_str_new((gchar *) (str), (len)), rb_intern("inspect"), 0)); \
|
93
|
+
fprintf(stderr, "\n"); \
|
94
|
+
fflush(NULL); }
|
95
|
+
//
|
96
|
+
// If we dont have debug turned on while compiling, just replace them with empty semicolons so as not to confuse the compiler.
|
97
|
+
//
|
98
|
+
#else
|
99
|
+
#define INDENT ;
|
100
|
+
#define UNINDENT ;
|
101
|
+
#define DEBUG(s, ...) ;
|
102
|
+
#define BITSTRING_DEBUG(msg,str,len) ;
|
103
|
+
#define IFDEBUG(s) ;
|
104
|
+
#endif
|
105
|
+
|
106
|
+
//
|
107
|
+
// Just iterate over ary freeing all content.
|
108
|
+
//
|
109
|
+
#define FREE_ARRAY_WITH_STRINGS(ary) { \
|
110
|
+
guint32 _free_ary_with_strings_int; \
|
111
|
+
for (_free_ary_with_strings_int = 0; \
|
112
|
+
_free_ary_with_strings_int < (ary)->len; \
|
113
|
+
_free_ary_with_strings_int++) { \
|
114
|
+
if (g_array_index((ary), guint8 *, _free_ary_with_strings_int) != NULL) \
|
115
|
+
g_free(g_array_index((ary), guint8 *, _free_ary_with_strings_int)); \
|
116
|
+
} \
|
117
|
+
g_array_free(ary, TRUE); \
|
118
|
+
}
|
119
|
+
// Returns the number of characters needed to print out the number i as a decimal number.
|
120
|
+
#define CHARS_FOR(i) ((guint32) (log10((gdouble) (i))) + 1)
|
121
|
+
// Returns a random number between 0 and max.
|
122
|
+
#define RANDOM(context,max) (oneliner_context_random(context) % (max))
|
123
|
+
// Returns a random float between >=0 and < 1.
|
124
|
+
#define RANDFLOAT(context) ( (gdouble) ( (guint32) oneliner_context_random(context) ) ) / ( (gdouble) G_MAXUINT32 )
|
125
|
+
// Will define a oneliner_superstring * named str and fetch the pointer from rb_obj into it.
|
126
|
+
#define RB_ONELINER(rb_obj,str) \
|
127
|
+
oneliner_superstring *str; \
|
128
|
+
Data_Get_Struct(rb_obj, oneliner_superstring, str);
|
129
|
+
// Will allocate a zeroed string of len characters for dst and copy src into it.
|
130
|
+
#define ALLOC_COPY8(dst,src,len) { \
|
131
|
+
(dst) = g_new0(guint8, (len) + 1); \
|
132
|
+
memcpy((dst), (src), sizeof(guint8) * (len)); }
|
133
|
+
|
134
|
+
// The Q constant of the algorithm (see http://en.wikipedia.org/wiki/Online_codes)
|
135
|
+
#define Q 3
|
136
|
+
// The E constant of the algorithm (see http://en.wikipedia.org/wiki/Online_codes)
|
137
|
+
#define E 0.01
|
138
|
+
|
139
|
+
//
|
140
|
+
// The c representation of a superstring.
|
141
|
+
//
|
142
|
+
typedef struct {
|
143
|
+
// The data_blocks of this superstring.
|
144
|
+
GArray *data_blocks;
|
145
|
+
// The aux blocks of this superstring.
|
146
|
+
GArray *aux_blocks;
|
147
|
+
// Our graph of check blocks.
|
148
|
+
GArray *check_block_graph;
|
149
|
+
// Our graph of aux blocks for the source blocks.
|
150
|
+
GArray *aux_block_graph;
|
151
|
+
// Our graph of aux blocks for the aux blocks themselves.
|
152
|
+
GArray *known_aux_blocks;
|
153
|
+
// The list of found blocks to analyze.
|
154
|
+
GList *to_analyze;
|
155
|
+
// The list of xor_blocks to free.
|
156
|
+
GList *to_free;
|
157
|
+
// The size of each block in bits.
|
158
|
+
guint32 block_size;
|
159
|
+
// The number of guint8's needed to contain those bits.
|
160
|
+
guint32 n_chars_in_block;
|
161
|
+
// The length of the original data.
|
162
|
+
guint32 data_len;
|
163
|
+
// The number of data_blocks needed to contain that data.
|
164
|
+
guint32 n_data_blocks_needed;
|
165
|
+
// The number of bytes needed to store those data_blocks.
|
166
|
+
guint32 n_bytes_for_data_blocks;
|
167
|
+
// The number of aux blocks needed for those blocks.
|
168
|
+
guint32 n_aux_blocks_needed;
|
169
|
+
// The number of check blocks we have decoded so far.
|
170
|
+
guint32 n_seen_check_blocks;
|
171
|
+
// Whether we have decided already that we are done decoding.
|
172
|
+
gboolean decode_done;
|
173
|
+
} oneliner_superstring;
|
174
|
+
|
175
|
+
//
|
176
|
+
// An as yet mysterious block.
|
177
|
+
//
|
178
|
+
typedef struct {
|
179
|
+
gboolean initialized;
|
180
|
+
guint8 *sum;
|
181
|
+
GHashTable *source_blocks;
|
182
|
+
oneliner_superstring *str;
|
183
|
+
gint32 index;
|
184
|
+
} oneliner_xor_block;
|
185
|
+
|
186
|
+
//
|
187
|
+
// An insertion to do into the graph of a superstring.
|
188
|
+
//
|
189
|
+
typedef struct {
|
190
|
+
guint32 source_block_nr;
|
191
|
+
oneliner_xor_block *check_block;
|
192
|
+
} oneliner_graph_insertion;
|
193
|
+
|
194
|
+
//
|
195
|
+
// A random context.
|
196
|
+
//
|
197
|
+
typedef guint8 oneliner_context;
|
198
|
+
|
199
|
+
// Just to solve a few dependency problems between the functions.
|
200
|
+
static guint8 *
|
201
|
+
oneliner_superstring_get_combined_block(oneliner_superstring *str, guint32 block_nr);
|
202
|
+
static void
|
203
|
+
oneliner_superstring_analyze(oneliner_superstring *str, guint32 found_block_nr);
|
204
|
+
|
205
|
+
//
|
206
|
+
// Encrypt the context again
|
207
|
+
//
|
208
|
+
static void
|
209
|
+
oneliner_context_randomize(oneliner_context *context)
|
210
|
+
{
|
211
|
+
AES_KEY key;
|
212
|
+
|
213
|
+
AES_set_encrypt_key((guint8 *) "0123456789012345", 128, &key);
|
214
|
+
|
215
|
+
AES_encrypt((guint8 *) context + 4,
|
216
|
+
(guint8 *) context + 4,
|
217
|
+
&key);
|
218
|
+
* (guint32 *) context = 1;
|
219
|
+
}
|
220
|
+
|
221
|
+
//
|
222
|
+
// Fill the buffer of context with seed and randomize it.
|
223
|
+
//
|
224
|
+
static gint32
|
225
|
+
oneliner_context_seed(oneliner_context *context, gint32 seed)
|
226
|
+
{
|
227
|
+
gint32 tmp;
|
228
|
+
|
229
|
+
for (tmp = 1; tmp < 5; tmp++)
|
230
|
+
( (gint32 *) context )[tmp] = seed;
|
231
|
+
|
232
|
+
oneliner_context_randomize(context);
|
233
|
+
|
234
|
+
return seed;
|
235
|
+
}
|
236
|
+
|
237
|
+
//
|
238
|
+
// Return an int that is the next random in the context
|
239
|
+
//
|
240
|
+
static gint32
|
241
|
+
oneliner_context_random(oneliner_context *context)
|
242
|
+
{
|
243
|
+
gint32 *int_context = (gint32 *) context;
|
244
|
+
if (int_context[0] < 5) {
|
245
|
+
gint32 return_value = int_context[int_context[0]];
|
246
|
+
int_context[0]++;
|
247
|
+
return return_value;
|
248
|
+
} else {
|
249
|
+
oneliner_context_randomize(context);
|
250
|
+
return oneliner_context_random(context);
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
//
|
255
|
+
// Initialize a context.
|
256
|
+
//
|
257
|
+
static oneliner_context *
|
258
|
+
oneliner_context_new()
|
259
|
+
{
|
260
|
+
return (oneliner_context *) g_new0(guint8, 4 * 5);
|
261
|
+
}
|
262
|
+
|
263
|
+
//
|
264
|
+
// Get a random degree
|
265
|
+
//
|
266
|
+
static guint32
|
267
|
+
oneliner_context_get_degree(oneliner_context *context)
|
268
|
+
{
|
269
|
+
gdouble f;
|
270
|
+
guint32 tmp = 0;
|
271
|
+
|
272
|
+
f = RANDFLOAT(context);
|
273
|
+
while (f > 0) {
|
274
|
+
tmp++;
|
275
|
+
f = f - P[tmp];
|
276
|
+
}
|
277
|
+
return tmp;
|
278
|
+
}
|
279
|
+
|
280
|
+
//
|
281
|
+
// Make object into object ^ subject
|
282
|
+
//
|
283
|
+
static void
|
284
|
+
oneliner_string_xor(guint8 *object, guint8 *subject, guint32 len)
|
285
|
+
{
|
286
|
+
guint32 tmp;
|
287
|
+
|
288
|
+
#ifdef G_HAVE_GINT64
|
289
|
+
for (tmp = 0; tmp < len / 8; tmp++)
|
290
|
+
( (guint64 *) object )[tmp] = ( (guint64 *) object )[tmp] ^ ( (guint64 *) subject )[tmp];
|
291
|
+
for (tmp = tmp * 2; tmp < len / 4; tmp++)
|
292
|
+
( (guint32 *) object )[tmp] = ( (guint32 *) object )[tmp] ^ ( (guint32 *) subject )[tmp];
|
293
|
+
for (tmp = tmp * 4; tmp < len; tmp++)
|
294
|
+
object[tmp] = object[tmp] ^ subject[tmp];
|
295
|
+
#else
|
296
|
+
for (tmp = 0; tmp < len / 4; tmp++)
|
297
|
+
( (guint32 *) object )[tmp] = ( (guint32 *) object )[tmp] ^ ( (guint32 *) subject )[tmp];
|
298
|
+
for (tmp = tmp * 4; tmp < len; tmp++)
|
299
|
+
object[tmp] = object[tmp] ^ subject[tmp];
|
300
|
+
#endif
|
301
|
+
}
|
302
|
+
|
303
|
+
//
|
304
|
+
// Ruby wrapper for oneliner_string_xor. Will make the self String into self ^ the object String.
|
305
|
+
//
|
306
|
+
static VALUE
|
307
|
+
rb_oneliner_string_xor(VALUE self, VALUE object)
|
308
|
+
{
|
309
|
+
Check_Type(object, T_STRING);
|
310
|
+
rb_str_modify(self);
|
311
|
+
oneliner_string_xor((guint8 *) RSTRING(self)->ptr, (guint8 *) RSTRING(object)->ptr, MIN(RSTRING(self)->len, RSTRING(object)->len));
|
312
|
+
return self;
|
313
|
+
}
|
314
|
+
|
315
|
+
//
|
316
|
+
// Iterator used in the hash inspector.
|
317
|
+
//
|
318
|
+
static void
|
319
|
+
oneliner_int_hash_debug_iterator(gpointer key, gpointer value, gpointer user_data)
|
320
|
+
{
|
321
|
+
gchar **buf = (gchar **) user_data;
|
322
|
+
guint32 key_int = GPOINTER_TO_UINT(key);
|
323
|
+
guint32 value_int = GPOINTER_TO_UINT(value);
|
324
|
+
guint32 extra_size_needed = CHARS_FOR(key_int) + CHARS_FOR(value_int) + 6 + 1;
|
325
|
+
guint32 new_size_needed = strlen(*buf) + extra_size_needed;
|
326
|
+
*buf = g_realloc(*buf, new_size_needed);
|
327
|
+
snprintf(*buf + strlen(*buf), extra_size_needed, "%i => %i, ", key_int, value_int);
|
328
|
+
}
|
329
|
+
|
330
|
+
//
|
331
|
+
// A hash inspector for GHashTables that considers all hashes as storing ints.
|
332
|
+
//
|
333
|
+
static gchar *
|
334
|
+
oneliner_int_hash_to_s(GHashTable *hash)
|
335
|
+
{
|
336
|
+
gchar *buf;
|
337
|
+
gchar *base = "<GHashTable: size='' data='";
|
338
|
+
guint32 size_needed = strlen(base) + CHARS_FOR(g_hash_table_size(hash)) + CHARS_FOR(G_MAXUINT32) + 1;
|
339
|
+
buf = g_new(gchar, size_needed);
|
340
|
+
snprintf(buf, size_needed, "<GHashTable:%i size='%i' data='", GPOINTER_TO_UINT(hash), g_hash_table_size(hash));
|
341
|
+
g_hash_table_foreach(hash, oneliner_int_hash_debug_iterator, &buf);
|
342
|
+
size_needed = strlen(buf) + 3;
|
343
|
+
buf = g_realloc(buf, size_needed);
|
344
|
+
snprintf(buf + strlen(buf), 3, "'>");
|
345
|
+
return buf;
|
346
|
+
}
|
347
|
+
|
348
|
+
//
|
349
|
+
// Prints out an inspection of hash.
|
350
|
+
//
|
351
|
+
static void
|
352
|
+
oneliner_int_hash_debug(GHashTable *hash)
|
353
|
+
{
|
354
|
+
gchar *s = oneliner_int_hash_to_s(hash);
|
355
|
+
DEBUG(s);
|
356
|
+
g_free(s);
|
357
|
+
}
|
358
|
+
|
359
|
+
// Returns if this xor_block is finished.
|
360
|
+
#define XOR_BLOCK_FINISHED(xor_block) ((xor_block)->initialized && \
|
361
|
+
(g_hash_table_size((xor_block)->source_blocks) == 1) && \
|
362
|
+
((oneliner_xor_block_last_uses((xor_block)) % 2) == 1))
|
363
|
+
// Returns if this xor_block is empty.
|
364
|
+
#define XOR_BLOCK_EMPTY(xor_block) (g_hash_table_size((xor_block)->source_blocks) == 0)
|
365
|
+
// Returns if this xor_block is an aux block.
|
366
|
+
#define XOR_BLOCK_IS_AUX(xor_block) ((xor_block)->index > -1)
|
367
|
+
// Returns if this xor_block is a check block.
|
368
|
+
#define XOR_BLOCK_IS_CHECK(xor_block) ((xor_block)->index == -1)
|
369
|
+
// Returns a constant string for the type of this xor_block.
|
370
|
+
#define XOR_TYPE(xor_block) (XOR_BLOCK_IS_AUX((xor_block)) ? "aux_block" : "check_block")
|
371
|
+
|
372
|
+
//
|
373
|
+
// An inspector for xor_blocks.
|
374
|
+
//
|
375
|
+
static gchar *
|
376
|
+
oneliner_xor_block_to_s(oneliner_xor_block *xor_block)
|
377
|
+
{
|
378
|
+
gchar *rval;
|
379
|
+
gchar *source_blocks_buf;
|
380
|
+
gchar *base = "<xor_block: type='' index='' initialized='' sum='' source_blocks='";
|
381
|
+
guint32 size_needed = strlen(base) + 1 + 1 + CHARS_FOR(xor_block->index) + 1 + xor_block->str->n_chars_in_block + CHARS_FOR(G_MAXUINT32) + 1 + strlen(XOR_TYPE(xor_block));
|
382
|
+
rval = g_new(gchar, size_needed);
|
383
|
+
snprintf(rval, size_needed, "<xor_block:%i type='%s' index='%i' initialized='%i' sum='%i' source_blocks='", GPOINTER_TO_UINT(xor_block), XOR_TYPE(xor_block), xor_block->index, xor_block->initialized, *(xor_block->sum));
|
384
|
+
source_blocks_buf = oneliner_int_hash_to_s(xor_block->source_blocks);
|
385
|
+
size_needed = strlen(rval) + strlen(source_blocks_buf) + 4;
|
386
|
+
rval = g_realloc(rval, size_needed);
|
387
|
+
sprintf(rval + strlen(rval), "%s'>", source_blocks_buf);
|
388
|
+
g_free(source_blocks_buf);
|
389
|
+
return rval;
|
390
|
+
}
|
391
|
+
|
392
|
+
//
|
393
|
+
// Prints out an inspection for this xor_block.
|
394
|
+
//
|
395
|
+
static void
|
396
|
+
oneliner_xor_block_debug(oneliner_xor_block *xor_block)
|
397
|
+
{
|
398
|
+
gchar *s = oneliner_xor_block_to_s(xor_block);
|
399
|
+
DEBUG(s);
|
400
|
+
g_free(s);
|
401
|
+
}
|
402
|
+
|
403
|
+
//
|
404
|
+
// Allocates a new xor_block containing data of len, which is initialized and bound to str at index.
|
405
|
+
//
|
406
|
+
static oneliner_xor_block *
|
407
|
+
oneliner_xor_block_new(guint8 *data, guint32 len, gboolean initialized, oneliner_superstring *str, gint32 index)
|
408
|
+
{
|
409
|
+
oneliner_xor_block *rval = g_new0(oneliner_xor_block, 1);
|
410
|
+
ALLOC_COPY8(rval->sum, data, len);
|
411
|
+
rval->initialized = initialized;
|
412
|
+
rval->source_blocks = g_hash_table_new(NULL, NULL);
|
413
|
+
rval->str = str;
|
414
|
+
rval->index = index;
|
415
|
+
return rval;
|
416
|
+
}
|
417
|
+
|
418
|
+
//
|
419
|
+
// Remove the dependency on the source_block_nr from ary for this xor_block.
|
420
|
+
//
|
421
|
+
static void
|
422
|
+
oneliner_xor_block_free_and_remove_from_array(oneliner_xor_block *xor_block, GArray *ary, guint32 source_block_nr)
|
423
|
+
{
|
424
|
+
GHashTable *hash;
|
425
|
+
|
426
|
+
if (ary != NULL) {
|
427
|
+
if ((hash = g_array_index(ary, GHashTable *, source_block_nr)) != NULL) {
|
428
|
+
if (g_hash_table_lookup_extended(hash, xor_block, NULL, NULL)) {
|
429
|
+
g_hash_table_remove(hash, xor_block);
|
430
|
+
} else {
|
431
|
+
DEBUG("it doesnt exist as a dependency :/ dependencies are:");
|
432
|
+
rb_raise(rb_eRuntimeError, "We have a serious problem with the internal state, an xor_block that depended on a data/aux block wasnt referenced back!");
|
433
|
+
}
|
434
|
+
} else {
|
435
|
+
DEBUG("no hash for that source block exists :/");
|
436
|
+
rb_raise(rb_eRuntimeError, "We have a serious problem with the internal state, the source block for an xor_block that we want to remove as a dependency doesnt have a dependency hash!");
|
437
|
+
}
|
438
|
+
} else {
|
439
|
+
DEBUG("no array exists :/");
|
440
|
+
rb_raise(rb_eRuntimeError, "We have a serious problem with the internal state, the oneliner_superstring an xor_block is attached to doesnt have the array we want to remove the dependencies of the xor_block from!");
|
441
|
+
}
|
442
|
+
}
|
443
|
+
|
444
|
+
//
|
445
|
+
// Iterator for the freeing of xor_blocks.
|
446
|
+
//
|
447
|
+
// Will remove the dependency from the proper array in the oneliner_superstring of
|
448
|
+
// this xor_block depending on it being aux or check block.
|
449
|
+
//
|
450
|
+
static void
|
451
|
+
oneliner_xor_block_free_and_remove(gpointer key, gpointer data, gpointer user_data)
|
452
|
+
{
|
453
|
+
guint32 source_block_nr = GPOINTER_TO_UINT(key);
|
454
|
+
oneliner_xor_block *xor_block = (oneliner_xor_block *) user_data;
|
455
|
+
|
456
|
+
INDENT;
|
457
|
+
|
458
|
+
if (XOR_BLOCK_IS_CHECK(xor_block)) {
|
459
|
+
DEBUG("removing _%i_ as a dependency from it in check_block_graph", source_block_nr);
|
460
|
+
oneliner_xor_block_free_and_remove_from_array(xor_block, xor_block->str->check_block_graph, source_block_nr);
|
461
|
+
} else {
|
462
|
+
DEBUG("removing _%i_ as a dependency from it in aux_block_graph", source_block_nr);
|
463
|
+
oneliner_xor_block_free_and_remove_from_array(xor_block, xor_block->str->aux_block_graph, source_block_nr);
|
464
|
+
}
|
465
|
+
|
466
|
+
UNINDENT;
|
467
|
+
}
|
468
|
+
|
469
|
+
//
|
470
|
+
// Free the xor_block, and if free_dependencies also remove all its dependencies from the arrays
|
471
|
+
// of its oneliner_superstring.
|
472
|
+
//
|
473
|
+
static void
|
474
|
+
oneliner_xor_block_free(oneliner_xor_block *xor_block, gboolean free_dependencies)
|
475
|
+
{
|
476
|
+
INDENT;
|
477
|
+
DEBUG("freeing %s %i", XOR_TYPE(xor_block), GPOINTER_TO_UINT(xor_block));
|
478
|
+
g_free(xor_block->sum);
|
479
|
+
if (free_dependencies) {
|
480
|
+
g_hash_table_foreach(xor_block->source_blocks, oneliner_xor_block_free_and_remove, xor_block);
|
481
|
+
}
|
482
|
+
g_hash_table_destroy(xor_block->source_blocks);
|
483
|
+
if (free_dependencies && XOR_BLOCK_IS_AUX(xor_block) && xor_block->str->known_aux_blocks != NULL)
|
484
|
+
g_array_index(xor_block->str->known_aux_blocks, oneliner_xor_block *, xor_block->index) = NULL;
|
485
|
+
g_free(xor_block);
|
486
|
+
UNINDENT;
|
487
|
+
}
|
488
|
+
|
489
|
+
//
|
490
|
+
// Add a dependency for source_block_nr for this xor_block.
|
491
|
+
//
|
492
|
+
static void
|
493
|
+
oneliner_xor_block_add(oneliner_xor_block *xor_block, guint32 source_block_nr)
|
494
|
+
{
|
495
|
+
g_hash_table_insert(xor_block->source_blocks,
|
496
|
+
GUINT_TO_POINTER(source_block_nr),
|
497
|
+
GUINT_TO_POINTER(GPOINTER_TO_UINT(g_hash_table_lookup(xor_block->source_blocks,
|
498
|
+
GUINT_TO_POINTER(source_block_nr))) + 1));
|
499
|
+
}
|
500
|
+
|
501
|
+
//
|
502
|
+
// Set the sum of this xor_block to sum of length len. Will also set the xor_block to initialized.
|
503
|
+
//
|
504
|
+
static void
|
505
|
+
oneliner_xor_block_set_sum(oneliner_xor_block *xor_block, guint8 *sum, guint32 len)
|
506
|
+
{
|
507
|
+
oneliner_string_xor(xor_block->sum, sum, len);
|
508
|
+
xor_block->initialized = TRUE;
|
509
|
+
}
|
510
|
+
|
511
|
+
//
|
512
|
+
// The iterator used by xor_block_last_source_block.
|
513
|
+
//
|
514
|
+
static void
|
515
|
+
oneliner_xor_block_last_source_block_nr_iterator(gpointer key, gpointer data, gpointer user_data)
|
516
|
+
{
|
517
|
+
* (guint32 *) user_data = GPOINTER_TO_UINT(key);
|
518
|
+
}
|
519
|
+
|
520
|
+
//
|
521
|
+
// Returns the last source_block_nr that this xor_block depends on.
|
522
|
+
//
|
523
|
+
static guint32
|
524
|
+
oneliner_xor_block_last_source_block_nr(oneliner_xor_block *xor_block)
|
525
|
+
{
|
526
|
+
guint32 source_block_nr;
|
527
|
+
g_hash_table_foreach(xor_block->source_blocks, oneliner_xor_block_last_source_block_nr_iterator, &source_block_nr);
|
528
|
+
return source_block_nr;
|
529
|
+
}
|
530
|
+
|
531
|
+
//
|
532
|
+
// The iterator used by xor_block_last_uses.
|
533
|
+
//
|
534
|
+
static void
|
535
|
+
oneliner_xor_block_last_uses_iterator(gpointer key, gpointer data, gpointer user_data)
|
536
|
+
{
|
537
|
+
* (guint32 *) user_data = GPOINTER_TO_UINT(data);
|
538
|
+
}
|
539
|
+
|
540
|
+
//
|
541
|
+
// Returns the number of times this xor_block depends on its last source block.
|
542
|
+
//
|
543
|
+
static guint32
|
544
|
+
oneliner_xor_block_last_uses(oneliner_xor_block *xor_block)
|
545
|
+
{
|
546
|
+
guint32 uses;
|
547
|
+
g_hash_table_foreach(xor_block->source_blocks, oneliner_xor_block_last_uses_iterator, &uses);
|
548
|
+
return uses;
|
549
|
+
}
|
550
|
+
|
551
|
+
//
|
552
|
+
// XOR the sum of xor_block with found_block_nr from the oneliner_superstring of xor_block the
|
553
|
+
// requisite nr of times and then remove the dependency.
|
554
|
+
//
|
555
|
+
static void
|
556
|
+
oneliner_xor_block_apply(oneliner_xor_block *xor_block, guint32 found_block_nr)
|
557
|
+
{
|
558
|
+
guint32 uses;
|
559
|
+
guint32 tmp;
|
560
|
+
|
561
|
+
INDENT;
|
562
|
+
uses = GPOINTER_TO_UINT(g_hash_table_lookup(xor_block->source_blocks, GUINT_TO_POINTER(found_block_nr)));
|
563
|
+
|
564
|
+
if (uses < 1) {
|
565
|
+
DEBUG("its not used by this xor_block!!! :O");
|
566
|
+
IFDEBUG(oneliner_xor_block_debug(xor_block));
|
567
|
+
rb_raise(rb_eRuntimeError, "We have a serious problem with the internal state, the source block being applied to an xor_block doesnt seem to be included in it!");
|
568
|
+
}
|
569
|
+
|
570
|
+
if (uses % 2 == 1)
|
571
|
+
oneliner_string_xor(xor_block->sum, oneliner_superstring_get_combined_block(xor_block->str, found_block_nr), xor_block->str->n_chars_in_block);
|
572
|
+
|
573
|
+
g_hash_table_remove(xor_block->source_blocks, GUINT_TO_POINTER(found_block_nr));
|
574
|
+
UNINDENT;
|
575
|
+
}
|
576
|
+
|
577
|
+
//
|
578
|
+
// Create a new graph_insertion of check_block for source_block_nr.
|
579
|
+
//
|
580
|
+
static oneliner_graph_insertion *
|
581
|
+
oneliner_graph_insertion_new(oneliner_xor_block *check_block, guint32 source_block_nr)
|
582
|
+
{
|
583
|
+
oneliner_graph_insertion *rval = g_new0(oneliner_graph_insertion, 1);
|
584
|
+
rval->check_block = check_block;
|
585
|
+
rval->source_block_nr = source_block_nr;
|
586
|
+
return rval;
|
587
|
+
}
|
588
|
+
|
589
|
+
//
|
590
|
+
// Remove this graph insertion for block_nr and insertion, and remove its xor_block without
|
591
|
+
// going for its dependencies (which shouldnt exist, anyway).
|
592
|
+
//
|
593
|
+
static gboolean
|
594
|
+
oneliner_graph_insertion_free_with_check_block(gpointer block_nr, gpointer insertion, gpointer user_data)
|
595
|
+
{
|
596
|
+
oneliner_xor_block_free(( (oneliner_graph_insertion *) insertion )->check_block, FALSE);
|
597
|
+
g_free(insertion);
|
598
|
+
return TRUE;
|
599
|
+
}
|
600
|
+
|
601
|
+
//
|
602
|
+
// Insert the given insertion into the given oneliner_superstring.
|
603
|
+
//
|
604
|
+
static gboolean
|
605
|
+
oneliner_insertion_execute(gpointer block_nr, gpointer insertion, gpointer string)
|
606
|
+
{
|
607
|
+
oneliner_graph_insertion *ins = (oneliner_graph_insertion *) insertion;
|
608
|
+
oneliner_superstring *str = (oneliner_superstring *) string;
|
609
|
+
GHashTable *hash;
|
610
|
+
|
611
|
+
INDENT;
|
612
|
+
DEBUG("inserting check_block %i as a dependency for block _%i_", GPOINTER_TO_UINT(ins->check_block), ins->source_block_nr);
|
613
|
+
|
614
|
+
if ((hash = g_array_index(str->check_block_graph, GHashTable *, ins->source_block_nr)) == NULL) {
|
615
|
+
hash = g_array_index(str->check_block_graph, GHashTable *, ins->source_block_nr) = g_hash_table_new(NULL, NULL);
|
616
|
+
}
|
617
|
+
|
618
|
+
g_hash_table_insert(hash, ins->check_block, GUINT_TO_POINTER(ins->source_block_nr));
|
619
|
+
|
620
|
+
g_free(insertion);
|
621
|
+
UNINDENT;
|
622
|
+
return TRUE;
|
623
|
+
}
|
624
|
+
|
625
|
+
|
626
|
+
//
|
627
|
+
// Return the block size in bits for a string of the given length.
|
628
|
+
//
|
629
|
+
static guint32
|
630
|
+
oneliner_superstring_get_block_size(guint32 len) {
|
631
|
+
if (len < 1024) {
|
632
|
+
return (guint32) ceil((len / 1024.0) * 8.0);
|
633
|
+
} else {
|
634
|
+
return ((len / 128) / 8) * 8;
|
635
|
+
}
|
636
|
+
}
|
637
|
+
|
638
|
+
//
|
639
|
+
// Fill *block with a block_size (bitwise) piece of *data from pos (bitwise).
|
640
|
+
//
|
641
|
+
static void
|
642
|
+
oneliner_superstring_get_block_from_data(guint8 *data, guint32 pos, guint32 block_size, guint8 *block)
|
643
|
+
{
|
644
|
+
//
|
645
|
+
// Block sizes 1-7 are tricky,
|
646
|
+
// but all other sizes are divisible by 8 and therefore ok to do with a simple memcpy.
|
647
|
+
//
|
648
|
+
if (block_size < 8) {
|
649
|
+
// If the whole block fits within one char then we cant assume that we have permission
|
650
|
+
// to read the char after it, but if it DOESNT then we MUST assume that we have permission
|
651
|
+
// to read the char after it. Therefore the below fork where we read a char or a short from the data.
|
652
|
+
if ((pos + block_size - 1) / 8 == pos / 8) {
|
653
|
+
*block = data[pos / 8];
|
654
|
+
*block = *block << (8 - ((pos + block_size) % 8)) % 8;
|
655
|
+
*block = *block >> 8 - block_size;
|
656
|
+
} else {
|
657
|
+
guint16 short_containing_block = * (guint16 *) (data + (pos / 8));
|
658
|
+
short_containing_block = short_containing_block << (8 - ((pos + block_size) % 8)) % 8;
|
659
|
+
short_containing_block = short_containing_block >> 16 - block_size;
|
660
|
+
*block = (guint8) short_containing_block;
|
661
|
+
}
|
662
|
+
} else {
|
663
|
+
memcpy(block, data + (pos / 8), sizeof(guint8) * (block_size / 8));
|
664
|
+
}
|
665
|
+
}
|
666
|
+
|
667
|
+
//
|
668
|
+
// Take *data and return a GArray * with all the block_size blocks it contains.
|
669
|
+
// Needs hints as to how many bytes we need to contain all blocks, how long *data is,
|
670
|
+
// how many chars each block needs and how many blocks we need in total.
|
671
|
+
//
|
672
|
+
static GArray *
|
673
|
+
oneliner_superstring_build_blocks_from_data(guint32 n_bytes_for_blocks,
|
674
|
+
guint32 data_len,
|
675
|
+
guint32 block_size,
|
676
|
+
guint32 n_chars_in_block,
|
677
|
+
guint32 n_blocks_needed,
|
678
|
+
guint8 *data)
|
679
|
+
{
|
680
|
+
guint32 block_nr;
|
681
|
+
guint8 *tmp_block;
|
682
|
+
guint8 tmp_data[n_bytes_for_blocks];
|
683
|
+
GArray *rval = g_array_new(FALSE, FALSE, sizeof(guint8 *));
|
684
|
+
|
685
|
+
g_array_set_size(rval, n_blocks_needed);
|
686
|
+
memcpy((gchar *) tmp_data, (gchar *) data, sizeof(guint8) * data_len);
|
687
|
+
for (block_nr = 0; block_nr < n_blocks_needed; block_nr++) {
|
688
|
+
guint32 pos = block_nr * block_size;
|
689
|
+
tmp_block = g_new0(guint8, n_chars_in_block + 1);
|
690
|
+
oneliner_superstring_get_block_from_data(tmp_data, pos, block_size, tmp_block);
|
691
|
+
g_array_index(rval, guint8 *, block_nr) = tmp_block;
|
692
|
+
}
|
693
|
+
|
694
|
+
return rval;
|
695
|
+
}
|
696
|
+
|
697
|
+
|
698
|
+
//
|
699
|
+
// Ensure that str->data_blocks contains a GArray with all the data_blocks of this data.
|
700
|
+
//
|
701
|
+
static void
|
702
|
+
oneliner_superstring_build_data_blocks(oneliner_superstring *str, guint8 *data)
|
703
|
+
{
|
704
|
+
str->data_blocks = oneliner_superstring_build_blocks_from_data(str->n_bytes_for_data_blocks,
|
705
|
+
str->data_len,
|
706
|
+
str->block_size,
|
707
|
+
str->n_chars_in_block,
|
708
|
+
str->n_data_blocks_needed,
|
709
|
+
data);
|
710
|
+
}
|
711
|
+
|
712
|
+
//
|
713
|
+
// Take the block_size (bitwise) content of *block and insert it in *data at block_nr.
|
714
|
+
//
|
715
|
+
static void
|
716
|
+
oneliner_superstring_set_data_from_block(guint8 *data, guint32 block_nr, guint32 block_size, guint8 *block)
|
717
|
+
{
|
718
|
+
//
|
719
|
+
// If the block size is less than 8 then we have some tricky business, otherwise
|
720
|
+
// we know that it is a multiple of 8, which makes it into a simple memcpy.
|
721
|
+
//
|
722
|
+
if (block_size < 8) {
|
723
|
+
// If the entire block fits within one byte then we can not assume that we can write
|
724
|
+
// the byte after, but if it doesnt then we MUST assume that we CAN write the byte
|
725
|
+
// after, therefore the below fork where we write a char or a long depending.
|
726
|
+
if ((block_nr * block_size) / 8 == (((block_nr + 1) * block_size) - 1) / 8) {
|
727
|
+
// Set the byte we want to write to the block content.
|
728
|
+
guint8 byte_to_write = *block;
|
729
|
+
// Left shift it enough so that it matches the segment of data we want to write.
|
730
|
+
byte_to_write = byte_to_write << (block_nr * block_size) % 8;
|
731
|
+
// Then OR the corresponding byte in the data with the byte to write. Since
|
732
|
+
// the data is supposed to be initialized with zeroes this ought to do the trick.
|
733
|
+
data[(block_nr * block_size) / 8] = data[(block_nr * block_size) / 8] | byte_to_write;
|
734
|
+
} else {
|
735
|
+
// Set the short we want to write to the block content.
|
736
|
+
guint16 short_to_write = (guint16) *block;
|
737
|
+
// Left shift it enough so that it matches the segment of data we want to write.
|
738
|
+
short_to_write = short_to_write << (block_nr * block_size) % 8;
|
739
|
+
// Then OR the corresponding short in the data with the short to write. Since
|
740
|
+
// the data is supposed to be initialized with zeroes this ought to do the trick.
|
741
|
+
* (guint16 *) (data + (block_nr * block_size) / 8) = * (guint16 *) (data + (block_nr * block_size) / 8) | short_to_write;
|
742
|
+
}
|
743
|
+
} else {
|
744
|
+
memcpy((gchar *) data + (block_nr * (block_size / 8)), (gchar *) block, sizeof(guint8) * (block_size / 8));
|
745
|
+
}
|
746
|
+
}
|
747
|
+
|
748
|
+
//
|
749
|
+
// Take the given blocks of size block_size needing n_bytes_for_blocks to be stored completely and
|
750
|
+
// concatenate them into a string, then return the first data_len bytes of the result.
|
751
|
+
//
|
752
|
+
// If prepend_size is larger than 0 then the prepend string will be prepended to the result.
|
753
|
+
//
|
754
|
+
static guint8 *
|
755
|
+
oneliner_superstring_build_data_from_blocks(guint32 n_bytes_for_blocks,
|
756
|
+
guint32 data_len,
|
757
|
+
guint32 block_size,
|
758
|
+
GArray *blocks,
|
759
|
+
guint32 prepend_size,
|
760
|
+
guint8 *prepend)
|
761
|
+
{
|
762
|
+
guint32 index;
|
763
|
+
guint8 *tmp_data = g_new0(guint8, n_bytes_for_blocks + prepend_size + 1);
|
764
|
+
for (index = 0; index < blocks->len; index++) {
|
765
|
+
oneliner_superstring_set_data_from_block(tmp_data + prepend_size, index, block_size, g_array_index(blocks, guint8 *, index));
|
766
|
+
}
|
767
|
+
memcpy((gchar *) tmp_data, (gchar *) prepend, sizeof(guint8) * prepend_size);
|
768
|
+
return g_realloc(tmp_data, data_len);
|
769
|
+
}
|
770
|
+
|
771
|
+
//
|
772
|
+
// Return the guint8 * that the given *str describes with its data_blocks.
|
773
|
+
//
|
774
|
+
static guint8 *
|
775
|
+
oneliner_superstring_build_data(oneliner_superstring *str)
|
776
|
+
{
|
777
|
+
return oneliner_superstring_build_data_from_blocks(str->n_bytes_for_data_blocks,
|
778
|
+
str->data_len,
|
779
|
+
str->block_size,
|
780
|
+
str->data_blocks,
|
781
|
+
0,
|
782
|
+
NULL);
|
783
|
+
}
|
784
|
+
|
785
|
+
//
|
786
|
+
// Create the aux_blocks GArray for *str using its blocks and length.
|
787
|
+
//
|
788
|
+
static void
|
789
|
+
oneliner_superstring_build_aux_blocks(oneliner_superstring *str)
|
790
|
+
{
|
791
|
+
guint32 tmp;
|
792
|
+
oneliner_context *context = oneliner_context_new();
|
793
|
+
|
794
|
+
oneliner_context_seed(context, (gint32) str->data_len);
|
795
|
+
str->aux_blocks = g_array_new(FALSE, TRUE, sizeof(guint8 *));
|
796
|
+
g_array_set_size(str->aux_blocks, str->n_aux_blocks_needed);
|
797
|
+
|
798
|
+
for (tmp = 0; tmp < str->n_data_blocks_needed; tmp++) {
|
799
|
+
guint32 tmp2;
|
800
|
+
DEBUG("selecting aux_blocks for data block _%i_ (%i)", tmp, *g_array_index(str->data_blocks, gchar *, tmp));
|
801
|
+
for (tmp2 = 0; tmp2 < Q; tmp2++) {
|
802
|
+
guint32 aux_block_nr = (guint32) RANDOM(context, str->n_aux_blocks_needed);
|
803
|
+
if (g_array_index(str->aux_blocks, guint *, aux_block_nr) == NULL) {
|
804
|
+
ALLOC_COPY8(g_array_index(str->aux_blocks, guint8 *, aux_block_nr),
|
805
|
+
g_array_index(str->data_blocks, gchar *, tmp),
|
806
|
+
str->n_chars_in_block);
|
807
|
+
} else {
|
808
|
+
oneliner_string_xor(g_array_index(str->aux_blocks, guint8 *, aux_block_nr),
|
809
|
+
g_array_index(str->data_blocks, guint8 *, tmp),
|
810
|
+
str->n_chars_in_block);
|
811
|
+
}
|
812
|
+
DEBUG(" %i => sum=%i", aux_block_nr, *g_array_index(str->aux_blocks, guint8 *, aux_block_nr));
|
813
|
+
}
|
814
|
+
}
|
815
|
+
|
816
|
+
g_free(context);
|
817
|
+
}
|
818
|
+
|
819
|
+
//
|
820
|
+
// Initialize all the precalculated state of *str using data_len.
|
821
|
+
//
|
822
|
+
static void
|
823
|
+
oneliner_superstring_initialize(oneliner_superstring *str, guint32 data_len)
|
824
|
+
{
|
825
|
+
DEBUG("initializing string %i", GPOINTER_TO_UINT(str));
|
826
|
+
// Make sure the length of our data (our String superclass content) is set.
|
827
|
+
str->data_len = (guint32) data_len;
|
828
|
+
// Make sure the block size we deem reasonable for this data length is set.
|
829
|
+
str->block_size = oneliner_superstring_get_block_size(str->data_len);
|
830
|
+
// Make sure the number of chars needed to contain such a block is set.
|
831
|
+
str->n_chars_in_block = (guint32) ceil(str->block_size / 8.0);
|
832
|
+
// Make sure the number of data_blocks needed to contain this data is set.
|
833
|
+
str->n_data_blocks_needed = (guint32) ceil((str->data_len * 8.0) / str->block_size);
|
834
|
+
// Make sure the number of bytes needed to contain those data_blocks is set.
|
835
|
+
str->n_bytes_for_data_blocks = (guint32) ceil((str->n_data_blocks_needed * str->block_size) / 8.0);
|
836
|
+
// Make sure the number of aux blocks needed for those data_blocks is set.
|
837
|
+
str->n_aux_blocks_needed = (guint32) ceil(0.55 * Q * E * str->n_data_blocks_needed);
|
838
|
+
// Make sure the number of known check blocks so far is set.
|
839
|
+
str->n_seen_check_blocks = 0;
|
840
|
+
// Make sure we dont think we have decoded already.
|
841
|
+
str->decode_done = FALSE;
|
842
|
+
// Make sure we have an initialized to_analyze.
|
843
|
+
str->to_analyze = NULL;
|
844
|
+
// Make sure we have an initialized to_free.
|
845
|
+
str->to_free = NULL;
|
846
|
+
// Make sure our graphs are initialized empty.
|
847
|
+
str->check_block_graph = NULL;
|
848
|
+
str->known_aux_blocks = NULL;
|
849
|
+
str->aux_block_graph = NULL;
|
850
|
+
}
|
851
|
+
|
852
|
+
//
|
853
|
+
// Initialize a superstring using (possibly) a String to encode.
|
854
|
+
//
|
855
|
+
static VALUE
|
856
|
+
rb_oneliner_superstring_initialize(int argc, VALUE *argv, VALUE self)
|
857
|
+
{
|
858
|
+
RB_ONELINER(self, str);
|
859
|
+
|
860
|
+
if (argc > 1) {
|
861
|
+
rb_raise(rb_eRuntimeError, "Oneliner::SuperString.new(String s = nil) takes at most 1 argument.");
|
862
|
+
} else if (argc == 1) {
|
863
|
+
Check_Type(argv[0], T_STRING);
|
864
|
+
|
865
|
+
if (RSTRING(argv[0])->len < 1)
|
866
|
+
rb_raise(rb_eRuntimeError, "First argument to Oneliner::SuperString.new(String s = nil) must be a String of at least size 1 if given.");
|
867
|
+
|
868
|
+
oneliner_superstring_initialize(str, RSTRING(argv[0])->len);
|
869
|
+
|
870
|
+
// Make sure that we have our data_blocks calculated properly.
|
871
|
+
oneliner_superstring_build_data_blocks(str, (guint8 *) RSTRING(argv[0])->ptr);
|
872
|
+
oneliner_superstring_build_aux_blocks(str);
|
873
|
+
str->decode_done = TRUE;
|
874
|
+
}
|
875
|
+
return self;
|
876
|
+
}
|
877
|
+
|
878
|
+
//
|
879
|
+
// Returns whether *str is done decoding.
|
880
|
+
//
|
881
|
+
static VALUE
|
882
|
+
oneliner_superstring_decode_done(oneliner_superstring *str)
|
883
|
+
{
|
884
|
+
guint32 tmp;
|
885
|
+
if (str->decode_done)
|
886
|
+
return Qtrue;
|
887
|
+
if (str->data_blocks == NULL)
|
888
|
+
return Qfalse;
|
889
|
+
if (str->n_seen_check_blocks < str->n_data_blocks_needed)
|
890
|
+
return Qfalse;
|
891
|
+
for (tmp = 0; tmp < str->n_data_blocks_needed; tmp++)
|
892
|
+
if (g_array_index(str->data_blocks, guint8 *, tmp) == NULL)
|
893
|
+
return Qfalse;
|
894
|
+
str->decode_done = TRUE;
|
895
|
+
return Qtrue;
|
896
|
+
}
|
897
|
+
|
898
|
+
//
|
899
|
+
// Returns a GArray * containing all the blocks described by *chunk of length chunk_len
|
900
|
+
// in the context of *str (its block_size, n_chars_in_block etc).
|
901
|
+
//
|
902
|
+
static GArray *
|
903
|
+
oneliner_superstring_get_blocks_from_chunk(oneliner_superstring *str, guint8 *chunk, guint32 chunk_len)
|
904
|
+
{
|
905
|
+
return oneliner_superstring_build_blocks_from_data(chunk_len,
|
906
|
+
chunk_len,
|
907
|
+
str->block_size,
|
908
|
+
str->n_chars_in_block,
|
909
|
+
(chunk_len * 8) / str->block_size,
|
910
|
+
chunk);
|
911
|
+
}
|
912
|
+
|
913
|
+
//
|
914
|
+
// Return the guint8 * at either source or aux block with index block_nr in *str.
|
915
|
+
//
|
916
|
+
static guint8 *
|
917
|
+
oneliner_superstring_get_combined_block(oneliner_superstring *str, guint32 block_nr)
|
918
|
+
{
|
919
|
+
if (block_nr < str->n_data_blocks_needed)
|
920
|
+
return g_array_index(str->data_blocks, guint8 *, block_nr);
|
921
|
+
else
|
922
|
+
return g_array_index(str->aux_blocks, guint8 *, block_nr - str->n_data_blocks_needed);
|
923
|
+
}
|
924
|
+
|
925
|
+
//
|
926
|
+
// Set either the source of aux block at block_nr of *str to *block.
|
927
|
+
//
|
928
|
+
static gboolean
|
929
|
+
oneliner_superstring_set_combined_block(oneliner_superstring *str, guint32 block_nr, guint8 *block)
|
930
|
+
{
|
931
|
+
if (block_nr < str->n_data_blocks_needed && g_array_index(str->data_blocks, guint8 *, block_nr) == NULL) {
|
932
|
+
ALLOC_COPY8(g_array_index(str->data_blocks, guint8 *, block_nr), block, str->n_chars_in_block);
|
933
|
+
return TRUE;
|
934
|
+
} else if (block_nr >= str->n_data_blocks_needed && g_array_index(str->aux_blocks, guint8 *, block_nr - str->n_data_blocks_needed) == NULL) {
|
935
|
+
ALLOC_COPY8(g_array_index(str->aux_blocks, guint8 *, block_nr - str->n_data_blocks_needed), block, str->n_chars_in_block);
|
936
|
+
return TRUE;
|
937
|
+
}
|
938
|
+
return FALSE;
|
939
|
+
}
|
940
|
+
|
941
|
+
//
|
942
|
+
// Analyze if the given xor_block will be finished or empty after applying a newly found block,
|
943
|
+
// and set and queue for analysis if we found something new.
|
944
|
+
//
|
945
|
+
static void
|
946
|
+
oneliner_superstring_analyze_source_block_with_hash(gpointer key, gpointer data, gpointer user_data)
|
947
|
+
{
|
948
|
+
guint32 source_block_nr;
|
949
|
+
guint32 found_block_nr = GPOINTER_TO_UINT(data);
|
950
|
+
oneliner_xor_block *xor_block = (oneliner_xor_block *) key;
|
951
|
+
oneliner_superstring *str = (oneliner_superstring *) user_data;
|
952
|
+
|
953
|
+
INDENT;
|
954
|
+
DEBUG("found %i for _%i_ (%i)",
|
955
|
+
GPOINTER_TO_UINT(xor_block),
|
956
|
+
found_block_nr,
|
957
|
+
*oneliner_superstring_get_combined_block(str, found_block_nr));
|
958
|
+
INDENT;
|
959
|
+
IFDEBUG(oneliner_xor_block_debug(xor_block));
|
960
|
+
|
961
|
+
// Apply this new knowledge to it.
|
962
|
+
oneliner_xor_block_apply(xor_block,
|
963
|
+
found_block_nr);
|
964
|
+
|
965
|
+
DEBUG("after applying it got size %i", g_hash_table_size(xor_block->source_blocks));
|
966
|
+
|
967
|
+
//
|
968
|
+
// If that meant that it is finished then dance the dance of setting the combined block,
|
969
|
+
// removing it from the GList of check blocks for that combined block,
|
970
|
+
// and analyzing the results.
|
971
|
+
//
|
972
|
+
// Otherwise if it is empty, just free it and remove it.
|
973
|
+
//
|
974
|
+
// In fact, right after we have entered this FINISHED block, we will (since we
|
975
|
+
// call analyze on the resulting block, which leads here) check the same xor_block
|
976
|
+
// again, reach the EMPTY block, and then free the block.
|
977
|
+
//
|
978
|
+
if (XOR_BLOCK_FINISHED(xor_block)) {
|
979
|
+
|
980
|
+
// Find the source block that it defines.
|
981
|
+
source_block_nr = oneliner_xor_block_last_source_block_nr(xor_block);
|
982
|
+
|
983
|
+
DEBUG("it is finished! queueing %s %i to be freed!", XOR_TYPE(xor_block), GPOINTER_TO_UINT(xor_block));
|
984
|
+
|
985
|
+
// And free the xor block.
|
986
|
+
str->to_free = g_list_append(str->to_free, xor_block);
|
987
|
+
|
988
|
+
// And set it.
|
989
|
+
// And now analyze what the newly found source block led to.
|
990
|
+
// (Right, it can be an aux block as well, but my logic is still correct, I believe.)
|
991
|
+
if (oneliner_superstring_set_combined_block(str, source_block_nr, xor_block->sum)) {
|
992
|
+
DEBUG("_%i_ (%i) was unknown, setting and queueing %i to be analyzed! ******************",
|
993
|
+
source_block_nr,
|
994
|
+
*oneliner_superstring_get_combined_block(str, source_block_nr),
|
995
|
+
source_block_nr);
|
996
|
+
str->to_analyze = g_list_append(str->to_analyze, GUINT_TO_POINTER(source_block_nr));
|
997
|
+
}
|
998
|
+
|
999
|
+
} else if (XOR_BLOCK_EMPTY(xor_block)) {
|
1000
|
+
|
1001
|
+
DEBUG("it is empty, queueing %i to be freed!", GPOINTER_TO_UINT(xor_block));
|
1002
|
+
|
1003
|
+
// Free the check block.
|
1004
|
+
str->to_free = g_list_append(str->to_free, xor_block);
|
1005
|
+
|
1006
|
+
}
|
1007
|
+
UNINDENT;
|
1008
|
+
UNINDENT;
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
//
|
1012
|
+
// Go through the to_free queue of str and free all xor_blocks that need to be freed.
|
1013
|
+
//
|
1014
|
+
static void
|
1015
|
+
oneliner_superstring_free_as_necessary(oneliner_superstring *str)
|
1016
|
+
{
|
1017
|
+
GList *list_element = str->to_free;
|
1018
|
+
|
1019
|
+
INDENT;
|
1020
|
+
DEBUG("going through the to_free queue...");
|
1021
|
+
|
1022
|
+
while (list_element != NULL) {
|
1023
|
+
oneliner_xor_block_free((oneliner_xor_block *) list_element->data, TRUE);
|
1024
|
+
str->to_free = g_list_remove_link(str->to_free, list_element);
|
1025
|
+
g_list_free_1(list_element);
|
1026
|
+
list_element = str->to_free;
|
1027
|
+
}
|
1028
|
+
UNINDENT;
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
//
|
1032
|
+
// See if there exists a hash of dependent check blocks for found_block_nr in ary
|
1033
|
+
// and if it does, analyze the results of applying it to them, then free all the check
|
1034
|
+
// blocks and remove the hash.
|
1035
|
+
//
|
1036
|
+
static void
|
1037
|
+
oneliner_superstring_analyze_source_block_with_array(oneliner_superstring *str,
|
1038
|
+
GArray *ary,
|
1039
|
+
guint32 found_block_nr)
|
1040
|
+
{
|
1041
|
+
GHashTable *hash;
|
1042
|
+
|
1043
|
+
INDENT;
|
1044
|
+
DEBUG("analyze_source_block_with_array called with _%i_ (%i) and %s",
|
1045
|
+
found_block_nr,
|
1046
|
+
*oneliner_superstring_get_combined_block(str, found_block_nr),
|
1047
|
+
ary == str->check_block_graph ? "check_block_graph" : "aux_block_graph");
|
1048
|
+
|
1049
|
+
if ((hash = g_array_index(ary, GHashTable *, found_block_nr)) != NULL) {
|
1050
|
+
DEBUG("found a hash:");
|
1051
|
+
IFDEBUG(oneliner_int_hash_debug(hash));
|
1052
|
+
g_hash_table_foreach(hash, oneliner_superstring_analyze_source_block_with_hash, str);
|
1053
|
+
|
1054
|
+
oneliner_superstring_free_as_necessary(str);
|
1055
|
+
|
1056
|
+
g_hash_table_destroy(hash);
|
1057
|
+
g_array_index(ary, GHashTable *, found_block_nr) = NULL;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
UNINDENT;
|
1061
|
+
}
|
1062
|
+
|
1063
|
+
//
|
1064
|
+
// Check to see if there is an un-initialized aux block at found_block_nr,
|
1065
|
+
// and if so initialize it. If that meant that it became finished or empty
|
1066
|
+
// then set and queue for analysis if it gave any new information.
|
1067
|
+
//
|
1068
|
+
static void
|
1069
|
+
oneliner_superstring_analyze_aux_block(oneliner_superstring *str,
|
1070
|
+
guint32 found_block_nr)
|
1071
|
+
{
|
1072
|
+
oneliner_xor_block *xor_block;
|
1073
|
+
guint32 source_block_nr;
|
1074
|
+
gboolean found_new_block;
|
1075
|
+
|
1076
|
+
INDENT;
|
1077
|
+
DEBUG("analyze_aux_block called with _%i_ (%i)",
|
1078
|
+
found_block_nr,
|
1079
|
+
*oneliner_superstring_get_combined_block(str, found_block_nr));
|
1080
|
+
|
1081
|
+
if ((xor_block = g_array_index(str->known_aux_blocks,
|
1082
|
+
oneliner_xor_block *,
|
1083
|
+
found_block_nr - str->n_data_blocks_needed)) != NULL) {
|
1084
|
+
|
1085
|
+
DEBUG("found an unset aux block %i", GPOINTER_TO_UINT(xor_block));
|
1086
|
+
|
1087
|
+
oneliner_xor_block_set_sum(xor_block, oneliner_superstring_get_combined_block(str, found_block_nr), str->n_chars_in_block);
|
1088
|
+
if (XOR_BLOCK_FINISHED(xor_block)) {
|
1089
|
+
source_block_nr = oneliner_xor_block_last_source_block_nr(xor_block);
|
1090
|
+
|
1091
|
+
DEBUG("it is finished, setting the xor block to the new sum, and queueing %i to be freed!", GPOINTER_TO_UINT(xor_block));
|
1092
|
+
|
1093
|
+
g_array_index(str->known_aux_blocks,
|
1094
|
+
oneliner_xor_block *,
|
1095
|
+
found_block_nr - str->n_data_blocks_needed) = NULL;
|
1096
|
+
str->to_free = g_list_append(str->to_free, xor_block);
|
1097
|
+
|
1098
|
+
if (oneliner_superstring_set_combined_block(str, source_block_nr, xor_block->sum)) {
|
1099
|
+
DEBUG("_%i_ (%i) was unknown, setting and queueing %i to be analyzed! ******************",
|
1100
|
+
source_block_nr,
|
1101
|
+
*oneliner_superstring_get_combined_block(str, source_block_nr),
|
1102
|
+
source_block_nr);
|
1103
|
+
str->to_analyze = g_list_append(str->to_analyze, GUINT_TO_POINTER(source_block_nr));
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
} else if (XOR_BLOCK_EMPTY(xor_block)) {
|
1107
|
+
DEBUG("it is empty, queueing %i to be freed", GPOINTER_TO_UINT(xor_block));
|
1108
|
+
str->to_free = g_list_append(str->to_free, xor_block);
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
oneliner_superstring_free_as_necessary(str);
|
1112
|
+
}
|
1113
|
+
UNINDENT;
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
//
|
1117
|
+
// Analyze the new information provided by finding found_block_nr for str.
|
1118
|
+
//
|
1119
|
+
static void
|
1120
|
+
oneliner_superstring_analyze(oneliner_superstring *str, guint32 found_block_nr)
|
1121
|
+
{
|
1122
|
+
|
1123
|
+
INDENT;
|
1124
|
+
DEBUG("analyze called with _%i_", found_block_nr);
|
1125
|
+
//
|
1126
|
+
// Analyze results for any unresolved check blocks for this found block nr.
|
1127
|
+
//
|
1128
|
+
oneliner_superstring_analyze_source_block_with_array(str,
|
1129
|
+
str->check_block_graph,
|
1130
|
+
found_block_nr);
|
1131
|
+
|
1132
|
+
if (found_block_nr < str->n_data_blocks_needed) {
|
1133
|
+
//
|
1134
|
+
// Analyze results for any unresolved aux blocks for this found block nr.
|
1135
|
+
//
|
1136
|
+
oneliner_superstring_analyze_source_block_with_array(str,
|
1137
|
+
str->aux_block_graph,
|
1138
|
+
found_block_nr);
|
1139
|
+
} else {
|
1140
|
+
//
|
1141
|
+
// Analyze results for any unresolved SOURCE blocks for this found aux block.
|
1142
|
+
//
|
1143
|
+
oneliner_superstring_analyze_aux_block(str, found_block_nr);
|
1144
|
+
}
|
1145
|
+
|
1146
|
+
UNINDENT;
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
//
|
1150
|
+
// Take the chunk of length chunk_len and seed and add it to the graphs of str, and queue for analysis any
|
1151
|
+
// results we find.
|
1152
|
+
//
|
1153
|
+
static void
|
1154
|
+
oneliner_superstring_add_to_graph(oneliner_superstring *str, guint32 seed, guint8 *chunk, guint32 chunk_len)
|
1155
|
+
{
|
1156
|
+
oneliner_context *context = oneliner_context_new();
|
1157
|
+
GArray *content_blocks;
|
1158
|
+
guint32 tmp;
|
1159
|
+
guint32 tmp2;
|
1160
|
+
guint32 unknown_source_blocks;
|
1161
|
+
guint32 unknown_source_block_nr;
|
1162
|
+
GHashTable *inserts = g_hash_table_new(NULL,NULL);
|
1163
|
+
oneliner_xor_block *xor_block;
|
1164
|
+
guint32 degree;
|
1165
|
+
guint32 block_nr;
|
1166
|
+
guint8 *block_content;
|
1167
|
+
|
1168
|
+
INDENT;
|
1169
|
+
DEBUG("add_to_graph called");
|
1170
|
+
|
1171
|
+
oneliner_context_seed(context, (gint32) seed);
|
1172
|
+
|
1173
|
+
content_blocks = oneliner_superstring_get_blocks_from_chunk(str, chunk, chunk_len);
|
1174
|
+
|
1175
|
+
DEBUG("the chunk '%s' of len %i has %i check blocks", chunk, chunk_len, content_blocks->len);
|
1176
|
+
|
1177
|
+
for (tmp = 0; tmp < content_blocks->len; tmp++) {
|
1178
|
+
DEBUG("looking at block with sum %i", *g_array_index(content_blocks, guint8 *, tmp));
|
1179
|
+
degree = oneliner_context_get_degree(context);
|
1180
|
+
if (degree == 1) {
|
1181
|
+
block_nr = RANDOM(context, str->n_data_blocks_needed + str->n_aux_blocks_needed);
|
1182
|
+
DEBUG("found block _%i_ in a single block check block", block_nr);
|
1183
|
+
if (oneliner_superstring_set_combined_block(str, block_nr, g_array_index(content_blocks, guint8 *, tmp))) {
|
1184
|
+
DEBUG("_%i_ (%i) was unknown, setting it and queueing it for analyze! *********************",
|
1185
|
+
block_nr,
|
1186
|
+
*oneliner_superstring_get_combined_block(str, block_nr));
|
1187
|
+
str->to_analyze = g_list_append(str->to_analyze, GUINT_TO_POINTER(block_nr));
|
1188
|
+
}
|
1189
|
+
} else {
|
1190
|
+
unknown_source_blocks = 0;
|
1191
|
+
unknown_source_block_nr = 0;
|
1192
|
+
|
1193
|
+
xor_block = oneliner_xor_block_new(g_array_index(content_blocks, guint8 *, tmp),
|
1194
|
+
str->n_chars_in_block,
|
1195
|
+
TRUE,
|
1196
|
+
str,
|
1197
|
+
-1);
|
1198
|
+
|
1199
|
+
DEBUG("found a multi block check block with blocks:");
|
1200
|
+
for (tmp2 = 0; tmp2 < degree; tmp2++) {
|
1201
|
+
block_nr = RANDOM(context, str->n_data_blocks_needed + str->n_aux_blocks_needed);
|
1202
|
+
block_content = oneliner_superstring_get_combined_block(str, block_nr);
|
1203
|
+
if (block_content != NULL) {
|
1204
|
+
oneliner_string_xor(xor_block->sum, block_content, str->n_chars_in_block);
|
1205
|
+
DEBUG(" _%i_ IS known!!!!!!!!! (making the block sum into %i)", block_nr, *(xor_block->sum));
|
1206
|
+
} else {
|
1207
|
+
DEBUG(" _%i_ is NOT known :.(", block_nr);
|
1208
|
+
oneliner_xor_block_add(xor_block, block_nr);
|
1209
|
+
if (!g_hash_table_lookup_extended(inserts, GUINT_TO_POINTER(block_nr), NULL, NULL))
|
1210
|
+
g_hash_table_insert(inserts, GUINT_TO_POINTER(block_nr), oneliner_graph_insertion_new(xor_block, block_nr));
|
1211
|
+
unknown_source_blocks++;
|
1212
|
+
unknown_source_block_nr = block_nr;
|
1213
|
+
}
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
if (XOR_BLOCK_FINISHED(xor_block)) {
|
1217
|
+
DEBUG("found block _%i_ in a multi block check block (sum = %i) block with only one missing block", unknown_source_block_nr, GPOINTER_TO_UINT(xor_block->sum));
|
1218
|
+
|
1219
|
+
if (oneliner_superstring_set_combined_block(str, unknown_source_block_nr, xor_block->sum)) {
|
1220
|
+
DEBUG("_%i_ (%i) was unknown, setting it and queueing it for analysis *****************",
|
1221
|
+
unknown_source_block_nr,
|
1222
|
+
*oneliner_superstring_get_combined_block(str, unknown_source_block_nr));
|
1223
|
+
str->to_analyze = g_list_append(str->to_analyze, GUINT_TO_POINTER(unknown_source_block_nr));
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
g_hash_table_foreach_remove(inserts, oneliner_graph_insertion_free_with_check_block, NULL);
|
1227
|
+
|
1228
|
+
} else if (XOR_BLOCK_EMPTY(xor_block)) {
|
1229
|
+
DEBUG("just deleting it, it is empty...");
|
1230
|
+
g_hash_table_foreach_remove(inserts, oneliner_graph_insertion_free_with_check_block, NULL);
|
1231
|
+
} else {
|
1232
|
+
DEBUG("inserting it into the check_block_graph");
|
1233
|
+
g_hash_table_foreach_remove(inserts, oneliner_insertion_execute, str);
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
}
|
1237
|
+
(str->n_seen_check_blocks)++;
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
FREE_ARRAY_WITH_STRINGS(content_blocks);
|
1241
|
+
g_hash_table_destroy(inserts);
|
1242
|
+
g_free(context);
|
1243
|
+
UNINDENT;
|
1244
|
+
}
|
1245
|
+
|
1246
|
+
//
|
1247
|
+
// Build a dependency graph for the aux blocks of str.
|
1248
|
+
//
|
1249
|
+
static void
|
1250
|
+
oneliner_superstring_build_aux_graph(oneliner_superstring *str)
|
1251
|
+
{
|
1252
|
+
oneliner_context *context = oneliner_context_new();
|
1253
|
+
guint32 tmp;
|
1254
|
+
guint8 *zeroes = g_new0(guint8, str->n_chars_in_block);
|
1255
|
+
guint32 tmp2;
|
1256
|
+
guint32 aux_block_nr;
|
1257
|
+
oneliner_xor_block *aux_block;
|
1258
|
+
GHashTable *aux_blocks;
|
1259
|
+
|
1260
|
+
INDENT;
|
1261
|
+
DEBUG("build_aux_graph called");
|
1262
|
+
|
1263
|
+
oneliner_context_seed(context, (gint32) str->data_len);
|
1264
|
+
str->known_aux_blocks = g_array_new(FALSE, TRUE, sizeof(oneliner_xor_block *));
|
1265
|
+
g_array_set_size(str->known_aux_blocks, str->n_aux_blocks_needed);
|
1266
|
+
str->aux_block_graph = g_array_new(FALSE, TRUE, sizeof(GHashTable *));
|
1267
|
+
g_array_set_size(str->aux_block_graph, str->n_data_blocks_needed);
|
1268
|
+
|
1269
|
+
for (tmp = 0; tmp < str->n_data_blocks_needed; tmp++) {
|
1270
|
+
aux_blocks = g_hash_table_new(NULL, NULL);
|
1271
|
+
|
1272
|
+
for (tmp2 = 0; tmp2 < Q; tmp2++) {
|
1273
|
+
aux_block_nr = RANDOM(context, str->n_aux_blocks_needed);
|
1274
|
+
|
1275
|
+
if ((aux_block = g_array_index(str->known_aux_blocks, oneliner_xor_block *, aux_block_nr)) == NULL) {
|
1276
|
+
aux_block = oneliner_xor_block_new(zeroes, str->n_chars_in_block, FALSE, str, aux_block_nr);
|
1277
|
+
DEBUG("creating aux_block nr %i", aux_block_nr, tmp);
|
1278
|
+
g_array_index(str->known_aux_blocks, oneliner_xor_block *, aux_block_nr) = aux_block;
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
DEBUG("adding _%i_ as dependency to aux_block %i", tmp, aux_block_nr);
|
1282
|
+
oneliner_xor_block_add(aux_block, tmp);
|
1283
|
+
IFDEBUG(oneliner_xor_block_debug(aux_block));
|
1284
|
+
|
1285
|
+
if (!g_hash_table_lookup_extended(aux_blocks, aux_block, NULL, NULL)) {
|
1286
|
+
g_hash_table_insert(aux_blocks, aux_block, GUINT_TO_POINTER(tmp));
|
1287
|
+
}
|
1288
|
+
}
|
1289
|
+
DEBUG("setting aux_block_graph for _%i_", tmp);
|
1290
|
+
IFDEBUG(oneliner_int_hash_debug(aux_blocks));
|
1291
|
+
g_array_index(str->aux_block_graph, GHashTable *, tmp) = aux_blocks;
|
1292
|
+
}
|
1293
|
+
|
1294
|
+
UNINDENT;
|
1295
|
+
g_free(zeroes);
|
1296
|
+
g_free(context);
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
//
|
1300
|
+
// Go through the queue of results to analyze of str until it is empty (note that it can be appended
|
1301
|
+
// while analyzing...)
|
1302
|
+
//
|
1303
|
+
static void
|
1304
|
+
oneliner_superstring_analyze_until_done(oneliner_superstring *str)
|
1305
|
+
{
|
1306
|
+
GList *list_element = str->to_analyze;
|
1307
|
+
|
1308
|
+
INDENT;
|
1309
|
+
DEBUG("going through the to_analyze queue...");
|
1310
|
+
|
1311
|
+
while (list_element != NULL) {
|
1312
|
+
oneliner_superstring_analyze(str, GPOINTER_TO_UINT(list_element->data));
|
1313
|
+
str->to_analyze = g_list_remove_link(str->to_analyze, list_element);
|
1314
|
+
g_list_free_1(list_element);
|
1315
|
+
list_element = str->to_analyze;
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
UNINDENT;
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
//
|
1322
|
+
// Decode chunk into self, and return whether self seems to be finished decoding.
|
1323
|
+
//
|
1324
|
+
static VALUE
|
1325
|
+
rb_oneliner_superstring_decode(VALUE self, VALUE chunk)
|
1326
|
+
{
|
1327
|
+
RB_ONELINER(self, str);
|
1328
|
+
guint32 data_len;
|
1329
|
+
guint32 seed;
|
1330
|
+
guint32 blocks_needed;
|
1331
|
+
|
1332
|
+
INDENT;
|
1333
|
+
|
1334
|
+
Check_Type(chunk, T_STRING);
|
1335
|
+
|
1336
|
+
DEBUG("decode called for string %i with chunk '%s'", GPOINTER_TO_UINT(str), RSTRING(chunk)->ptr);
|
1337
|
+
|
1338
|
+
if (RSTRING(chunk)->len < 8)
|
1339
|
+
rb_raise(rb_eRuntimeError, "Oneliner::SuperString#decode(String chunk) needs an argument that is at least 8 characters long.");
|
1340
|
+
|
1341
|
+
data_len = ((guint32 *) RSTRING(chunk)->ptr)[0];
|
1342
|
+
seed = ((guint32 *) RSTRING(chunk)->ptr)[1];
|
1343
|
+
|
1344
|
+
DEBUG("data_len=%i, seed=%i", data_len, seed);
|
1345
|
+
|
1346
|
+
if (str->data_len == 0) {
|
1347
|
+
str->data_len = data_len;
|
1348
|
+
} else if (str->data_len != data_len) {
|
1349
|
+
rb_raise(rb_eRuntimeError, "Oneliner::Superstring#decode(String chunk) needs all consecutive calls to be with arguments having the same first four characters. Didn't you use chunks produced using #encode calls from the same instance?");
|
1350
|
+
}
|
1351
|
+
|
1352
|
+
if (str->data_blocks == NULL) {
|
1353
|
+
DEBUG("first decode, setting up...");
|
1354
|
+
oneliner_superstring_initialize(str, data_len);
|
1355
|
+
str->data_blocks = g_array_new(FALSE, TRUE, sizeof(guint8 *));
|
1356
|
+
g_array_set_size(str->data_blocks, str->n_data_blocks_needed);
|
1357
|
+
str->aux_blocks = g_array_new(FALSE, TRUE, sizeof(guint8 *));
|
1358
|
+
g_array_set_size(str->aux_blocks, str->n_aux_blocks_needed);
|
1359
|
+
str->check_block_graph = g_array_new(FALSE, TRUE, sizeof(GHashTable *));
|
1360
|
+
g_array_set_size(str->check_block_graph, str->n_data_blocks_needed + str->n_aux_blocks_needed);
|
1361
|
+
oneliner_superstring_build_aux_graph(str);
|
1362
|
+
}
|
1363
|
+
|
1364
|
+
oneliner_superstring_add_to_graph(str, seed, (guint8 *) RSTRING(chunk)->ptr + 8, (guint32) RSTRING(chunk)->len - 8);
|
1365
|
+
|
1366
|
+
oneliner_superstring_analyze_until_done(str);
|
1367
|
+
UNINDENT;
|
1368
|
+
return oneliner_superstring_decode_done(str);
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
//
|
1372
|
+
// Produce and return a new check block for str using the given context.
|
1373
|
+
//
|
1374
|
+
static guint8 *
|
1375
|
+
oneliner_superstring_get_check_block(oneliner_superstring *str, oneliner_context *context)
|
1376
|
+
{
|
1377
|
+
guint32 degree = oneliner_context_get_degree(context);
|
1378
|
+
guint32 block_nr = RANDOM(context, str->n_data_blocks_needed + str->n_aux_blocks_needed);
|
1379
|
+
guint8 *rval;
|
1380
|
+
guint32 tmp;
|
1381
|
+
|
1382
|
+
ALLOC_COPY8(rval, oneliner_superstring_get_combined_block(str, block_nr), str->n_chars_in_block);
|
1383
|
+
DEBUG("creating check block with degree %3i and data_blocks _%i_: %i", degree, block_nr, *oneliner_superstring_get_combined_block(str, block_nr));
|
1384
|
+
for (tmp = 2; tmp <= degree; tmp++) {
|
1385
|
+
block_nr = RANDOM(context, str->n_data_blocks_needed + str->n_aux_blocks_needed);
|
1386
|
+
DEBUG(" _%i_: %i", block_nr, *oneliner_superstring_get_combined_block(str, block_nr));
|
1387
|
+
oneliner_string_xor(rval,
|
1388
|
+
oneliner_superstring_get_combined_block(str, block_nr),
|
1389
|
+
str->n_chars_in_block);
|
1390
|
+
}
|
1391
|
+
DEBUG(" sum: %i ^^^^^", *rval);
|
1392
|
+
return rval;
|
1393
|
+
}
|
1394
|
+
|
1395
|
+
//
|
1396
|
+
// Encode a new chunk of check blocks for str and put it in an array pointer to by buffer of length len.
|
1397
|
+
//
|
1398
|
+
static guint32
|
1399
|
+
oneliner_superstring_encode(oneliner_superstring *str, guint8 **buffer, guint32 len)
|
1400
|
+
{
|
1401
|
+
oneliner_context *context = oneliner_context_new();
|
1402
|
+
guint8 prepend[8];
|
1403
|
+
gint32 tmp;
|
1404
|
+
guint32 needed_blocks = ((len - 8) * 8) / str->block_size;
|
1405
|
+
GArray *rval_ary = g_array_new(FALSE, FALSE, sizeof(guint8 *));
|
1406
|
+
guint32 resulting_size;
|
1407
|
+
struct timeval tv;
|
1408
|
+
|
1409
|
+
DEBUG("encode called for string %i with len %i (with block size %i that means %i blocks)",
|
1410
|
+
GPOINTER_TO_UINT(str),
|
1411
|
+
len,
|
1412
|
+
str->block_size,
|
1413
|
+
needed_blocks);
|
1414
|
+
|
1415
|
+
g_array_set_size(rval_ary, needed_blocks);
|
1416
|
+
|
1417
|
+
gettimeofday(&tv, NULL);
|
1418
|
+
srand(tv.tv_usec);
|
1419
|
+
tmp = (gint32) rand();
|
1420
|
+
oneliner_context_seed(context, tmp);
|
1421
|
+
|
1422
|
+
( (guint32 *) prepend )[0] = str->data_len;
|
1423
|
+
( (guint32 *) prepend )[1] = (guint32) tmp;
|
1424
|
+
|
1425
|
+
for (tmp = 0; tmp < needed_blocks; tmp++) {
|
1426
|
+
guint8 *check_block = oneliner_superstring_get_check_block(str, context);
|
1427
|
+
g_array_index(rval_ary, guint8 *, tmp) = check_block;
|
1428
|
+
}
|
1429
|
+
|
1430
|
+
// Here I let resulting_size describe the number of bytes needed to contain the rval_ary considering the block
|
1431
|
+
// size. And since we cant really truncate it at the end at this stage (like we can in the final build_data_from_blocks)
|
1432
|
+
// the data_len argument is the same as the n_bytes_for_blocks argument. Also, we want to prepend the original data-len
|
1433
|
+
// and seed, so we use the prepend argument.
|
1434
|
+
resulting_size = (guint32) ceil((needed_blocks * str->block_size) / 8) + 8;
|
1435
|
+
*buffer = oneliner_superstring_build_data_from_blocks(resulting_size,
|
1436
|
+
resulting_size,
|
1437
|
+
str->block_size,
|
1438
|
+
rval_ary,
|
1439
|
+
8,
|
1440
|
+
prepend);
|
1441
|
+
g_free(context);
|
1442
|
+
FREE_ARRAY_WITH_STRINGS(rval_ary);
|
1443
|
+
|
1444
|
+
return resulting_size;
|
1445
|
+
}
|
1446
|
+
|
1447
|
+
//
|
1448
|
+
// Add the given xor_block to the given hash. Used as an iterator to clear up other hashes.
|
1449
|
+
//
|
1450
|
+
static void
|
1451
|
+
oneliner_superstring_add_xor_to_hash(gpointer key, gpointer data, gpointer user_data)
|
1452
|
+
{
|
1453
|
+
if (!g_hash_table_lookup_extended((GHashTable *) user_data, key, NULL, NULL)) {
|
1454
|
+
DEBUG("queueing xor_block %i to be freed", GPOINTER_TO_UINT(key));
|
1455
|
+
g_hash_table_insert((GHashTable *) user_data, key, NULL);
|
1456
|
+
}
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
//
|
1460
|
+
// Go through the given ary and put all xor_blocks in its contained hahes into the
|
1461
|
+
// hashtable xors, then destroy the hashtables.
|
1462
|
+
//
|
1463
|
+
static void
|
1464
|
+
oneliner_superstring_free_ary_of_hashes_of_xor_blocks(GArray *ary, GHashTable *xors)
|
1465
|
+
{
|
1466
|
+
guint32 tmp;
|
1467
|
+
for (tmp = 0; tmp < ary->len; tmp++) {
|
1468
|
+
GHashTable *hash;
|
1469
|
+
if ((hash = (GHashTable *) g_array_index(ary, GHashTable *, tmp)) != NULL) {
|
1470
|
+
DEBUG("removing xor blocks belonging to _%i_", tmp);
|
1471
|
+
g_hash_table_foreach(hash, oneliner_superstring_add_xor_to_hash, xors);
|
1472
|
+
g_hash_table_destroy(hash);
|
1473
|
+
}
|
1474
|
+
}
|
1475
|
+
}
|
1476
|
+
|
1477
|
+
//
|
1478
|
+
// Free the given xor_block. Used to iterator over the hashtable containing all remaining
|
1479
|
+
// xor_blocks in an onliner_superstring when it is being freed.
|
1480
|
+
//
|
1481
|
+
static void
|
1482
|
+
oneliner_superstring_free_xors_killer(gpointer data, gpointer tmp1, gpointer tmp2)
|
1483
|
+
{
|
1484
|
+
oneliner_xor_block_free((oneliner_xor_block *) data, FALSE);
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
//
|
1488
|
+
// Free the given oneliner_superstring by freeing its blocks and aux_blocks,
|
1489
|
+
// then go through the graphs and empty and free them, then free the xor_blocks that
|
1490
|
+
// existed in the graphs.
|
1491
|
+
//
|
1492
|
+
static void
|
1493
|
+
oneliner_superstring_free(oneliner_superstring *str)
|
1494
|
+
{
|
1495
|
+
GHashTable *xors = g_hash_table_new(NULL, NULL);
|
1496
|
+
guint32 tmp;
|
1497
|
+
|
1498
|
+
DEBUG("freeing string %i", GPOINTER_TO_UINT(str));
|
1499
|
+
|
1500
|
+
if (str->data_blocks != NULL) {
|
1501
|
+
FREE_ARRAY_WITH_STRINGS(str->data_blocks);
|
1502
|
+
}
|
1503
|
+
if (str->aux_blocks != NULL) {
|
1504
|
+
FREE_ARRAY_WITH_STRINGS(str->aux_blocks);
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
if (str->check_block_graph != NULL) {
|
1508
|
+
INDENT;
|
1509
|
+
DEBUG("freeing check_block_graph");
|
1510
|
+
oneliner_superstring_free_ary_of_hashes_of_xor_blocks(str->check_block_graph, xors);
|
1511
|
+
g_array_free(str->check_block_graph, TRUE);
|
1512
|
+
str->check_block_graph = NULL;
|
1513
|
+
UNINDENT;
|
1514
|
+
}
|
1515
|
+
if (str->known_aux_blocks != NULL) {
|
1516
|
+
INDENT;
|
1517
|
+
DEBUG("freeing known_aux_blocks");
|
1518
|
+
for (tmp = 0; tmp < str->n_aux_blocks_needed; tmp++) {
|
1519
|
+
gpointer xor_block;
|
1520
|
+
if ((xor_block = g_array_index(str->known_aux_blocks, oneliner_xor_block *, tmp)) != NULL) {
|
1521
|
+
DEBUG("queueing aux block at _%i_ to be freed", tmp);
|
1522
|
+
g_hash_table_insert(xors, xor_block, NULL);
|
1523
|
+
}
|
1524
|
+
}
|
1525
|
+
g_array_free(str->known_aux_blocks, TRUE);
|
1526
|
+
str->known_aux_blocks = NULL;
|
1527
|
+
UNINDENT;
|
1528
|
+
}
|
1529
|
+
if (str->aux_block_graph != NULL) {
|
1530
|
+
INDENT;
|
1531
|
+
DEBUG("freeing aux_block_graph");
|
1532
|
+
oneliner_superstring_free_ary_of_hashes_of_xor_blocks(str->aux_block_graph, xors);
|
1533
|
+
g_array_free(str->aux_block_graph, TRUE);
|
1534
|
+
str->aux_block_graph = NULL;
|
1535
|
+
UNINDENT;
|
1536
|
+
}
|
1537
|
+
|
1538
|
+
DEBUG("freeing all xor blocks");
|
1539
|
+
g_hash_table_foreach(xors, oneliner_superstring_free_xors_killer, NULL);
|
1540
|
+
g_hash_table_destroy(xors);
|
1541
|
+
g_free(str);
|
1542
|
+
}
|
1543
|
+
|
1544
|
+
//
|
1545
|
+
// Create a new Oneliner::SuperString by allocating a new oneliner_superstring.
|
1546
|
+
//
|
1547
|
+
static VALUE
|
1548
|
+
rb_oneliner_superstring_alloc(VALUE klass)
|
1549
|
+
{
|
1550
|
+
oneliner_superstring *str = g_new0(oneliner_superstring, 1);
|
1551
|
+
return Data_Wrap_Struct(klass, NULL, oneliner_superstring_free, str);
|
1552
|
+
}
|
1553
|
+
|
1554
|
+
//
|
1555
|
+
// Create a ruby Array filled with all the char arrays of length len within container.
|
1556
|
+
//
|
1557
|
+
static VALUE
|
1558
|
+
oneliner_superstring_get_blocks(GArray *container, guint32 len)
|
1559
|
+
{
|
1560
|
+
guint32 tmp;
|
1561
|
+
VALUE rval = rb_ary_new();
|
1562
|
+
if (container == NULL)
|
1563
|
+
return rb_ary_new();
|
1564
|
+
for (tmp = 0; tmp < container->len; tmp++) {
|
1565
|
+
guint8 *tmp_block = g_array_index(container, guint8 *, tmp);
|
1566
|
+
if (tmp_block == NULL)
|
1567
|
+
rb_ary_push(rval, Qnil);
|
1568
|
+
else
|
1569
|
+
rb_ary_push(rval, rb_str_new((gchar *) tmp_block, len));
|
1570
|
+
}
|
1571
|
+
return rval;
|
1572
|
+
}
|
1573
|
+
|
1574
|
+
//
|
1575
|
+
// Return the data blocks of self.
|
1576
|
+
//
|
1577
|
+
static VALUE
|
1578
|
+
rb_oneliner_superstring_data_blocks(VALUE self)
|
1579
|
+
{
|
1580
|
+
RB_ONELINER(self, str);
|
1581
|
+
return oneliner_superstring_get_blocks(str->data_blocks, str->n_chars_in_block);
|
1582
|
+
}
|
1583
|
+
|
1584
|
+
//
|
1585
|
+
// Return the aux blocks of self.
|
1586
|
+
//
|
1587
|
+
static VALUE
|
1588
|
+
rb_oneliner_superstring_aux_blocks(VALUE self)
|
1589
|
+
{
|
1590
|
+
RB_ONELINER(self, str);
|
1591
|
+
return oneliner_superstring_get_blocks(str->aux_blocks, str->n_chars_in_block);
|
1592
|
+
}
|
1593
|
+
|
1594
|
+
//
|
1595
|
+
// Put together the data blocks of self and return the resulting String.
|
1596
|
+
//
|
1597
|
+
static VALUE
|
1598
|
+
rb_oneliner_superstring_to_s(VALUE self)
|
1599
|
+
{
|
1600
|
+
RB_ONELINER(self, str);
|
1601
|
+
VALUE rval;
|
1602
|
+
guint8 *tmp_data;
|
1603
|
+
|
1604
|
+
if (oneliner_superstring_decode_done(str) == Qfalse)
|
1605
|
+
return rb_str_new2("");
|
1606
|
+
tmp_data = oneliner_superstring_build_data(str);
|
1607
|
+
rval = rb_str_new((gchar *) tmp_data, str->data_len);
|
1608
|
+
g_free(tmp_data);
|
1609
|
+
return rval;
|
1610
|
+
}
|
1611
|
+
|
1612
|
+
//
|
1613
|
+
// Returns the block size of self.
|
1614
|
+
//
|
1615
|
+
static VALUE
|
1616
|
+
rb_oneliner_superstring_block_size(VALUE self)
|
1617
|
+
{
|
1618
|
+
RB_ONELINER(self, str);
|
1619
|
+
return INT2NUM(str->block_size);
|
1620
|
+
}
|
1621
|
+
|
1622
|
+
//
|
1623
|
+
// Returns whether self is done decoding.
|
1624
|
+
//
|
1625
|
+
static VALUE
|
1626
|
+
rb_oneliner_superstring_decode_done(VALUE self)
|
1627
|
+
{
|
1628
|
+
RB_ONELINER(self, str);
|
1629
|
+
return oneliner_superstring_decode_done(str);
|
1630
|
+
}
|
1631
|
+
|
1632
|
+
//
|
1633
|
+
// Return a newly created chunk of check blocks of size from self.
|
1634
|
+
//
|
1635
|
+
static VALUE
|
1636
|
+
rb_oneliner_superstring_encode(VALUE self, VALUE size)
|
1637
|
+
{
|
1638
|
+
RB_ONELINER(self, str);
|
1639
|
+
guint8 *chunk;
|
1640
|
+
VALUE rval;
|
1641
|
+
guint32 chunk_size;
|
1642
|
+
|
1643
|
+
Check_Type(size, T_FIXNUM);
|
1644
|
+
if (NUM2INT(size) < 8)
|
1645
|
+
rb_raise(rb_eRuntimeError, "Oneliner::SuperString#encode(Fixnum size) needs a size of at least 8.");
|
1646
|
+
|
1647
|
+
if (!str->decode_done)
|
1648
|
+
rb_raise(rb_eRuntimeError, "Oneliner::SuperString#encode(Fixnum size) can only be called on strings that are done decoding themselves.");
|
1649
|
+
|
1650
|
+
chunk_size = oneliner_superstring_encode(str, &chunk, NUM2INT(size));
|
1651
|
+
|
1652
|
+
rval = rb_str_new((gchar *) chunk, chunk_size);
|
1653
|
+
|
1654
|
+
g_free(chunk);
|
1655
|
+
|
1656
|
+
return rval;
|
1657
|
+
}
|
1658
|
+
|
1659
|
+
//
|
1660
|
+
// Returns the number of chars self would contain if you did to_s.
|
1661
|
+
//
|
1662
|
+
static VALUE
|
1663
|
+
rb_oneliner_superstring_size(VALUE self)
|
1664
|
+
{
|
1665
|
+
RB_ONELINER(self, str);
|
1666
|
+
return INT2NUM(str->data_len);
|
1667
|
+
}
|
1668
|
+
|
1669
|
+
//
|
1670
|
+
// Returns the number of check blocks processed by self.
|
1671
|
+
//
|
1672
|
+
static VALUE
|
1673
|
+
rb_oneliner_superstring_seen_check_blocks(VALUE self)
|
1674
|
+
{
|
1675
|
+
RB_ONELINER(self, str);
|
1676
|
+
return INT2NUM(str->n_seen_check_blocks);
|
1677
|
+
}
|
1678
|
+
|
1679
|
+
//
|
1680
|
+
// Iterator used to find out how many check blocks we have in our graphs.
|
1681
|
+
//
|
1682
|
+
static void
|
1683
|
+
rb_oneliner_superstring_known_check_blocks_iterator(gpointer key, gpointer data, gpointer user_data)
|
1684
|
+
{
|
1685
|
+
g_hash_table_insert((GHashTable *) user_data, key, NULL);
|
1686
|
+
}
|
1687
|
+
|
1688
|
+
//
|
1689
|
+
// Returns the number of check blocks in our graphs.
|
1690
|
+
//
|
1691
|
+
static VALUE
|
1692
|
+
rb_oneliner_superstring_known_check_blocks(VALUE self)
|
1693
|
+
{
|
1694
|
+
RB_ONELINER(self, str);
|
1695
|
+
guint32 tmp;
|
1696
|
+
guint32 tmp2;
|
1697
|
+
GHashTable *sum = g_hash_table_new(NULL, NULL);
|
1698
|
+
VALUE rval;
|
1699
|
+
|
1700
|
+
if (str->data_blocks == NULL)
|
1701
|
+
return INT2NUM(0);
|
1702
|
+
for (tmp = 0; tmp < str->n_data_blocks_needed + str->n_aux_blocks_needed; tmp++)
|
1703
|
+
if (g_array_index(str->check_block_graph, GHashTable *, tmp) != NULL)
|
1704
|
+
g_hash_table_foreach((GHashTable *) g_array_index(str->check_block_graph, GHashTable *, tmp),
|
1705
|
+
rb_oneliner_superstring_known_check_blocks_iterator,
|
1706
|
+
sum);
|
1707
|
+
rval = INT2NUM(g_hash_table_size(sum));
|
1708
|
+
g_hash_table_destroy(sum);
|
1709
|
+
return rval;
|
1710
|
+
}
|
1711
|
+
|
1712
|
+
//
|
1713
|
+
// Create a Onliner::Chunk to inspect a chunk of check blocks.
|
1714
|
+
//
|
1715
|
+
static VALUE
|
1716
|
+
rb_oneliner_chunk_initialize(VALUE self, VALUE chunk)
|
1717
|
+
{
|
1718
|
+
VALUE blocks_ary;
|
1719
|
+
GArray *blocks;
|
1720
|
+
guint32 data_len;
|
1721
|
+
guint32 seed;
|
1722
|
+
oneliner_superstring str;
|
1723
|
+
|
1724
|
+
data_len = ((guint32 *) RSTRING(chunk)->ptr)[0];
|
1725
|
+
seed = ((guint32 *) RSTRING(chunk)->ptr)[1];
|
1726
|
+
|
1727
|
+
Check_Type(chunk, T_STRING);
|
1728
|
+
|
1729
|
+
if (RSTRING(chunk)->len < 8)
|
1730
|
+
rb_raise(rb_eRuntimeError, "Oneliner::Chunk.new(String chunk) needs an argument that is at least 8 characters long.");
|
1731
|
+
|
1732
|
+
oneliner_superstring_initialize(&str, data_len);
|
1733
|
+
|
1734
|
+
blocks = oneliner_superstring_get_blocks_from_chunk(&str,
|
1735
|
+
(guint8 *) RSTRING(chunk)->ptr + 8,
|
1736
|
+
(guint32) RSTRING(chunk)->len - 8);
|
1737
|
+
|
1738
|
+
rb_ivar_set(self, rb_intern("@blocks"), oneliner_superstring_get_blocks(blocks,
|
1739
|
+
str.n_chars_in_block));
|
1740
|
+
rb_ivar_set(self, rb_intern("@seed"), INT2NUM(seed));
|
1741
|
+
rb_ivar_set(self, rb_intern("@data_len"), INT2NUM(data_len));
|
1742
|
+
|
1743
|
+
FREE_ARRAY_WITH_STRINGS(blocks);
|
1744
|
+
|
1745
|
+
return self;
|
1746
|
+
}
|
1747
|
+
|
1748
|
+
#ifdef __cplusplus
|
1749
|
+
extern "C" {
|
1750
|
+
#endif
|
1751
|
+
void Init_oneliner() {
|
1752
|
+
VALUE rb_string = rb_define_class("String", rb_cObject);
|
1753
|
+
rb_define_method(rb_string, "xor!", rb_oneliner_string_xor, 1);
|
1754
|
+
|
1755
|
+
VALUE rb_oneliner = rb_define_module("Oneliner");
|
1756
|
+
rb_superstring = rb_define_class_under(rb_oneliner,
|
1757
|
+
"SuperString",
|
1758
|
+
rb_cObject);
|
1759
|
+
rb_define_alloc_func(rb_superstring, rb_oneliner_superstring_alloc);
|
1760
|
+
rb_define_method(rb_superstring, "initialize", rb_oneliner_superstring_initialize, -1);
|
1761
|
+
rb_define_method(rb_superstring, "data_blocks", rb_oneliner_superstring_data_blocks, 0);
|
1762
|
+
rb_define_method(rb_superstring, "aux_blocks", rb_oneliner_superstring_aux_blocks, 0);
|
1763
|
+
rb_define_method(rb_superstring, "to_s", rb_oneliner_superstring_to_s, 0);
|
1764
|
+
rb_define_method(rb_superstring, "encode", rb_oneliner_superstring_encode, 1);
|
1765
|
+
rb_define_method(rb_superstring, "block_size", rb_oneliner_superstring_block_size, 0);
|
1766
|
+
rb_define_method(rb_superstring, "decode!", rb_oneliner_superstring_decode, 1);
|
1767
|
+
rb_define_method(rb_superstring, "done?", rb_oneliner_superstring_decode_done, 0);
|
1768
|
+
rb_define_method(rb_superstring, "size", rb_oneliner_superstring_size, 0);
|
1769
|
+
rb_define_method(rb_superstring, "seen_check_blocks", rb_oneliner_superstring_seen_check_blocks, 0);
|
1770
|
+
rb_define_method(rb_superstring, "known_check_blocks", rb_oneliner_superstring_known_check_blocks, 0);
|
1771
|
+
|
1772
|
+
rb_chunk = rb_define_class_under(rb_oneliner,
|
1773
|
+
"Chunk",
|
1774
|
+
rb_cObject);
|
1775
|
+
rb_define_method(rb_chunk, "initialize", rb_oneliner_chunk_initialize, 1);
|
1776
|
+
}
|
1777
|
+
#ifdef __cplusplus
|
1778
|
+
}
|
1779
|
+
#endif
|
1780
|
+
|