semacode-ruby19 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }