semacode-ruby19 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ CHANGELOG
2
+
3
+ 2007-03-02 guido
4
+
5
+ * Initial encoder wrapping for Ruby API
6
+
7
+ * Packaged as a gem
8
+
9
+
10
+ 2007-03-03 guido
11
+
12
+ * Separated native extension into its own namespace
13
+
14
+ * Trying to make a correct gem still
15
+
16
+
17
+ 2007-03-04 guido
18
+
19
+ * Exposed the encoding list used to create the semacode
20
+
21
+ * Use Ruby allocation functions instead of malloc.
22
+
23
+ * Fixes compiler errors with Fink not finding malloc.h
24
+
25
+ * Given up on making the gem do auto-require
26
+
27
+ * Fixes a memory leak where the encoding list wasn't being freed.
28
+
29
+
30
+ 2007-03-04 guido
31
+
32
+ * Free up internal memory allocated before we throw an exception
33
+
34
+ * Throw ArgError and RangeError exceptions rather than Runtime exceptions
35
+
36
+ * Don't return an inconsistent semacode when presented with overlong input
37
+
38
+ * Don't fail quietly either, throw an exception
39
+
40
+ * Very conservatively use a far smaller maximum value for input length than the header file suggests
data/README ADDED
@@ -0,0 +1,149 @@
1
+ = Ruby Semacode Encoder
2
+
3
+ == Introduction
4
+
5
+ This Ruby extension implements a DataMatrix encoder for Ruby. It is typically
6
+ used to create semacodes, which are barcodes, that contain URLs. This encoder
7
+ does not create image files or visual representations of the semacode. This is
8
+ because it can be used for more than creating images, such as rendering
9
+ semacodes to HTML, SVG, PDF or even stored in a database or file for later
10
+ use.
11
+
12
+ See test.rb for an example of how to create a visual symbol for a semacode, it
13
+ presents a semacode in HTML and plain text formats, and this can give you an
14
+ idea of how to start.
15
+
16
+ Once you have a visual representation of the semacode, you can use a reader,
17
+ such as those from http://semacode.org on your camera phone, to capture the
18
+ URL embedded in the semacode and proceed directly to that web site.
19
+
20
+ === License
21
+
22
+ This software is released under the terms of the GNU Public License version 2,
23
+ available from <http://www.gnu.org>
24
+
25
+ === Contact Information
26
+
27
+ You can contact me via <guido@sohne.net> if you have patches, bug fixes or
28
+ improvements.
29
+
30
+ Copyright (C) 2007, Guido Sohne
31
+ Website: http://sohne.net/projects/semafox
32
+
33
+ === Credits
34
+
35
+ Based on the iec16022ecc200.c encoder by Adrian Kennard, Andrews & Arnold Ltd
36
+
37
+ == Quick Start
38
+
39
+ Configure the extension to your local system and ruby
40
+
41
+ <tt>ruby extconf.rb</tt>
42
+
43
+ Build the extension
44
+
45
+ <tt>make</tt>
46
+
47
+ Test that it works
48
+
49
+ <tt>ruby test.rb</tt>
50
+
51
+ Install the extension (you may need to become root)
52
+
53
+ <tt>make install</tt>
54
+
55
+ You should take a look at tests/test.rb to understand how to use this. It
56
+ includes some code to generate a semacode using HTML and CSS, so that could
57
+ end up being useful.
58
+
59
+
60
+ == USAGE
61
+
62
+ Here's some basic ways in which you can make use of this extension. It tries
63
+ to show by example, how the semacodes can be created and what can be done with
64
+ or to a semacode object.
65
+
66
+
67
+ Include this library
68
+
69
+ <tt>require 'rubygems'</tt>
70
+ <tt>require 'semacode'</tt>
71
+
72
+ Create a semacode
73
+
74
+ <tt>semacode = Barcode::Semacode.new "http://sohne.net/projects/semafox/"</tt>
75
+
76
+ Return the semacode as an array of arrays of boolean
77
+
78
+ The first element of the array is the top row, the last element is the
79
+ bottom row. the array length is the semacode height, and each element is
80
+ an array as wide as the semacode width
81
+
82
+ <tt>grid = semacode.data</tt> or
83
+ <tt>grid = semacode.to_a</tt> or
84
+
85
+ Return the encoding list used to create the semacode
86
+
87
+ This encoding list is composed of the 'character set', complete with
88
+ shifts from one encoding type to another, that is used for the DataMatrix
89
+ algorithm.
90
+
91
+ <tt>encoding = semacode.encoding</tt>
92
+
93
+ Return the semacode as a string
94
+
95
+ The string is a comma separated list of character vectors. Each vector is a row
96
+ in the semacode symbol, the top row is first, and the bottom row is last. Inside
97
+ each row, the vector reads from left to right.
98
+
99
+ <tt>semacode.to_s</tt> or
100
+ <tt>semacode.to_str</tt>
101
+
102
+ Encode another string
103
+
104
+ <tt>semacode.encode "http://sohne.net"</tt>
105
+
106
+ Get the width of the semacode
107
+
108
+ <tt>semacode.width</tt>
109
+
110
+ Get the height of the semacode
111
+
112
+ <tt>semacode.height</tt>
113
+
114
+ How long is the semacode? (width * height)
115
+
116
+ <tt>semacode.length</tt> or
117
+ <tt>semacode.size</tt>
118
+
119
+ Get the raw encoded length (before padding and before ECC)
120
+
121
+ <tt>semacode.raw_encoded_length</tt>
122
+
123
+ Get the symbol size
124
+
125
+ The max number of characters this semacode type
126
+ (specific width x height) can hold is called the
127
+ symbol size.
128
+
129
+ <tt>semacode.symbol_size</tt>
130
+
131
+ Count the ECC bytes
132
+
133
+ How many bytes were used for error correction?
134
+
135
+ <tt>semacode.ecc_bytes</tt>
136
+
137
+
138
+ == NOTES
139
+
140
+ The C code can throw runtime exceptions. Be sure to include
141
+ a catch block if you want to use this in production. Mostly
142
+ the exceptions are not recoverable, except for when the data
143
+ is too long, in which case you can shorten it and try again.
144
+
145
+ There are two type of exceptions that it will throw. The first
146
+ is a RangeError exception, which happens when the input is too
147
+ long or when it just can't find a fit for the data. The second
148
+ is a ArgumentError (ArgError?) exception that gets thrown when
149
+ the input contains data it cannot handle.
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = "semacode-ruby19"
6
+ s.version = "0.7.4"
7
+ s.authors = ["Guido Sohne", "Tore Darell"]
8
+ s.email = "guido@sohne.net"
9
+ s.homepage = "http://sohne.net/projects/semafox/"
10
+ s.platform = Gem::Platform::RUBY
11
+ s.summary = "Create semacodes (2D barcodes) using Ruby."
12
+ s.rubyforge_project = "semacode"
13
+ s.description = <<DESC
14
+ This Ruby extension implements a DataMatrix encoder for Ruby. It is typically
15
+ used to create semacodes, which are barcodes, that contain URLs. This encoder
16
+ does not create image files or visual representations of the semacode. This is
17
+ because it can be used for more than creating images, such as rendering
18
+ semacodes to HTML, SVG, PDF or even stored in a database or file for later
19
+ use.
20
+
21
+ Ruby 1.9 compatibility added by Tore Darell <toredarell@gmail.com>.
22
+ DESC
23
+
24
+ s.extensions << 'ext/extconf.rb'
25
+ s.add_dependency('rake', '>= 0.7.0')
26
+ s.files = FileList[
27
+ "{lib,ext}/**/*.rb",
28
+ "ext/**/*.c",
29
+ "ext/**/*.h",
30
+ "tests/**/*.rb",
31
+ "README",
32
+ "CHANGELOG",
33
+ "Rakefile"].to_a
34
+ s.require_path = "lib"
35
+ s.autorequire = "semacode"
36
+ s.test_files = FileList["{tests}/**/*test.rb"].to_a
37
+ s.has_rdoc = true
38
+ s.extra_rdoc_files = ["README"]
39
+ end
40
+
41
+ Rake::GemPackageTask.new(spec) do |pkg|
42
+ pkg.need_zip = true
43
+ pkg.need_tar_gz = true
44
+ pkg.need_tar_bz2 = true
45
+ end
46
+
47
+ task :default => "pkg/#{spec.name}-#{spec.version}.gem" do
48
+ puts "Successfully created #{spec.name}-#{spec.version} gem"
49
+ end
50
+
51
+ if $0 == __FILE__
52
+ Gem::manage_gems
53
+ Gem::Builder.new(spec).build
54
+ end
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+ dir_config("semacode_native")
3
+ create_makefile('semacode_native')
@@ -0,0 +1,950 @@
1
+ // IEC16022 bar code generation library
2
+ // Adrian Kennard, Andrews & Arnold Ltd
3
+ // with help from Cliff Hones on the RS coding
4
+ //
5
+ // Revision 1.8 2004/09/12 10:35:25 cvs
6
+ // Minor fixes to auto encoding, and more precise placement of text on stamp output.
7
+ //
8
+ // Revision 1.7 2004/09/11 11:16:20 cvs
9
+ // Fixed binary format encoding, and added output file to indicia
10
+ //
11
+ // Revision 1.6 2004/09/10 16:10:30 cvs
12
+ // Correction of declaration ordering
13
+ //
14
+ // Revision 1.5 2004/09/09 12:35:48 cvs
15
+ // Interleaved (large) codes now working as well.
16
+ // Fixed bugs in the auto encoding (was selecting EDIFACT wrongly)
17
+ //
18
+ // Revision 1.4 2004/09/09 07:45:09 cvs
19
+ // Added change history to source files
20
+ // Added "info" type to IEC16022
21
+ // Added exact size checking shortcodes on encoding generation for iec16022
22
+ //
23
+
24
+
25
+ #include <stdio.h>
26
+ #include <ctype.h>
27
+ #include <string.h>
28
+ #include <time.h>
29
+ #include "ruby.h"
30
+ #include "reedsol.h"
31
+ #include "iec16022ecc200.h"
32
+
33
+ static struct ecc200matrix_s
34
+ {
35
+ int H,
36
+ W;
37
+ int FH,
38
+ FW;
39
+ int bytes;
40
+ int datablock,
41
+ rsblock;
42
+ }
43
+ ecc200matrix[] =
44
+ {
45
+ 10, 10, 10, 10, 3, 3, 5, //
46
+ 12, 12, 12, 12, 5, 5, 7, //
47
+ 14, 14, 14, 14, 8, 8, 10, //
48
+ 16, 16, 16, 16, 12, 12, 12, //
49
+ 18, 18, 18, 18, 18, 18, 14, //
50
+ 20, 20, 20, 20, 22, 22, 18, //
51
+ 22, 22, 22, 22, 30, 30, 20, //
52
+ 24, 24, 24, 24, 36, 36, 24, //
53
+ 26, 26, 26, 26, 44, 44, 28, //
54
+ 32, 32, 16, 16, 62, 62, 36, //
55
+ 36, 36, 18, 18, 86, 86, 42, //
56
+ 40, 40, 20, 20, 114, 114, 48, //
57
+ 44, 44, 22, 22, 144, 144, 56, //
58
+ 48, 48, 24, 24, 174, 174, 68, //
59
+ 52, 52, 26, 26, 204, 102, 42, //
60
+ 64, 64, 16, 16, 280, 140, 56, //
61
+ 72, 72, 18, 18, 368, 92, 36, //
62
+ 80, 80, 20, 20, 456, 114, 48, //
63
+ 88, 88, 22, 22, 576, 144, 56, //
64
+ 96, 96, 24, 24, 696, 174, 68, //
65
+ 104, 104, 26, 26, 816, 136, 56, //
66
+ 120, 120, 20, 20, 1050, 175, 68, //
67
+ 132, 132, 22, 22, 1304, 163, 62, //
68
+ 144, 144, 24, 24, 1558, 156, 62, // 156*4+155*2
69
+ 0 // terminate
70
+ };
71
+
72
+ // Annex M placement alorithm low level
73
+ static void
74
+ ecc200placementbit (int *array, int NR, int NC, int r, int c, int p, char b)
75
+ {
76
+ if (r < 0)
77
+ {
78
+ r += NR;
79
+ c += 4 - ((NR + 4) % 8);
80
+ }
81
+ if (c < 0)
82
+ {
83
+ c += NC;
84
+ r += 4 - ((NC + 4) % 8);
85
+ }
86
+ array[r * NC + c] = (p << 3) + b;
87
+ }
88
+
89
+ static void
90
+ ecc200placementblock (int *array, int NR, int NC, int r, int c, int p)
91
+ {
92
+ ecc200placementbit (array, NR, NC, r - 2, c - 2, p, 7);
93
+ ecc200placementbit (array, NR, NC, r - 2, c - 1, p, 6);
94
+ ecc200placementbit (array, NR, NC, r - 1, c - 2, p, 5);
95
+ ecc200placementbit (array, NR, NC, r - 1, c - 1, p, 4);
96
+ ecc200placementbit (array, NR, NC, r - 1, c - 0, p, 3);
97
+ ecc200placementbit (array, NR, NC, r - 0, c - 2, p, 2);
98
+ ecc200placementbit (array, NR, NC, r - 0, c - 1, p, 1);
99
+ ecc200placementbit (array, NR, NC, r - 0, c - 0, p, 0);
100
+ }
101
+
102
+ static void
103
+ ecc200placementcornerA (int *array, int NR, int NC, int p)
104
+ {
105
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 7);
106
+ ecc200placementbit (array, NR, NC, NR - 1, 1, p, 6);
107
+ ecc200placementbit (array, NR, NC, NR - 1, 2, p, 5);
108
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
109
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
110
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 2);
111
+ ecc200placementbit (array, NR, NC, 2, NC - 1, p, 1);
112
+ ecc200placementbit (array, NR, NC, 3, NC - 1, p, 0);
113
+ }
114
+
115
+ static void
116
+ ecc200placementcornerB (int *array, int NR, int NC, int p)
117
+ {
118
+ ecc200placementbit (array, NR, NC, NR - 3, 0, p, 7);
119
+ ecc200placementbit (array, NR, NC, NR - 2, 0, p, 6);
120
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 5);
121
+ ecc200placementbit (array, NR, NC, 0, NC - 4, p, 4);
122
+ ecc200placementbit (array, NR, NC, 0, NC - 3, p, 3);
123
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 2);
124
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 1);
125
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 0);
126
+ }
127
+
128
+ static void
129
+ ecc200placementcornerC (int *array, int NR, int NC, int p)
130
+ {
131
+ ecc200placementbit (array, NR, NC, NR - 3, 0, p, 7);
132
+ ecc200placementbit (array, NR, NC, NR - 2, 0, p, 6);
133
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 5);
134
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
135
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
136
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 2);
137
+ ecc200placementbit (array, NR, NC, 2, NC - 1, p, 1);
138
+ ecc200placementbit (array, NR, NC, 3, NC - 1, p, 0);
139
+ }
140
+
141
+ static void
142
+ ecc200placementcornerD (int *array, int NR, int NC, int p)
143
+ {
144
+ ecc200placementbit (array, NR, NC, NR - 1, 0, p, 7);
145
+ ecc200placementbit (array, NR, NC, NR - 1, NC - 1, p, 6);
146
+ ecc200placementbit (array, NR, NC, 0, NC - 3, p, 5);
147
+ ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
148
+ ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
149
+ ecc200placementbit (array, NR, NC, 1, NC - 3, p, 2);
150
+ ecc200placementbit (array, NR, NC, 1, NC - 2, p, 1);
151
+ ecc200placementbit (array, NR, NC, 1, NC - 1, p, 0);
152
+ }
153
+
154
+ // Annex M placement alorithm main function
155
+ static void
156
+ ecc200placement (int *array, int NR, int NC)
157
+ {
158
+ int r,
159
+ c,
160
+ p;
161
+ // invalidate
162
+ for (r = 0; r < NR; r++)
163
+ for (c = 0; c < NC; c++)
164
+ array[r * NC + c] = 0;
165
+ // start
166
+ p = 1;
167
+ r = 4;
168
+ c = 0;
169
+ do
170
+ {
171
+ // check corner
172
+ if (r == NR && !c)
173
+ ecc200placementcornerA (array, NR, NC, p++);
174
+ if (r == NR - 2 && !c && NC % 4)
175
+ ecc200placementcornerB (array, NR, NC, p++);
176
+ if (r == NR - 2 && !c && (NC % 8) == 4)
177
+ ecc200placementcornerC (array, NR, NC, p++);
178
+ if (r == NR + 4 && c == 2 && !(NC % 8))
179
+ ecc200placementcornerD (array, NR, NC, p++);
180
+ // up/right
181
+ do
182
+ {
183
+ if (r < NR && c >= 0 && !array[r * NC + c])
184
+ ecc200placementblock (array, NR, NC, r, c, p++);
185
+ r -= 2;
186
+ c += 2;
187
+ }
188
+ while (r >= 0 && c < NC);
189
+ r++;
190
+ c += 3;
191
+ // down/left
192
+ do
193
+ {
194
+ if (r >= 0 && c < NC && !array[r * NC + c])
195
+ ecc200placementblock (array, NR, NC, r, c, p++);
196
+ r += 2;
197
+ c -= 2;
198
+ }
199
+ while (r < NR && c >= 0);
200
+ r += 3;
201
+ c++;
202
+ }
203
+ while (r < NR || c < NC);
204
+ // unfilled corner
205
+ if (!array[NR * NC - 1])
206
+ array[NR * NC - 1] = array[NR * NC - NC - 2] = 1;
207
+ }
208
+
209
+ // calculate and append ecc code, and if necessary interleave
210
+ static void
211
+ ecc200 (unsigned char *binary, int bytes, int datablock, int rsblock)
212
+ {
213
+ int blocks = (bytes + 2) / datablock, b;
214
+ rs_init_gf (0x12d);
215
+ rs_init_code (rsblock, 1);
216
+ for (b = 0; b < blocks; b++)
217
+ {
218
+ unsigned char buf[256],
219
+ ecc[256];
220
+ int n,
221
+ p = 0;
222
+ for (n = b; n < bytes; n += blocks)
223
+ buf[p++] = binary[n];
224
+ rs_encode (p, buf, ecc);
225
+ p = rsblock - 1; // comes back reversed
226
+ for (n = b; n < rsblock * blocks; n += blocks)
227
+ binary[bytes + n] = ecc[p--];
228
+ }
229
+ }
230
+
231
+ // perform encoding for ecc200, source s len sl, to target t len tl, using optional encoding control string e
232
+ // return 1 if OK, 0 if failed. Does all necessary padding to tl
233
+ char
234
+ ecc200encode (unsigned char *t, int tl, unsigned char *s, int sl, char *encoding, int *lenp)
235
+ {
236
+ char enc = 'a'; // start in ASCII encoding mode
237
+ int tp = 0,
238
+ sp = 0;
239
+ if (strlen (encoding) < sl)
240
+ {
241
+ free(encoding);
242
+ rb_raise(rb_eArgError, "encoding string too short");
243
+ return 0;
244
+ }
245
+ // do the encoding
246
+ while (sp < sl && tp < tl)
247
+ {
248
+ char newenc = enc; // suggest new encoding
249
+ if (tl - tp <= 1 && (enc == 'c' || enc == 't') || tl - tp <= 2 && enc == 'x')
250
+ enc = 'a'; // auto revert to ASCII
251
+ newenc = tolower (encoding[sp]);
252
+ switch (newenc)
253
+ { // encode character
254
+ case 'c': // C40
255
+ case 't': // Text
256
+ case 'x': // X12
257
+ {
258
+ char out[6],
259
+ p = 0;
260
+ const char *e,
261
+ *s2 = "!\"#$%&'()*+,-./:;<=>?@[\\]_",
262
+ *s3 = 0;
263
+ if (newenc == 'c')
264
+ {
265
+ e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
266
+ s3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177";
267
+ }
268
+ if (newenc == 't')
269
+ {
270
+ e = " 0123456789abcdefghijklmnopqrstuvwxyz";
271
+ s3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177";
272
+ }
273
+ if (newenc == 'x')
274
+ e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\r*>";
275
+ do
276
+ {
277
+ unsigned char c = s[sp++];
278
+ char *w;
279
+ if (c & 0x80)
280
+ {
281
+ if (newenc == 'x')
282
+ {
283
+ free(encoding);
284
+ rb_raise(rb_eArgError, "cannot encode character in X12", c);
285
+ return 0;
286
+ }
287
+ c &= 0x7f;
288
+ out[p++] = 1;
289
+ out[p++] = 30;
290
+ }
291
+ w = strchr (e, c);
292
+ if (w)
293
+ out[p++] = ((w - e) + 3) % 40;
294
+ else
295
+ {
296
+ if (newenc == 'x')
297
+ {
298
+ free(encoding);
299
+ rb_raise(rb_eArgError, "cannot encode character in X12", c);
300
+ return 0;
301
+ }
302
+ if (c < 32)
303
+ { // shift 1
304
+ out[p++] = 0;
305
+ out[p++] = c;
306
+ } else
307
+ {
308
+ w = strchr (s2, c);
309
+ if (w)
310
+ { // shift 2
311
+ out[p++] = 1;
312
+ out[p++] = (w - s2);
313
+ } else
314
+ {
315
+ w = strchr (s3, c);
316
+ if (w)
317
+ {
318
+ out[p++] = 2;
319
+ out[p++] = (w - s3);
320
+ } else
321
+ {
322
+ free(encoding);
323
+ rb_raise(rb_eRuntimeError, "this should not be happening!", c);
324
+ return 0;
325
+ }
326
+ }
327
+ }
328
+ }
329
+ if (p == 2 && tp + 2 == tl && sp == sl)
330
+ out[p++] = 0; // shift 1 pad at end
331
+ while (p >= 3)
332
+ {
333
+ int v = out[0] * 1600 + out[1] * 40 + out[2] + 1;
334
+ if (enc != newenc)
335
+ {
336
+ if (enc == 'c' || enc == 't' || enc == 'x')
337
+ t[tp++] = 254; // escape C40/text/X12
338
+ else if (enc == 'x')
339
+ t[tp++] = 0x7C; // escape EDIFACT
340
+ if (newenc == 'c')
341
+ t[tp++] = 230;
342
+ if (newenc == 't')
343
+ t[tp++] = 239;
344
+ if (newenc == 'x')
345
+ t[tp++] = 238;
346
+ enc = newenc;
347
+ }
348
+ t[tp++] = (v >> 8);
349
+ t[tp++] = (v & 0xFF);
350
+ p -= 3;
351
+ out[0] = out[3];
352
+ out[1] = out[4];
353
+ out[2] = out[5];
354
+ }
355
+ }
356
+ while (p && sp < sl);
357
+ }
358
+ break;
359
+ case 'e': // EDIFACT
360
+ {
361
+ unsigned char out[4],
362
+ p = 0;
363
+ if (enc != newenc)
364
+ { // can only be from C40/Text/X12
365
+ t[tp++] = 254;
366
+ enc = 'a';
367
+ }
368
+ while (sp < sl && tolower (encoding[sp]) == 'e' && p < 4)
369
+ out[p++] = s[sp++];
370
+ if (p < 4)
371
+ {
372
+ out[p++] = 0x1F;
373
+ enc = 'a';
374
+ } // termination
375
+ t[tp] = ((s[0] & 0x3F) << 2);
376
+ t[tp++] |= ((s[1] & 0x30) >> 4);
377
+ t[tp] = ((s[1] & 0x0F) << 4);
378
+ if (p == 2)
379
+ tp++;
380
+ else
381
+ {
382
+ t[tp++] |= ((s[2] & 0x3C) >> 2);
383
+ t[tp] = ((s[2] & 0x03) << 6);
384
+ t[tp++] |= (s[3] & 0x3F);
385
+ }
386
+ }
387
+ break;
388
+ case 'a': // ASCII
389
+ if (enc != newenc)
390
+ {
391
+ if (enc == 'c' || enc == 't' || enc == 'x')
392
+ t[tp++] = 254; // escape C40/text/X12
393
+ else
394
+ t[tp++] = 0x7C; // escape EDIFACT
395
+ }
396
+ enc = 'a';
397
+ if (sl - sp >= 2 && isdigit (s[sp]) && isdigit (s[sp + 1]))
398
+ {
399
+ t[tp++] = (s[sp] - '0') * 10 + s[sp + 1] - '0' + 130;
400
+ sp += 2;
401
+ } else if (s[sp] > 127)
402
+ {
403
+ t[tp++] = 235;
404
+ t[tp++] = s[sp++] - 127;
405
+ } else
406
+ t[tp++] = s[sp++] + 1;
407
+ break;
408
+ case 'b': // Binary
409
+ {
410
+ int l = 0; // how much to encode
411
+ if (encoding)
412
+ {
413
+ int p;
414
+ for (p = sp; p < sl && tolower (encoding[p]) == 'b'; p++)
415
+ l++;
416
+ }
417
+ t[tp++] = 231; // base256
418
+ if (l < 250)
419
+ t[tp++] = l;
420
+ else
421
+ {
422
+ t[tp++] = 249 + (l / 250);
423
+ t[tp++] = (l % 250);
424
+ }
425
+ while (l-- && tp < tl)
426
+ {
427
+ t[tp] = s[sp++] + (((tp + 1) * 149) % 255) + 1; // see annex H
428
+ tp++;
429
+ }
430
+ enc = 'a'; // reverse to ASCII at end
431
+ }
432
+ break;
433
+ default:
434
+ free(encoding);
435
+ rb_raise(rb_eArgError, "unknown encoding attempted");
436
+ return 0; // failed
437
+ }
438
+ }
439
+ if (lenp)
440
+ *lenp = tp;
441
+ if (tp < tl && enc != 'a')
442
+ {
443
+ if (enc == 'c' || enc == 'x' || enc == 't')
444
+ t[tp++] = 254; // escape X12/C40/Text
445
+ else
446
+ t[tp++] = 0x7C; // escape EDIFACT
447
+ }
448
+ if (tp < tl)
449
+ t[tp++] = 129; // pad
450
+ while (tp < tl)
451
+ { // more padding
452
+ int v = 129 + (((tp + 1) * 149) % 253) + 1; // see Annex H
453
+ if (v > 254)
454
+ v -= 254;
455
+ t[tp++] = v;
456
+ }
457
+ if (tp > tl || sp < sl)
458
+ return 0; // did not fit
459
+ //for (tp = 0; tp < tl; tp++) rb_raise(rb_eRuntimeError, "%02X ", t[tp]); rb_raise(rb_eRuntimeError, "\n");
460
+ return 1; // OK
461
+ }
462
+
463
+ // Auto encoding format functions
464
+ static char encchr[] = "ACTXEB";
465
+
466
+ enum
467
+ {
468
+ E_ASCII,
469
+ E_C40,
470
+ E_TEXT,
471
+ E_X12,
472
+ E_EDIFACT,
473
+ E_BINARY,
474
+ E_MAX
475
+ };
476
+
477
+ unsigned char switchcost[E_MAX][E_MAX] = {
478
+ 0, 1, 1, 1, 1, 2, // From E_ASCII
479
+ 1, 0, 2, 2, 2, 3, // From E_C40
480
+ 1, 2, 0, 2, 2, 3, // From E_TEXT
481
+ 1, 2, 2, 0, 2, 3, // From E_X12
482
+ 1, 2, 2, 2, 0, 3, // From E_EDIFACT
483
+ 0, 1, 1, 1, 1, 0, // From E_BINARY
484
+ };
485
+
486
+ // Creates a encoding list (malloc)
487
+ // returns encoding string
488
+ // if lenp not null, target len stored
489
+ // if error, null returned
490
+ // if exact specified, then assumes shortcuts applicable for exact fit in target
491
+ // 1. No unlatch to return to ASCII for last encoded byte after C40 or Text or X12
492
+ // 2. No unlatch to return to ASCII for last 1 or 2 encoded bytes after EDIFACT
493
+ // 3. Final C40 or text encoding exactly in last 2 bytes can have a shift 0 to pad to make a tripple
494
+ // Only use the encoding from an exact request if the len matches the target, otherwise free the result and try again with exact=0
495
+ static char *
496
+ encmake (int l, unsigned char *s, int *lenp, char exact)
497
+ {
498
+ VALUE rb_str = NULL;
499
+ char *encoding = 0;
500
+ int p = l;
501
+ char e;
502
+ struct
503
+ {
504
+ short s; // number of bytes of source that can be encoded in a row at this point using this encoding mode
505
+ short t; // number of bytes of target generated encoding from this point to end if already in this encoding mode
506
+ } enc[MAXBARCODE][E_MAX];
507
+ memset (&enc, 0, sizeof (enc));
508
+ if (!l)
509
+ return ""; // no length
510
+ if (l > MAXBARCODE)
511
+ return 0; // not valid
512
+ while (p--)
513
+ {
514
+ char b = 0,
515
+ sub;
516
+ int sl,
517
+ tl,
518
+ bl,
519
+ t;
520
+ // consider each encoding from this point
521
+ // ASCII
522
+ sl = tl = 1;
523
+ if (isdigit (s[p]) && p + 1 < l && isdigit (s[p + 1]))
524
+ sl = 2; // double digit
525
+ else if (s[p] & 0x80)
526
+ tl = 2; // high shifted
527
+ bl = 0;
528
+ if (p + sl < l)
529
+ for (e = 0; e < E_MAX; e++)
530
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_ASCII][e]) < bl || !bl))
531
+ {
532
+ bl = t;
533
+ b = e;
534
+ }
535
+ enc[p][E_ASCII].t = tl + bl;
536
+ enc[p][E_ASCII].s = sl;
537
+ if (bl && b == E_ASCII)
538
+ enc[p][b].s += enc[p + sl][b].s;
539
+ // C40
540
+ sub = tl = sl = 0;
541
+ do
542
+ {
543
+ unsigned char c = s[p + sl++];
544
+ if (c & 0x80)
545
+ { // shift + upper
546
+ sub += 2;
547
+ c &= 0x7F;
548
+ }
549
+ if (c != ' ' && !isdigit (c) && !isupper (c))
550
+ sub++; // shift
551
+ sub++;
552
+ while (sub >= 3)
553
+ {
554
+ sub -= 3;
555
+ tl += 2;
556
+ }
557
+ } while (sub && p + sl < l);
558
+ if (exact && sub == 2 && p + sl == l)
559
+ { // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
560
+ sub = 0;
561
+ tl += 2;
562
+ }
563
+ if (!sub)
564
+ { // can encode C40
565
+ bl = 0;
566
+ if (p + sl < l)
567
+ for (e = 0; e < E_MAX; e++)
568
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_C40][e]) < bl || !bl))
569
+ {
570
+ bl = t;
571
+ b = e;
572
+ }
573
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
574
+ { // special case, switch to ASCII for last bytes
575
+ bl = 1;
576
+ b = E_ASCII;
577
+ }
578
+ enc[p][E_C40].t = tl + bl;
579
+ enc[p][E_C40].s = sl;
580
+ if (bl && b == E_C40)
581
+ enc[p][b].s += enc[p + sl][b].s;
582
+ }
583
+ // Text
584
+ sub = tl = sl = 0;
585
+ do
586
+ {
587
+ unsigned char c = s[p + sl++];
588
+ if (c & 0x80)
589
+ { // shift + upper
590
+ sub += 2;
591
+ c &= 0x7F;
592
+ }
593
+ if (c != ' ' && !isdigit (c) && !islower (c))
594
+ sub++; // shift
595
+ sub++;
596
+ while (sub >= 3)
597
+ {
598
+ sub -= 3;
599
+ tl += 2;
600
+ }
601
+ } while (sub && p + sl < l);
602
+ if (exact && sub == 2 && p + sl == l)
603
+ { // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
604
+ sub = 0;
605
+ tl += 2;
606
+ }
607
+ if (!sub && sl)
608
+ { // can encode Text
609
+ bl = 0;
610
+ if (p + sl < l)
611
+ for (e = 0; e < E_MAX; e++)
612
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_TEXT][e]) < bl || !bl))
613
+ {
614
+ bl = t;
615
+ b = e;
616
+ }
617
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
618
+ { // special case, switch to ASCII for last bytes
619
+ bl = 1;
620
+ b = E_ASCII;
621
+ }
622
+ enc[p][E_TEXT].t = tl + bl;
623
+ enc[p][E_TEXT].s = sl;
624
+ if (bl && b == E_TEXT)
625
+ enc[p][b].s += enc[p + sl][b].s;
626
+ }
627
+ // X12
628
+ sub = tl = sl = 0;
629
+ do
630
+ {
631
+ unsigned char c = s[p + sl++];
632
+ if (c != 13 && c != '*' && c != '>' && c != ' ' && !isdigit (c) && !isupper (c))
633
+ {
634
+ sl = 0;
635
+ break;
636
+ }
637
+ sub++;
638
+ while (sub >= 3)
639
+ {
640
+ sub -= 3;
641
+ tl += 2;
642
+ }
643
+ } while (sub && p + sl < l);
644
+ if (!sub && sl)
645
+ { // can encode X12
646
+ bl = 0;
647
+ if (p + sl < l)
648
+ for (e = 0; e < E_MAX; e++)
649
+ if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_X12][e]) < bl || !bl))
650
+ {
651
+ bl = t;
652
+ b = e;
653
+ }
654
+ if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
655
+ { // special case, switch to ASCII for last bytes
656
+ bl = 1;
657
+ b = E_ASCII;
658
+ }
659
+ enc[p][E_X12].t = tl + bl;
660
+ enc[p][E_X12].s = sl;
661
+ if (bl && b == E_X12)
662
+ enc[p][b].s += enc[p + sl][b].s;
663
+ }
664
+ // EDIFACT
665
+ sl = bl = 0;
666
+ if (s[p + 0] >= 32 && s[p + 0] <= 94)
667
+ { // can encode 1
668
+ char bs = 0;
669
+ if (p + 1 == l && (!bl || bl < 2))
670
+ {
671
+ bl = 2;
672
+ bs = 1;
673
+ } else
674
+ for (e = 0; e < E_MAX; e++)
675
+ if (e != E_EDIFACT && enc[p + 1][e].t && ((t = 2 + enc[p + 1][e].t + switchcost[E_ASCII][e]) < bl || !bl)) // E_ASCII as allowed for unlatch
676
+ {
677
+ bs = 1;
678
+ bl = t;
679
+ b = e;
680
+ }
681
+ if (p + 1 < l && s[p + 1] >= 32 && s[p + 1] <= 94)
682
+ { // can encode 2
683
+ if (p + 2 == l && (!bl || bl < 2))
684
+ {
685
+ bl = 3;
686
+ bs = 2;
687
+ } else
688
+ for (e = 0; e < E_MAX; e++)
689
+ if (e != E_EDIFACT && enc[p + 2][e].t && ((t = 3 + enc[p + 2][e].t + switchcost[E_ASCII][e]) < bl || !bl)) // E_ASCII as allowed for unlatch
690
+ {
691
+ bs = 2;
692
+ bl = t;
693
+ b = e;
694
+ }
695
+ if (p + 2 < l && s[p + 2] >= 32 && s[p + 2] <= 94)
696
+ { // can encode 3
697
+ if (p + 3 == l && (!bl || bl < 3))
698
+ {
699
+ bl = 3;
700
+ bs = 3;
701
+ } else
702
+ for (e = 0; e < E_MAX; e++)
703
+ if (e != E_EDIFACT && enc[p + 3][e].t && ((t = 3 + enc[p + 3][e].t + switchcost[E_ASCII][e]) < bl || !bl)) // E_ASCII as allowed for unlatch
704
+ {
705
+ bs = 3;
706
+ bl = t;
707
+ b = e;
708
+ }
709
+ if (p + 4 < l && s[p + 3] >= 32 && s[p + 3] <= 94)
710
+ { // can encode 4
711
+ if (p + 4 == l && (!bl || bl < 3))
712
+ {
713
+ bl = 3;
714
+ bs = 4;
715
+ } else
716
+ {
717
+ for (e = 0; e < E_MAX; e++)
718
+ if (enc[p + 4][e].t && ((t = 3 + enc[p + 4][e].t + switchcost[E_EDIFACT][e]) < bl || !bl))
719
+ {
720
+ bs = 4;
721
+ bl = t;
722
+ b = e;
723
+ }
724
+ if (exact && enc[p + 4][E_ASCII].t && enc[p + 4][E_ASCII].t <= 2 && (t = 3 + enc[p + 4][E_ASCII].t) < bl)
725
+ { // special case, switch to ASCII for last 1 ot two bytes
726
+ bs = 4;
727
+ bl = t;
728
+ b = E_ASCII;
729
+ }
730
+ }
731
+ }
732
+ }
733
+ }
734
+ enc[p][E_EDIFACT].t = bl;
735
+ enc[p][E_EDIFACT].s = bs;
736
+ if (bl && b == E_EDIFACT)
737
+ enc[p][b].s += enc[p + bs][b].s;
738
+ }
739
+ // Binary
740
+ bl = 0;
741
+ for (e = 0; e < E_MAX; e++)
742
+ if (enc[p + 1][e].t
743
+ && ((t = enc[p + 1][e].t + switchcost[E_BINARY][e] + ((e == E_BINARY && enc[p + 1][e].t == 249) ? 1 : 0)) < bl || !bl))
744
+ {
745
+ bl = t;
746
+ b = e;
747
+ }
748
+ enc[p][E_BINARY].t = 1 + bl;
749
+ enc[p][E_BINARY].s = 1;
750
+ if (bl && b == E_BINARY)
751
+ enc[p][b].s += enc[p + 1][b].s;
752
+ //rb_raise(rb_eRuntimeError, "%d:", p); for (e = 0; e < E_MAX; e++) rb_raise(rb_eRuntimeError, " %c*%d/%d", encchr[e], enc[p][e].s, enc[p][e].t); rb_raise(rb_eRuntimeError, "\n");
753
+ }
754
+ encoding = ALLOC_N(char, l + 1);
755
+ p = 0;
756
+ {
757
+ char cur = E_ASCII; // starts ASCII
758
+ while (p < l)
759
+ {
760
+ int t,
761
+ m = 0;
762
+ char b = 0;
763
+ for (e = 0; e < E_MAX; e++)
764
+ if (enc[p][e].t && ((t = enc[p][e].t + switchcost[cur][e]) < m || t == m && e == cur || !m))
765
+ {
766
+ b = e;
767
+ m = t;
768
+ }
769
+ cur = b;
770
+ m = enc[p][b].s;
771
+ if (!p && lenp)
772
+ *lenp = enc[p][b].t;
773
+ while (p < l && m--)
774
+ encoding[p++] = encchr[b];
775
+ }
776
+ }
777
+ encoding[p] = 0;
778
+ return encoding;
779
+ }
780
+
781
+ void iec16022init(int *Wptr, int *Hptr, const char *barcode)
782
+ {
783
+ if(Wptr == NULL || Hptr == NULL || barcode == NULL) return;
784
+
785
+ int barcodelen = strlen(barcode) + 1;
786
+ struct ecc200matrix_s *matrix;
787
+ for (matrix = ecc200matrix; matrix->bytes < barcodelen; matrix++);
788
+ *Wptr = matrix->W;
789
+ *Hptr = matrix->H;
790
+ }
791
+
792
+ // Main encoding function
793
+ // Returns the grid (malloced) containing the matrix. L corner at 0,0.
794
+ // Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
795
+ // Takes barcodelen and barcode to be encoded
796
+ // Note, if *encodingptr is null, then fills with auto picked (malloced) encoding
797
+ // If lenp not null, then the length of encoded data before any final unlatch or pad is stored
798
+ // If maxp not null, then the max storage of this size code is stored
799
+ // If eccp not null, then the number of ecc bytes used in this size is stored
800
+ // Returns 0 on error (writes to stderr with details).
801
+ unsigned char *
802
+ iec16022ecc200 (int *Wptr, int *Hptr, char **encodingptr, int barcodelen, unsigned char *barcode, int *lenp, int *maxp, int *eccp)
803
+ {
804
+ // GS
805
+ // max semacode size is 3116 (from iec16022ecc200.h)
806
+ // we over compensate and check that the input is within this length
807
+ // to avoid any buffer overflow conditions.
808
+ unsigned char binary[4096]; // encoded raw data and ecc to place in barcode
809
+ int W = 0,
810
+ H = 0;
811
+ char *encoding = 0;
812
+ unsigned char *grid = 0;
813
+ struct ecc200matrix_s *matrix;
814
+
815
+ // GS
816
+ // using the length from the 144x144 semacode in the matrix
817
+ // I don't trust the 3116 maximum length value ... and
818
+ // besides how many characters do you really need in a
819
+ // semacode?
820
+
821
+ if(barcodelen > 1556) {
822
+ rb_raise(rb_eRangeError, "barcode is too long (> 1556 chars)");
823
+ return NULL;
824
+ }
825
+
826
+ memset (binary, 0, sizeof (binary));
827
+ if (encodingptr)
828
+ encoding = *encodingptr;
829
+ if (Wptr)
830
+ W = *Wptr;
831
+ if (Hptr)
832
+ H = *Hptr;
833
+
834
+ // encoding
835
+ if (W)
836
+ { // known size
837
+ for (matrix = ecc200matrix; matrix->W && (matrix->W != W || matrix->H != H); matrix++);
838
+ if (!matrix->W)
839
+ {
840
+ rb_raise(rb_eRangeError, "invalid size for barcode");
841
+ return 0;
842
+ }
843
+ if (!encoding)
844
+ {
845
+ int len;
846
+ char *e = encmake (barcodelen, barcode, &len, 1);
847
+ if (e && len != matrix->bytes)
848
+ { // try not an exact fit
849
+ free (e);
850
+ e = encmake (barcodelen, barcode, &len, 0);
851
+ if (len > matrix->bytes)
852
+ {
853
+ free(e);
854
+ rb_raise(rb_eRangeError, "cannot make barcode fit");
855
+ return 0;
856
+ }
857
+ }
858
+ encoding = e;
859
+ }
860
+ } else
861
+ { // find size
862
+ if (encoding)
863
+ { // find one that fits chosen encoding
864
+ for (matrix = ecc200matrix; matrix->W; matrix++)
865
+ if (ecc200encode (binary, matrix->bytes, barcode, barcodelen, encoding, 0))
866
+ break;
867
+ } else
868
+ {
869
+ int len;
870
+ char *e;
871
+ e = encmake (barcodelen, barcode, &len, 1);
872
+ for (matrix = ecc200matrix; matrix->W && matrix->bytes != len; matrix++);
873
+ if (e && !matrix->W)
874
+ { // try for non exact fit
875
+ free (e);
876
+ e = encmake (barcodelen, barcode, &len, 0);
877
+ for (matrix = ecc200matrix; matrix->W && matrix->bytes < len; matrix++);
878
+ }
879
+ encoding = e;
880
+ }
881
+ if (!matrix->W)
882
+ {
883
+ free(encoding);
884
+ rb_raise(rb_eRangeError, "overlong barcode");
885
+ return 0;
886
+ }
887
+ W = matrix->W;
888
+ H = matrix->H;
889
+ }
890
+ if (!ecc200encode (binary, matrix->bytes, barcode, barcodelen, encoding, lenp))
891
+ {
892
+ free(encoding);
893
+ rb_raise(rb_eRangeError, "barcode too long for expected encoding");
894
+ return 0;
895
+ }
896
+ // ecc code
897
+ ecc200 (binary, matrix->bytes, matrix->datablock, matrix->rsblock);
898
+ { // placement
899
+ int x,
900
+ y,
901
+ NC,
902
+ NR,
903
+ *places;
904
+ NC = W - 2 * (W / matrix->FW);
905
+ NR = H - 2 * (H / matrix->FH);
906
+ places = ALLOC_N(int, NC * NR);
907
+ ecc200placement (places, NR, NC);
908
+ grid = ALLOC_N(char, W * H);
909
+ memset (grid, 0, W * H);
910
+ for (y = 0; y < H; y += matrix->FH)
911
+ {
912
+ for (x = 0; x < W; x++)
913
+ grid[y * W + x] = 1;
914
+ for (x = 0; x < W; x += 2)
915
+ grid[(y + matrix->FH - 1) * W + x] = 1;
916
+ }
917
+ for (x = 0; x < W; x += matrix->FW)
918
+ {
919
+ for (y = 0; y < H; y++)
920
+ grid[y * W + x] = 1;
921
+ for (y = 0; y < H; y += 2)
922
+ grid[y * W + x + matrix->FW - 1] = 1;
923
+ }
924
+ for (y = 0; y < NR; y++)
925
+ {
926
+ for (x = 0; x < NC; x++)
927
+ {
928
+ int v = places[(NR - y - 1) * NC + x];
929
+ //rb_raise(rb_eRuntimeError, "%4d", v);
930
+ if (v == 1 || v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))
931
+ grid[(1 + y + 2 * (y / (matrix->FH - 2))) * W + 1 + x + 2 * (x / (matrix->FW - 2))] = 1;
932
+ }
933
+ //rb_raise(rb_eRuntimeError, "\n");
934
+ }
935
+ free (places);
936
+ }
937
+ if (Wptr)
938
+ *Wptr = W;
939
+ if (Hptr)
940
+ *Hptr = H;
941
+ if (encodingptr)
942
+ *encodingptr = encoding;
943
+ else
944
+ free(encoding); // get rid of this if we aren't returning it
945
+ if (maxp)
946
+ *maxp = matrix->bytes;
947
+ if (eccp)
948
+ *eccp = (matrix->bytes + 2) / matrix->datablock * matrix->rsblock;
949
+ return grid;
950
+ }