data_matrix 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +5 -0
- data/Gemfile +5 -0
- data/README.md +36 -0
- data/Rakefile +13 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/data_matrix.gemspec +42 -0
- data/ext/data_matrix/data_matrix.c +206 -0
- data/ext/data_matrix/data_matrix.h +21 -0
- data/ext/data_matrix/extconf.rb +4 -0
- data/ext/data_matrix/iec16022ecc200.c +847 -0
- data/ext/data_matrix/iec16022ecc200.h +36 -0
- data/ext/data_matrix/reedsol.c +122 -0
- data/ext/data_matrix/reedsol.h +10 -0
- data/lib/data_matrix.rb +8 -0
- data/lib/data_matrix/encoder.rb +19 -0
- data/lib/data_matrix/version.rb +4 -0
- data/lib/semacode.rb +3 -0
- metadata +144 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4c4f71b784d1454fdc371e8565479b0404f5f4bc
|
4
|
+
data.tar.gz: e385701eaf8326b9a4fce2e04eb3414341643925
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 38213745494b7b57f1dfb489c778c1ff2c18274e88cbd0919337c158ec13a91101522f4f7a7f20b5d22c134da399aebd8d1967e37996ebed0114f94c2790d8a7
|
7
|
+
data.tar.gz: aee294d8edf2b0db6eee86d41ee79c4855a1f8cd7edcddd4fdbe6f3c0e73c9b7830534635edaac3a3cebdfd20e2bbef3d1076013952a0b44b727efda5790a0c4
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# DataMatrix
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/data_matrix`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'data_matrix'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install data_matrix
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/vessi/data_matrix.
|
36
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
require 'rake/extensiontask'
|
8
|
+
|
9
|
+
task build: :compile
|
10
|
+
|
11
|
+
Rake::ExtensionTask.new('data_matrix') { |ext| ext.lib_dir = 'lib/data_matrix' }
|
12
|
+
|
13
|
+
task default: %i(clobber compile spec)
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "data_matrix"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/data_matrix.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# coding: utf-8
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'data_matrix/version'
|
6
|
+
|
7
|
+
datamatrix_description = <<DESC
|
8
|
+
This Ruby extension implements a DataMatrix encoder for Ruby. It is typically
|
9
|
+
used to create semacodes, which are barcodes, that contain URLs. This encoder
|
10
|
+
does not create image files or visual representations of the semacode. This is
|
11
|
+
because it can be used for more than creating images, such as rendering
|
12
|
+
semacodes to HTML, SVG, PDF or even stored in a database or file for later
|
13
|
+
use.
|
14
|
+
DESC
|
15
|
+
|
16
|
+
Gem::Specification.new do |spec|
|
17
|
+
spec.name = 'data_matrix'
|
18
|
+
spec.version = DataMatrix::VERSION
|
19
|
+
spec.authors = ['Mikhail Bortnyk', 'Guido Sohne']
|
20
|
+
spec.email = %w(vessimir@gmail.com guido@sohne.net)
|
21
|
+
|
22
|
+
spec.summary = 'Create semacodes (2D barcodes) using Ruby.'
|
23
|
+
spec.description = datamatrix_description
|
24
|
+
spec.homepage = 'https://github.com/vessi/data_matrix'
|
25
|
+
|
26
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
27
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
28
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
|
29
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
30
|
+
|
31
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
32
|
+
spec.bindir = 'exe'
|
33
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
34
|
+
spec.require_paths = %w(lib)
|
35
|
+
spec.extensions = %w(ext/data_matrix/extconf.rb)
|
36
|
+
|
37
|
+
spec.add_development_dependency 'bundler', '~> 1.14'
|
38
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
39
|
+
spec.add_development_dependency 'rake-compiler'
|
40
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
41
|
+
spec.add_development_dependency 'rubocop'
|
42
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
#include "data_matrix.h"
|
2
|
+
|
3
|
+
VALUE rb_mDataMatrix, rb_cEncoder;
|
4
|
+
|
5
|
+
semacode_t* encode_string(semacode_t* semacode, const char *message) {
|
6
|
+
char* fixed_message;
|
7
|
+
|
8
|
+
if (semacode == NULL || message == NULL || strlen(message) < 1) {
|
9
|
+
return NULL;
|
10
|
+
}
|
11
|
+
|
12
|
+
fixed_message = malloc(sizeof(char) * strlen(message) + 1);
|
13
|
+
|
14
|
+
if (semacode->data != NULL) {
|
15
|
+
free(semacode->data);
|
16
|
+
}
|
17
|
+
if (semacode->encoding != NULL) {
|
18
|
+
free(semacode->encoding);
|
19
|
+
}
|
20
|
+
|
21
|
+
bzero(semacode, sizeof(semacode_t));
|
22
|
+
fixed_message = strdup(message);
|
23
|
+
strcat(fixed_message, " ");
|
24
|
+
|
25
|
+
iec16022init(&semacode->width, &semacode->height, fixed_message);
|
26
|
+
|
27
|
+
semacode->data = (char *) iec16022ecc200(&semacode->width, &semacode->height, &semacode->encoding,
|
28
|
+
(int) strlen(fixed_message), (unsigned char *) fixed_message,
|
29
|
+
&semacode->raw_encoded_length, &semacode->symbol_capacity,
|
30
|
+
&semacode->ecc_bytes);
|
31
|
+
|
32
|
+
free(fixed_message);
|
33
|
+
|
34
|
+
return semacode;
|
35
|
+
}
|
36
|
+
|
37
|
+
static void data_matrix_mark(semacode_t* semacode) {
|
38
|
+
semacode->width = 0;
|
39
|
+
semacode->height = 0;
|
40
|
+
semacode->raw_encoded_length = 0;
|
41
|
+
semacode->symbol_capacity = 0;
|
42
|
+
semacode->ecc_bytes = 0;
|
43
|
+
semacode->encoding = NULL;
|
44
|
+
semacode->data = NULL;
|
45
|
+
}
|
46
|
+
|
47
|
+
static void data_matrix_free(semacode_t* semacode) {
|
48
|
+
if (semacode != NULL) {
|
49
|
+
if (semacode->data != NULL) {
|
50
|
+
free(semacode->encoding);
|
51
|
+
free(semacode->data);
|
52
|
+
}
|
53
|
+
bzero(semacode, sizeof(semacode));
|
54
|
+
free(semacode);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
static VALUE data_matrix_grid(semacode_t *semacode) {
|
59
|
+
int w = semacode->width;
|
60
|
+
int h = semacode->height;
|
61
|
+
|
62
|
+
VALUE ret = rb_ary_new2(h);
|
63
|
+
|
64
|
+
int x, y;
|
65
|
+
for (y = h - 1; y >= 0; y--) {
|
66
|
+
VALUE ary = rb_ary_new2(w);
|
67
|
+
for (x = 0; x < w; x++) {
|
68
|
+
if(semacode->data[y * w + x])
|
69
|
+
rb_ary_push(ary, Qtrue);
|
70
|
+
else
|
71
|
+
rb_ary_push(ary, Qfalse);
|
72
|
+
}
|
73
|
+
rb_ary_push(ret, ary);
|
74
|
+
}
|
75
|
+
|
76
|
+
return ret;
|
77
|
+
}
|
78
|
+
|
79
|
+
static VALUE data_matrix_allocate(VALUE klass) {
|
80
|
+
semacode_t *semacode;
|
81
|
+
return Data_Make_Struct(klass, semacode_t, data_matrix_mark, data_matrix_free, semacode);
|
82
|
+
}
|
83
|
+
|
84
|
+
static VALUE data_matrix_init(VALUE self, VALUE message) {
|
85
|
+
semacode_t *semacode;
|
86
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
87
|
+
|
88
|
+
encode_string(semacode, StringValuePtr(message));
|
89
|
+
|
90
|
+
return self;
|
91
|
+
}
|
92
|
+
|
93
|
+
static VALUE data_matrix_encode(VALUE self, VALUE encoding) {
|
94
|
+
semacode_t *semacode;
|
95
|
+
|
96
|
+
if (!rb_respond_to(encoding, rb_intern ("to_s")))
|
97
|
+
rb_raise(rb_eRuntimeError, "target must respond to 'to_s'");
|
98
|
+
|
99
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
100
|
+
|
101
|
+
/* free previous string if that exists */
|
102
|
+
if(semacode->data != NULL) {
|
103
|
+
free(semacode->data);
|
104
|
+
semacode->data = NULL;
|
105
|
+
}
|
106
|
+
|
107
|
+
/* do a new encoding */
|
108
|
+
DATA_PTR(self) = encode_string(semacode, StringValuePtr(encoding));
|
109
|
+
return data_matrix_grid(semacode);
|
110
|
+
}
|
111
|
+
|
112
|
+
static VALUE data_matrix_data(VALUE self) {
|
113
|
+
semacode_t *semacode;
|
114
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
115
|
+
|
116
|
+
if(semacode->data == NULL)
|
117
|
+
return Qnil;
|
118
|
+
else
|
119
|
+
return data_matrix_grid(semacode);
|
120
|
+
}
|
121
|
+
|
122
|
+
static VALUE data_matrix_encoded(VALUE self) {
|
123
|
+
semacode_t *semacode;
|
124
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
125
|
+
|
126
|
+
return rb_str_new2(semacode->encoding);
|
127
|
+
}
|
128
|
+
|
129
|
+
static VALUE data_matrix_to_s(VALUE self) {
|
130
|
+
semacode_t *semacode;
|
131
|
+
VALUE str;
|
132
|
+
int x, y, w, h;
|
133
|
+
|
134
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
135
|
+
|
136
|
+
if(semacode == NULL || semacode->data == NULL) return Qnil;
|
137
|
+
|
138
|
+
w = semacode->width;
|
139
|
+
h = semacode->height;
|
140
|
+
|
141
|
+
str = rb_str_new2("");
|
142
|
+
|
143
|
+
for (y = h - 1; y >= 0; y--) {
|
144
|
+
for (x = 0; x < w; x++) {
|
145
|
+
if(semacode->data[y * w + x])
|
146
|
+
rb_str_cat(str, "1", 1);
|
147
|
+
else
|
148
|
+
rb_str_cat(str, "0", 1);
|
149
|
+
}
|
150
|
+
rb_str_cat(str, ",", 1);
|
151
|
+
}
|
152
|
+
return str;
|
153
|
+
}
|
154
|
+
|
155
|
+
static VALUE data_matrix_width(VALUE self) {
|
156
|
+
semacode_t *semacode;
|
157
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
158
|
+
|
159
|
+
return INT2FIX(semacode->width);
|
160
|
+
}
|
161
|
+
|
162
|
+
static VALUE data_matrix_height(VALUE self) {
|
163
|
+
semacode_t *semacode;
|
164
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
165
|
+
|
166
|
+
return INT2FIX(semacode->height);
|
167
|
+
}
|
168
|
+
|
169
|
+
static VALUE data_matrix_raw_encoded_length(VALUE self) {
|
170
|
+
semacode_t *semacode;
|
171
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
172
|
+
|
173
|
+
return INT2FIX(semacode->raw_encoded_length);
|
174
|
+
}
|
175
|
+
|
176
|
+
static VALUE data_matrix_symbol_size(VALUE self) {
|
177
|
+
semacode_t *semacode;
|
178
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
179
|
+
|
180
|
+
return INT2FIX(semacode->symbol_capacity);
|
181
|
+
}
|
182
|
+
|
183
|
+
static VALUE data_matrix_ecc_bytes(VALUE self) {
|
184
|
+
semacode_t *semacode;
|
185
|
+
Data_Get_Struct(self, semacode_t, semacode);
|
186
|
+
|
187
|
+
return INT2FIX(semacode->ecc_bytes);
|
188
|
+
}
|
189
|
+
|
190
|
+
void Init_data_matrix(void) {
|
191
|
+
rb_mDataMatrix = rb_define_module("DataMatrix");
|
192
|
+
rb_cEncoder = rb_define_class_under(rb_mDataMatrix, "Encoder", rb_cObject);
|
193
|
+
|
194
|
+
rb_define_alloc_func(rb_cEncoder, data_matrix_allocate);
|
195
|
+
|
196
|
+
rb_define_method(rb_cEncoder, "encode_string", data_matrix_init, 1);
|
197
|
+
rb_define_method(rb_cEncoder, "encode", data_matrix_encode, 1);
|
198
|
+
rb_define_method(rb_cEncoder, "data", data_matrix_data, 0);
|
199
|
+
rb_define_method(rb_cEncoder, "encoding", data_matrix_encoded, 0);
|
200
|
+
rb_define_method(rb_cEncoder, "to_s", data_matrix_to_s, 0);
|
201
|
+
rb_define_method(rb_cEncoder, "width", data_matrix_width, 0);
|
202
|
+
rb_define_method(rb_cEncoder, "height", data_matrix_height, 0);
|
203
|
+
rb_define_method(rb_cEncoder, "raw_encoded_length", data_matrix_raw_encoded_length, 0);
|
204
|
+
rb_define_method(rb_cEncoder, "symbol_size", data_matrix_symbol_size, 0);
|
205
|
+
rb_define_method(rb_cEncoder, "ecc_bytes", data_matrix_ecc_bytes, 0);
|
206
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#ifndef DATA_MATRIX_H
|
2
|
+
#define DATA_MATRIX_H 1
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "iec16022ecc200.h"
|
6
|
+
|
7
|
+
typedef struct semacode_t {
|
8
|
+
int width;
|
9
|
+
int height;
|
10
|
+
int raw_encoded_length;
|
11
|
+
int symbol_capacity;
|
12
|
+
int ecc_bytes;
|
13
|
+
char *encoding;
|
14
|
+
char *data;
|
15
|
+
} semacode_t;
|
16
|
+
|
17
|
+
semacode_t* encode_string(semacode_t* semacode, const char *message);
|
18
|
+
static void data_matrix_mark(semacode_t* semacode);
|
19
|
+
static void data_matrix_free(semacode_t* semacode);
|
20
|
+
|
21
|
+
#endif /* DATA_MATRIX_H */
|
@@ -0,0 +1,847 @@
|
|
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 <stdlib.h>
|
27
|
+
#include <ctype.h>
|
28
|
+
#include <string.h>
|
29
|
+
#include <time.h>
|
30
|
+
#include "reedsol.h"
|
31
|
+
#include "iec16022ecc200.h"
|
32
|
+
|
33
|
+
static struct ecc200matrix_s {
|
34
|
+
int H, W, FH, FW, bytes, datablock, rsblock;
|
35
|
+
}
|
36
|
+
|
37
|
+
const ecc200matrix[] = {
|
38
|
+
{10, 10, 10, 10, 3, 3, 5}, //
|
39
|
+
{12, 12, 12, 12, 5, 5, 7}, //
|
40
|
+
{14, 14, 14, 14, 8, 8, 10}, //
|
41
|
+
{16, 16, 16, 16, 12, 12, 12}, //
|
42
|
+
{18, 18, 18, 18, 18, 18, 14}, //
|
43
|
+
{20, 20, 20, 20, 22, 22, 18}, //
|
44
|
+
{22, 22, 22, 22, 30, 30, 20}, //
|
45
|
+
{24, 24, 24, 24, 36, 36, 24}, //
|
46
|
+
{26, 26, 26, 26, 44, 44, 28}, //
|
47
|
+
{32, 32, 16, 16, 62, 62, 36}, //
|
48
|
+
{36, 36, 18, 18, 86, 86, 42}, //
|
49
|
+
{40, 40, 20, 20, 114, 114, 48}, //
|
50
|
+
{44, 44, 22, 22, 144, 144, 56}, //
|
51
|
+
{48, 48, 24, 24, 174, 174, 68}, //
|
52
|
+
{52, 52, 26, 26, 204, 102, 42}, //
|
53
|
+
{64, 64, 16, 16, 280, 140, 56}, //
|
54
|
+
{72, 72, 18, 18, 368, 92, 36}, //
|
55
|
+
{80, 80, 20, 20, 456, 114, 48}, //
|
56
|
+
{88, 88, 22, 22, 576, 144, 56}, //
|
57
|
+
{96, 96, 24, 24, 696, 174, 68}, //
|
58
|
+
{104, 104, 26, 26, 816, 136, 56}, //
|
59
|
+
{120, 120, 20, 20, 1050, 175, 68}, //
|
60
|
+
{132, 132, 22, 22, 1304, 163, 62}, //
|
61
|
+
{144, 144, 24, 24, 1558, 156, 62}, // 156*4+155*2
|
62
|
+
{0} // terminate
|
63
|
+
};
|
64
|
+
|
65
|
+
// Auto encoding format functions
|
66
|
+
static char encchr[] = "ACTXEB";
|
67
|
+
|
68
|
+
enum {
|
69
|
+
E_ASCII,
|
70
|
+
E_C40,
|
71
|
+
E_TEXT,
|
72
|
+
E_X12,
|
73
|
+
E_EDIFACT,
|
74
|
+
E_BINARY,
|
75
|
+
E_MAX
|
76
|
+
};
|
77
|
+
|
78
|
+
unsigned char switchcost[E_MAX][E_MAX] = {
|
79
|
+
{0, 1, 1, 1, 1, 2}, // From E_ASCII
|
80
|
+
{1, 0, 2, 2, 2, 3}, // From E_C40
|
81
|
+
{1, 2, 0, 2, 2, 3}, // From E_TEXT
|
82
|
+
{1, 2, 2, 0, 2, 3}, // From E_X12
|
83
|
+
{1, 2, 2, 2, 0, 3}, // From E_EDIFACT
|
84
|
+
{0, 1, 1, 1, 1, 0}, // From E_BINARY
|
85
|
+
};
|
86
|
+
|
87
|
+
// Annex M placement alorithm low level
|
88
|
+
static void ecc200placementbit(int *array, int NR, int NC, int r, int c, int p, char b) {
|
89
|
+
if (r < 0) {
|
90
|
+
r += NR;
|
91
|
+
c += 4 - ((NR + 4) % 8);
|
92
|
+
}
|
93
|
+
if (c < 0) {
|
94
|
+
c += NC;
|
95
|
+
r += 4 - ((NC + 4) % 8);
|
96
|
+
}
|
97
|
+
array[r * NC + c] = (p << 3) + b;
|
98
|
+
}
|
99
|
+
|
100
|
+
static void ecc200placementblock(int *array, int NR, int NC, int r, int c, int p) {
|
101
|
+
ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7);
|
102
|
+
ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6);
|
103
|
+
ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5);
|
104
|
+
ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4);
|
105
|
+
ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3);
|
106
|
+
ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2);
|
107
|
+
ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1);
|
108
|
+
ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0);
|
109
|
+
}
|
110
|
+
|
111
|
+
static void ecc200placementcornerA(int *array, int NR, int NC, int p) {
|
112
|
+
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
|
113
|
+
ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6);
|
114
|
+
ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5);
|
115
|
+
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
|
116
|
+
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
|
117
|
+
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
|
118
|
+
ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
|
119
|
+
ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
|
120
|
+
}
|
121
|
+
|
122
|
+
static void ecc200placementcornerB(int *array, int NR, int NC, int p) {
|
123
|
+
ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
|
124
|
+
ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
|
125
|
+
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
|
126
|
+
ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4);
|
127
|
+
ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3);
|
128
|
+
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2);
|
129
|
+
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1);
|
130
|
+
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
|
131
|
+
}
|
132
|
+
|
133
|
+
static void ecc200placementcornerC(int *array, int NR, int NC, int p) {
|
134
|
+
ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
|
135
|
+
ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
|
136
|
+
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
|
137
|
+
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
|
138
|
+
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
|
139
|
+
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
|
140
|
+
ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
|
141
|
+
ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
|
142
|
+
}
|
143
|
+
|
144
|
+
static void ecc200placementcornerD(int *array, int NR, int NC, int p) {
|
145
|
+
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
|
146
|
+
ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6);
|
147
|
+
ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5);
|
148
|
+
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
|
149
|
+
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
|
150
|
+
ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2);
|
151
|
+
ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1);
|
152
|
+
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
|
153
|
+
}
|
154
|
+
|
155
|
+
// Annex M placement alorithm main function
|
156
|
+
static void ecc200placement(int *array, int NR, int NC) {
|
157
|
+
int r, c, p;
|
158
|
+
// invalidate
|
159
|
+
for (r = 0; r < NR; r++)
|
160
|
+
for (c = 0; c < NC; c++)
|
161
|
+
array[r * NC + c] = 0;
|
162
|
+
// start
|
163
|
+
p = 1;
|
164
|
+
r = 4;
|
165
|
+
c = 0;
|
166
|
+
do {
|
167
|
+
// check corner
|
168
|
+
if (r == NR && !c)
|
169
|
+
ecc200placementcornerA(array, NR, NC, p++);
|
170
|
+
if (r == NR - 2 && !c && NC % 4)
|
171
|
+
ecc200placementcornerB(array, NR, NC, p++);
|
172
|
+
if (r == NR - 2 && !c && (NC % 8) == 4)
|
173
|
+
ecc200placementcornerC(array, NR, NC, p++);
|
174
|
+
if (r == NR + 4 && c == 2 && !(NC % 8))
|
175
|
+
ecc200placementcornerD(array, NR, NC, p++);
|
176
|
+
// up/right
|
177
|
+
do {
|
178
|
+
if (r < NR && c >= 0 && !array[r * NC + c])
|
179
|
+
ecc200placementblock(array, NR, NC, r, c, p++);
|
180
|
+
r -= 2;
|
181
|
+
c += 2;
|
182
|
+
} while (r >= 0 && c < NC);
|
183
|
+
r++;
|
184
|
+
c += 3;
|
185
|
+
// down/left
|
186
|
+
do {
|
187
|
+
if (r >= 0 && c < NC && !array[r * NC + c])
|
188
|
+
ecc200placementblock (array, NR, NC, r, c, p++);
|
189
|
+
r += 2;
|
190
|
+
c -= 2;
|
191
|
+
} while (r < NR && c >= 0);
|
192
|
+
r += 3;
|
193
|
+
c++;
|
194
|
+
} while (r < NR || c < NC);
|
195
|
+
// unfilled corner
|
196
|
+
if (!array[NR * NC - 1])
|
197
|
+
array[NR * NC - 1] = array[NR * NC - NC - 2] = 1;
|
198
|
+
}
|
199
|
+
|
200
|
+
// calculate and append ecc code, and if necessary interleave
|
201
|
+
static void ecc200(unsigned char *binary, int bytes, int datablock, int rsblock) {
|
202
|
+
int blocks = (bytes + 2) / datablock, b;
|
203
|
+
rs_init_gf(0x12d);
|
204
|
+
rs_init_code(rsblock, 1);
|
205
|
+
for (b = 0; b < blocks; b++) {
|
206
|
+
unsigned char buf[256], ecc[256];
|
207
|
+
int n, p = 0;
|
208
|
+
for (n = b; n < bytes; n += blocks)
|
209
|
+
buf[p++] = binary[n];
|
210
|
+
rs_encode(p, buf, ecc);
|
211
|
+
p = rsblock - 1; // comes back reversed
|
212
|
+
for (n = b; n < rsblock * blocks; n += blocks)
|
213
|
+
binary[bytes + n] = ecc[p--];
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
// perform encoding for ecc200, source s len sl, to target t len tl, using optional encoding control string e
|
218
|
+
// return 1 if OK, 0 if failed. Does all necessary padding to tl
|
219
|
+
char ecc200encode(unsigned char *t, unsigned int tl, const unsigned char *s, const unsigned int sl, char *encoding, int *lenp) {
|
220
|
+
char enc = 'a'; // start in ASCII encoding mode
|
221
|
+
unsigned int tp = 0, sp = 0;
|
222
|
+
if (strlen(encoding) < sl) {
|
223
|
+
free(encoding);
|
224
|
+
//TODO: Insert return with return code here
|
225
|
+
return 0;
|
226
|
+
}
|
227
|
+
// do the encoding
|
228
|
+
while (sp < sl && tp < tl) {
|
229
|
+
char newenc = enc; // suggest new encoding
|
230
|
+
if (tl - tp <= 1 && (enc == 'c' || enc == 't') || tl - tp <= 2 && enc == 'x')
|
231
|
+
enc = 'a'; // auto revert to ASCII
|
232
|
+
newenc = tolower(encoding[sp]);
|
233
|
+
switch (newenc) {
|
234
|
+
// encode character
|
235
|
+
case 'c': // C40
|
236
|
+
case 't': // Text
|
237
|
+
case 'x': // X12
|
238
|
+
{
|
239
|
+
char out[6];
|
240
|
+
unsigned char p = 0;
|
241
|
+
const char *e, *s2 = "!\"#$%&'()*+,-./:;<=>?@[\\]_", *s3 = 0;
|
242
|
+
if (newenc == 'c') {
|
243
|
+
e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
244
|
+
s3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177";
|
245
|
+
}
|
246
|
+
if (newenc == 't')
|
247
|
+
{
|
248
|
+
e = " 0123456789abcdefghijklmnopqrstuvwxyz";
|
249
|
+
s3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177";
|
250
|
+
}
|
251
|
+
if (newenc == 'x')
|
252
|
+
e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\r*>";
|
253
|
+
do
|
254
|
+
{
|
255
|
+
unsigned char c = s[sp++];
|
256
|
+
char *w;
|
257
|
+
if (c & 0x80)
|
258
|
+
{
|
259
|
+
if (newenc == 'x')
|
260
|
+
{
|
261
|
+
free(encoding);
|
262
|
+
//TODO: Insert rb_raise(rb_eArgError, "cannot encode character in X12", c);
|
263
|
+
return 0;
|
264
|
+
}
|
265
|
+
c &= 0x7f;
|
266
|
+
out[p++] = 1;
|
267
|
+
out[p++] = 30;
|
268
|
+
}
|
269
|
+
w = strchr (e, c);
|
270
|
+
if (w)
|
271
|
+
out[p++] = ((w - e) + 3) % 40;
|
272
|
+
else
|
273
|
+
{
|
274
|
+
if (newenc == 'x')
|
275
|
+
{
|
276
|
+
free(encoding);
|
277
|
+
//TODO: rb_raise(rb_eArgError, "cannot encode character in X12", c);
|
278
|
+
return 0;
|
279
|
+
}
|
280
|
+
if (c < 32)
|
281
|
+
{ // shift 1
|
282
|
+
out[p++] = 0;
|
283
|
+
out[p++] = c;
|
284
|
+
} else
|
285
|
+
{
|
286
|
+
w = strchr (s2, c);
|
287
|
+
if (w)
|
288
|
+
{ // shift 2
|
289
|
+
out[p++] = 1;
|
290
|
+
out[p++] = (w - s2);
|
291
|
+
} else
|
292
|
+
{
|
293
|
+
w = strchr (s3, c);
|
294
|
+
if (w)
|
295
|
+
{
|
296
|
+
out[p++] = 2;
|
297
|
+
out[p++] = (w - s3);
|
298
|
+
} else
|
299
|
+
{
|
300
|
+
free(encoding);
|
301
|
+
//TODO: rb_raise(rb_eRuntimeError, "this should not be happening!", c);
|
302
|
+
return 0;
|
303
|
+
}
|
304
|
+
}
|
305
|
+
}
|
306
|
+
}
|
307
|
+
if (p == 2 && tp + 2 == tl && sp == sl)
|
308
|
+
out[p++] = 0; // shift 1 pad at end
|
309
|
+
while (p >= 3)
|
310
|
+
{
|
311
|
+
int v = out[0] * 1600 + out[1] * 40 + out[2] + 1;
|
312
|
+
if (enc != newenc)
|
313
|
+
{
|
314
|
+
if (enc == 'c' || enc == 't' || enc == 'x')
|
315
|
+
t[tp++] = 254; // escape C40/text/X12
|
316
|
+
else if (enc == 'x')
|
317
|
+
t[tp++] = 0x7C; // escape EDIFACT
|
318
|
+
if (newenc == 'c')
|
319
|
+
t[tp++] = 230;
|
320
|
+
if (newenc == 't')
|
321
|
+
t[tp++] = 239;
|
322
|
+
if (newenc == 'x')
|
323
|
+
t[tp++] = 238;
|
324
|
+
enc = newenc;
|
325
|
+
}
|
326
|
+
t[tp++] = (v >> 8);
|
327
|
+
t[tp++] = (v & 0xFF);
|
328
|
+
p -= 3;
|
329
|
+
out[0] = out[3];
|
330
|
+
out[1] = out[4];
|
331
|
+
out[2] = out[5];
|
332
|
+
}
|
333
|
+
}
|
334
|
+
while (p && sp < sl);
|
335
|
+
}
|
336
|
+
break;
|
337
|
+
case 'e': // EDIFACT
|
338
|
+
{
|
339
|
+
char out[4];
|
340
|
+
unsigned char p = 0;
|
341
|
+
if (enc != newenc) {
|
342
|
+
// can only be from C40/Text/X12
|
343
|
+
t[tp++] = 254;
|
344
|
+
enc = 'a';
|
345
|
+
}
|
346
|
+
while (sp < sl && tolower (encoding[sp]) == 'e' && p < 4)
|
347
|
+
out[p++] = s[sp++];
|
348
|
+
if (p < 4) {
|
349
|
+
out[p++] = 0x1F;
|
350
|
+
enc = 'a';
|
351
|
+
} // termination
|
352
|
+
t[tp] = ((s[0] & 0x3F) << 2);
|
353
|
+
t[tp++] |= ((s[1] & 0x30) >> 4);
|
354
|
+
t[tp] = ((s[1] & 0x0F) << 4);
|
355
|
+
if (p == 2)
|
356
|
+
tp++;
|
357
|
+
else {
|
358
|
+
t[tp++] |= ((s[2] & 0x3C) >> 2);
|
359
|
+
t[tp] = ((s[2] & 0x03) << 6);
|
360
|
+
t[tp++] |= (s[3] & 0x3F);
|
361
|
+
}
|
362
|
+
}
|
363
|
+
break;
|
364
|
+
case 'a': // ASCII
|
365
|
+
if (enc != newenc) {
|
366
|
+
if (enc == 'c' || enc == 't' || enc == 'x')
|
367
|
+
t[tp++] = 254; // escape C40/text/X12
|
368
|
+
else
|
369
|
+
t[tp++] = 0x7C; // escape EDIFACT
|
370
|
+
}
|
371
|
+
enc = 'a';
|
372
|
+
if (sl - sp >= 2 && isdigit(s[sp]) && isdigit(s[sp + 1])) {
|
373
|
+
t[tp++] = (s[sp] - '0') * 10 + s[sp + 1] - '0' + 130;
|
374
|
+
sp += 2;
|
375
|
+
} else
|
376
|
+
if (s[sp] > 127) {
|
377
|
+
t[tp++] = 235;
|
378
|
+
t[tp++] = s[sp++] - 127;
|
379
|
+
} else
|
380
|
+
t[tp++] = s[sp++] + 1;
|
381
|
+
break;
|
382
|
+
case 'b': // Binary
|
383
|
+
{
|
384
|
+
int l = 0; // how much to encode
|
385
|
+
if (encoding) {
|
386
|
+
unsigned int p;
|
387
|
+
for (p = sp; p < sl && tolower(encoding[p]) == 'b'; p++)
|
388
|
+
l++;
|
389
|
+
}
|
390
|
+
t[tp++] = 231; // base256
|
391
|
+
if (l < 250)
|
392
|
+
t[tp++] = l;
|
393
|
+
else {
|
394
|
+
t[tp++] = 249 + (l / 250);
|
395
|
+
t[tp++] = (l % 250);
|
396
|
+
}
|
397
|
+
while (l-- && tp < tl) {
|
398
|
+
t[tp] = s[sp++] + (((tp + 1) * 149) % 255) + 1; // see annex H
|
399
|
+
tp++;
|
400
|
+
}
|
401
|
+
enc = 'a'; // reverse to ASCII at end
|
402
|
+
}
|
403
|
+
break;
|
404
|
+
default:
|
405
|
+
free(encoding);
|
406
|
+
//TODO: rb_raise(rb_eArgError, "unknown encoding attempted");
|
407
|
+
return 0; // failed
|
408
|
+
}
|
409
|
+
}
|
410
|
+
if (lenp)
|
411
|
+
*lenp = tp;
|
412
|
+
if (tp < tl && enc != 'a') {
|
413
|
+
if (enc == 'c' || enc == 'x' || enc == 't')
|
414
|
+
t[tp++] = 254; // escape X12/C40/Text
|
415
|
+
else
|
416
|
+
t[tp++] = 0x7C; // escape EDIFACT
|
417
|
+
}
|
418
|
+
if (tp < tl)
|
419
|
+
t[tp++] = 129; // pad
|
420
|
+
while (tp < tl) {
|
421
|
+
// more padding
|
422
|
+
int v = 129 + (((tp + 1) * 149) % 253) + 1; // see Annex H
|
423
|
+
if (v > 254)
|
424
|
+
v -= 254;
|
425
|
+
t[tp++] = v;
|
426
|
+
}
|
427
|
+
if (tp > tl || sp < sl)
|
428
|
+
return 0; // did not fit
|
429
|
+
return 1; // OK
|
430
|
+
}
|
431
|
+
|
432
|
+
// Creates a encoding list (malloc)
|
433
|
+
// returns encoding string
|
434
|
+
// if lenp not null, target len stored
|
435
|
+
// if error, null returned
|
436
|
+
// if exact specified, then assumes shortcuts applicable for exact fit in target
|
437
|
+
// 1. No unlatch to return to ASCII for last encoded byte after C40 or Text or X12
|
438
|
+
// 2. No unlatch to return to ASCII for last 1 or 2 encoded bytes after EDIFACT
|
439
|
+
// 3. Final C40 or text encoding exactly in last 2 bytes can have a shift 0 to pad to make a tripple
|
440
|
+
// Only use the encoding from an exact request if the len matches the target, otherwise free the result and try again with exact=0
|
441
|
+
static char* encmake(const unsigned int l, const unsigned char *s, int *lenp, char exact) {
|
442
|
+
char *encoding = 0;
|
443
|
+
unsigned int p = l;
|
444
|
+
unsigned char e;
|
445
|
+
struct {
|
446
|
+
short s; // number of bytes of source that can be encoded in a row at this point using this encoding mode
|
447
|
+
short t; // number of bytes of target generated encoding from this point to end if already in this encoding mode
|
448
|
+
} enc[IEC16022ECC200_MAXBARCODE][E_MAX];
|
449
|
+
memset(&enc, 0, sizeof (enc));
|
450
|
+
if (!l)
|
451
|
+
return ""; // no length
|
452
|
+
if (l > IEC16022ECC200_MAXBARCODE)
|
453
|
+
return 0; // not valid
|
454
|
+
while (p--) {
|
455
|
+
unsigned char b = 0;
|
456
|
+
char sub;
|
457
|
+
int sl, tl, bl, t;
|
458
|
+
// consider each encoding from this point
|
459
|
+
// ASCII
|
460
|
+
sl = tl = 1;
|
461
|
+
if (isdigit(s[p]) && p + 1 < l && isdigit(s[p + 1]))
|
462
|
+
sl = 2; // double digit
|
463
|
+
else
|
464
|
+
if (s[p] & 0x80)
|
465
|
+
tl = 2; // high shifted
|
466
|
+
bl = 0;
|
467
|
+
if (p + sl < l)
|
468
|
+
for (e = 0; e < E_MAX; e++)
|
469
|
+
if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
|
470
|
+
bl = t;
|
471
|
+
b = e;
|
472
|
+
}
|
473
|
+
enc[p][E_ASCII].t = tl + bl;
|
474
|
+
enc[p][E_ASCII].s = sl;
|
475
|
+
if (bl && b == E_ASCII)
|
476
|
+
enc[p][b].s += enc[p + sl][b].s;
|
477
|
+
// C40
|
478
|
+
sub = tl = sl = 0;
|
479
|
+
do {
|
480
|
+
unsigned char c = s[p + sl++];
|
481
|
+
if (c & 0x80) {
|
482
|
+
// shift + upper
|
483
|
+
sub += 2;
|
484
|
+
c &= 0x7F;
|
485
|
+
}
|
486
|
+
if (c != ' ' && !isdigit (c) && !isupper (c))
|
487
|
+
sub++; // shift
|
488
|
+
sub++;
|
489
|
+
while (sub >= 3) {
|
490
|
+
sub -= 3;
|
491
|
+
tl += 2;
|
492
|
+
}
|
493
|
+
} while (sub && p + sl < l);
|
494
|
+
if (exact && sub == 2 && p + sl == l) {
|
495
|
+
// special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
|
496
|
+
sub = 0;
|
497
|
+
tl += 2;
|
498
|
+
}
|
499
|
+
if (!sub) {
|
500
|
+
// can encode C40
|
501
|
+
bl = 0;
|
502
|
+
if (p + sl < l)
|
503
|
+
for (e = 0; e < E_MAX; e++)
|
504
|
+
if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_C40][e]) < bl || !bl)) {
|
505
|
+
bl = t;
|
506
|
+
b = e;
|
507
|
+
}
|
508
|
+
if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
|
509
|
+
// special case, switch to ASCII for last bytes
|
510
|
+
bl = 1;
|
511
|
+
b = E_ASCII;
|
512
|
+
}
|
513
|
+
enc[p][E_C40].t = tl + bl;
|
514
|
+
enc[p][E_C40].s = sl;
|
515
|
+
if (bl && b == E_C40)
|
516
|
+
enc[p][b].s += enc[p + sl][b].s;
|
517
|
+
}
|
518
|
+
// Text
|
519
|
+
sub = tl = sl = 0;
|
520
|
+
do {
|
521
|
+
unsigned char c = s[p + sl++];
|
522
|
+
if (c & 0x80) {
|
523
|
+
// shift + upper
|
524
|
+
sub += 2;
|
525
|
+
c &= 0x7F;
|
526
|
+
}
|
527
|
+
if (c != ' ' && !isdigit (c) && !islower (c))
|
528
|
+
sub++; // shift
|
529
|
+
sub++;
|
530
|
+
while (sub >= 3) {
|
531
|
+
sub -= 3;
|
532
|
+
tl += 2;
|
533
|
+
}
|
534
|
+
} while (sub && p + sl < l);
|
535
|
+
if (exact && sub == 2 && p + sl == l) {
|
536
|
+
// special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
|
537
|
+
sub = 0;
|
538
|
+
tl += 2;
|
539
|
+
}
|
540
|
+
if (!sub && sl) {
|
541
|
+
// can encode Text
|
542
|
+
bl = 0;
|
543
|
+
if (p + sl < l)
|
544
|
+
for (e = 0; e < E_MAX; e++)
|
545
|
+
if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_TEXT][e]) < bl || !bl)) {
|
546
|
+
bl = t;
|
547
|
+
b = e;
|
548
|
+
}
|
549
|
+
if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
|
550
|
+
// special case, switch to ASCII for last bytes
|
551
|
+
bl = 1;
|
552
|
+
b = E_ASCII;
|
553
|
+
}
|
554
|
+
enc[p][E_TEXT].t = tl + bl;
|
555
|
+
enc[p][E_TEXT].s = sl;
|
556
|
+
if (bl && b == E_TEXT)
|
557
|
+
enc[p][b].s += enc[p + sl][b].s;
|
558
|
+
}
|
559
|
+
// X12
|
560
|
+
sub = tl = sl = 0;
|
561
|
+
do {
|
562
|
+
unsigned char c = s[p + sl++];
|
563
|
+
if (c != 13 && c != '*' && c != '>' && c != ' ' && !isdigit(c) && !isupper(c)) {
|
564
|
+
sl = 0;
|
565
|
+
break;
|
566
|
+
}
|
567
|
+
sub++;
|
568
|
+
while (sub >= 3) {
|
569
|
+
sub -= 3;
|
570
|
+
tl += 2;
|
571
|
+
}
|
572
|
+
} while (sub && p + sl < l);
|
573
|
+
if (!sub && sl) {
|
574
|
+
// can encode X12
|
575
|
+
bl = 0;
|
576
|
+
if (p + sl < l)
|
577
|
+
for (e = 0; e < E_MAX; e++)
|
578
|
+
if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_X12][e]) < bl || !bl)) {
|
579
|
+
bl = t;
|
580
|
+
b = e;
|
581
|
+
}
|
582
|
+
if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
|
583
|
+
// special case, switch to ASCII for last bytes
|
584
|
+
bl = 1;
|
585
|
+
b = E_ASCII;
|
586
|
+
}
|
587
|
+
enc[p][E_X12].t = tl + bl;
|
588
|
+
enc[p][E_X12].s = sl;
|
589
|
+
if (bl && b == E_X12)
|
590
|
+
enc[p][b].s += enc[p + sl][b].s;
|
591
|
+
}
|
592
|
+
// EDIFACT
|
593
|
+
sl = bl = 0;
|
594
|
+
if (s[p + 0] >= 32 && s[p + 0] <= 94) {
|
595
|
+
// can encode 1
|
596
|
+
char bs = 0;
|
597
|
+
if (p + 1 == l && (!bl || bl < 2)) {
|
598
|
+
bl = 2;
|
599
|
+
bs = 1;
|
600
|
+
} else
|
601
|
+
for (e = 0; e < E_MAX; e++)
|
602
|
+
if (e != E_EDIFACT && enc[p + 1][e].t && ((t = 2 + enc[p + 1][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
|
603
|
+
// E_ASCII as allowed for unlatch
|
604
|
+
bs = 1;
|
605
|
+
bl = t;
|
606
|
+
b = e;
|
607
|
+
}
|
608
|
+
if (p + 1 < l && s[p + 1] >= 32 && s[p + 1] <= 94) {
|
609
|
+
// can encode 2
|
610
|
+
if (p + 2 == l && (!bl || bl < 2)) {
|
611
|
+
bl = 3;
|
612
|
+
bs = 2;
|
613
|
+
} else
|
614
|
+
for (e = 0; e < E_MAX; e++)
|
615
|
+
if (e != E_EDIFACT && enc[p + 2][e].t && ((t = 3 + enc[p + 2][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
|
616
|
+
// E_ASCII as allowed for unlatch
|
617
|
+
bs = 2;
|
618
|
+
bl = t;
|
619
|
+
b = e;
|
620
|
+
}
|
621
|
+
if (p + 2 < l && s[p + 2] >= 32 && s[p + 2] <= 94) {
|
622
|
+
// can encode 3
|
623
|
+
if (p + 3 == l && (!bl || bl < 3)) {
|
624
|
+
bl = 3;
|
625
|
+
bs = 3;
|
626
|
+
} else
|
627
|
+
for (e = 0; e < E_MAX; e++)
|
628
|
+
if (e != E_EDIFACT && enc[p + 3][e].t && ((t = 3 + enc[p + 3][e].t + switchcost[E_ASCII][e]) < bl || !bl)) {
|
629
|
+
// E_ASCII as allowed for unlatch
|
630
|
+
bs = 3;
|
631
|
+
bl = t;
|
632
|
+
b = e;
|
633
|
+
}
|
634
|
+
if (p + 4 < l && s[p + 3] >= 32 && s[p + 3] <= 94) {
|
635
|
+
// can encode 4
|
636
|
+
if (p + 4 == l && (!bl || bl < 3)) {
|
637
|
+
bl = 3;
|
638
|
+
bs = 4;
|
639
|
+
} else {
|
640
|
+
for (e = 0; e < E_MAX; e++)
|
641
|
+
if (enc[p + 4][e].t && ((t = 3 + enc[p + 4][e].t + switchcost[E_EDIFACT][e]) < bl || !bl)) {
|
642
|
+
bs = 4;
|
643
|
+
bl = t;
|
644
|
+
b = e;
|
645
|
+
}
|
646
|
+
if (exact && enc[p + 4][E_ASCII].t && enc[p + 4][E_ASCII].t <= 2 && (t = 3 + enc[p + 4][E_ASCII].t) < bl) {
|
647
|
+
// special case, switch to ASCII for last 1 ot two bytes
|
648
|
+
bs = 4;
|
649
|
+
bl = t;
|
650
|
+
b = E_ASCII;
|
651
|
+
}
|
652
|
+
}
|
653
|
+
}
|
654
|
+
}
|
655
|
+
}
|
656
|
+
enc[p][E_EDIFACT].t = bl;
|
657
|
+
enc[p][E_EDIFACT].s = bs;
|
658
|
+
if (bl && b == E_EDIFACT)
|
659
|
+
enc[p][b].s += enc[p + bs][b].s;
|
660
|
+
}
|
661
|
+
// Binary
|
662
|
+
bl = 0;
|
663
|
+
for (e = 0; e < E_MAX; e++)
|
664
|
+
if (enc[p + 1][e].t && ((t = enc[p + 1][e].t + switchcost[E_BINARY][e] + ((e == E_BINARY && enc[p + 1][e].t == 249) ? 1 : 0)) < bl || !bl)) {
|
665
|
+
bl = t;
|
666
|
+
b = e;
|
667
|
+
}
|
668
|
+
enc[p][E_BINARY].t = 1 + bl;
|
669
|
+
enc[p][E_BINARY].s = 1;
|
670
|
+
if (bl && b == E_BINARY)
|
671
|
+
enc[p][b].s += enc[p + 1][b].s;
|
672
|
+
}
|
673
|
+
encoding = malloc(sizeof(char)*(l + 1));
|
674
|
+
p = 0;
|
675
|
+
{
|
676
|
+
unsigned char cur = E_ASCII; // starts ASCII
|
677
|
+
while (p < l) {
|
678
|
+
int t, m = 0;
|
679
|
+
unsigned char b = 0;
|
680
|
+
for (e = 0; e < E_MAX; e++)
|
681
|
+
if (enc[p][e].t && ((t = enc[p][e].t + switchcost[cur][e]) < m || t == m && e == cur || !m)) {
|
682
|
+
b = e;
|
683
|
+
m = t;
|
684
|
+
}
|
685
|
+
cur = b;
|
686
|
+
m = enc[p][b].s;
|
687
|
+
if (!p && lenp)
|
688
|
+
*lenp = enc[p][b].t;
|
689
|
+
while (p < l && m--)
|
690
|
+
encoding[p++] = encchr[b];
|
691
|
+
}
|
692
|
+
}
|
693
|
+
encoding[p] = 0;
|
694
|
+
return encoding;
|
695
|
+
}
|
696
|
+
|
697
|
+
void iec16022init(int *Wptr, int *Hptr, const char *barcode) {
|
698
|
+
if(Wptr == NULL || Hptr == NULL || barcode == NULL)
|
699
|
+
return;
|
700
|
+
|
701
|
+
int barcodelen = (int)strlen(barcode) + 1;
|
702
|
+
struct ecc200matrix_s *matrix;
|
703
|
+
for (matrix = ecc200matrix; matrix->bytes < barcodelen; matrix++);
|
704
|
+
*Wptr = matrix->W;
|
705
|
+
*Hptr = matrix->H;
|
706
|
+
}
|
707
|
+
|
708
|
+
// Main encoding function
|
709
|
+
// Returns the grid (malloced) containing the matrix. L corner at 0,0.
|
710
|
+
// Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
|
711
|
+
// Takes barcodelen and barcode to be encoded
|
712
|
+
// Note, if *encodingptr is null, then fills with auto picked (malloced) encoding
|
713
|
+
// If lenp not null, then the length of encoded data before any final unlatch or pad is stored
|
714
|
+
// If maxp not null, then the max storage of this size code is stored
|
715
|
+
// If eccp not null, then the number of ecc bytes used in this size is stored
|
716
|
+
// Returns 0 on error (writes to stderr with details).
|
717
|
+
unsigned char* iec16022ecc200(int *Wptr, int *Hptr, char **encodingptr, const int barcodelen, const unsigned char *barcode, int *lenp, int *maxp, int *eccp) {
|
718
|
+
// GS
|
719
|
+
// max semacode size is 3116 (from iec16022ecc200.h)
|
720
|
+
// we over compensate and check that the input is within this length
|
721
|
+
// to avoid any buffer overflow conditions.
|
722
|
+
unsigned char binary[4096]; // encoded raw data and ecc to place in barcode
|
723
|
+
int W = 0, H = 0;
|
724
|
+
char *encoding = 0;
|
725
|
+
unsigned char *grid = 0;
|
726
|
+
struct ecc200matrix_s *matrix;
|
727
|
+
|
728
|
+
// GS
|
729
|
+
// using the length from the 144x144 semacode in the matrix
|
730
|
+
// I don't trust the 3116 maximum length value ... and
|
731
|
+
// besides how many characters do you really need in a
|
732
|
+
// semacode?
|
733
|
+
if(barcodelen > 1556) {
|
734
|
+
//TODO: rb_raise(rb_eRangeError, "barcode is too long (> 1556 chars)");
|
735
|
+
return NULL;
|
736
|
+
}
|
737
|
+
|
738
|
+
memset(binary, 0, sizeof(binary));
|
739
|
+
if (encodingptr)
|
740
|
+
encoding = *encodingptr;
|
741
|
+
if (Wptr)
|
742
|
+
W = *Wptr;
|
743
|
+
if (Hptr)
|
744
|
+
H = *Hptr;
|
745
|
+
|
746
|
+
// encoding
|
747
|
+
if (W) {
|
748
|
+
// known size
|
749
|
+
for (matrix = ecc200matrix; matrix->W && (matrix->W != W || matrix->H != H); matrix++);
|
750
|
+
if (!matrix->W) {
|
751
|
+
//TODO: rb_raise(rb_eRangeError, "invalid size for barcode");
|
752
|
+
return 0;
|
753
|
+
}
|
754
|
+
if (!encoding) {
|
755
|
+
int len;
|
756
|
+
char *e = encmake(barcodelen, barcode, &len, 1);
|
757
|
+
if (e && len != matrix->bytes) {
|
758
|
+
// try not an exact fit
|
759
|
+
free (e);
|
760
|
+
e = encmake (barcodelen, barcode, &len, 0);
|
761
|
+
if (len > matrix->bytes) {
|
762
|
+
free(e);
|
763
|
+
//TODO: rb_raise(rb_eRangeError, "cannot make barcode fit");
|
764
|
+
return 0;
|
765
|
+
}
|
766
|
+
}
|
767
|
+
encoding = e;
|
768
|
+
}
|
769
|
+
} else {
|
770
|
+
// find size
|
771
|
+
if (encoding) {
|
772
|
+
// find one that fits chosen encoding
|
773
|
+
for (matrix = ecc200matrix; matrix->W; matrix++)
|
774
|
+
if (ecc200encode(binary, matrix->bytes, barcode, barcodelen, encoding, 0))
|
775
|
+
break;
|
776
|
+
} else {
|
777
|
+
int len;
|
778
|
+
char *e;
|
779
|
+
e = encmake(barcodelen, barcode, &len, 1);
|
780
|
+
for (matrix = ecc200matrix; matrix->W && matrix->bytes != len; matrix++);
|
781
|
+
if (e && !matrix->W) {
|
782
|
+
// try for non exact fit
|
783
|
+
free (e);
|
784
|
+
e = encmake(barcodelen, barcode, &len, 0);
|
785
|
+
for (matrix = ecc200matrix; matrix->W && matrix->bytes < len; matrix++);
|
786
|
+
}
|
787
|
+
encoding = e;
|
788
|
+
}
|
789
|
+
if (!matrix->W) {
|
790
|
+
free(encoding);
|
791
|
+
//TODO: rb_raise(rb_eRangeError, "overlong barcode");
|
792
|
+
return 0;
|
793
|
+
}
|
794
|
+
W = matrix->W;
|
795
|
+
H = matrix->H;
|
796
|
+
}
|
797
|
+
if (!ecc200encode(binary, matrix->bytes, barcode, barcodelen, encoding, lenp)) {
|
798
|
+
free(encoding);
|
799
|
+
//TODO: rb_raise(rb_eRangeError, "barcode too long for expected encoding");
|
800
|
+
return 0;
|
801
|
+
}
|
802
|
+
// ecc code
|
803
|
+
ecc200(binary, matrix->bytes, matrix->datablock, matrix->rsblock);
|
804
|
+
{
|
805
|
+
// placement
|
806
|
+
int x, y, NC, NR, *places;
|
807
|
+
NC = W - 2 * (W / matrix->FW);
|
808
|
+
NR = H - 2 * (H / matrix->FH);
|
809
|
+
places = malloc(sizeof(int) * NC * NR);
|
810
|
+
ecc200placement(places, NR, NC);
|
811
|
+
grid = malloc(sizeof(char) * W * H);
|
812
|
+
memset (grid, 0, W * H);
|
813
|
+
for (y = 0; y < H; y += matrix->FH) {
|
814
|
+
for (x = 0; x < W; x++)
|
815
|
+
grid[y * W + x] = 1;
|
816
|
+
for (x = 0; x < W; x += 2)
|
817
|
+
grid[(y + matrix->FH - 1) * W + x] = 1;
|
818
|
+
}
|
819
|
+
for (x = 0; x < W; x += matrix->FW) {
|
820
|
+
for (y = 0; y < H; y++)
|
821
|
+
grid[y * W + x] = 1;
|
822
|
+
for (y = 0; y < H; y += 2)
|
823
|
+
grid[y * W + x + matrix->FW - 1] = 1;
|
824
|
+
}
|
825
|
+
for (y = 0; y < NR; y++) {
|
826
|
+
for (x = 0; x < NC; x++) {
|
827
|
+
int v = places[(NR - y - 1) * NC + x];
|
828
|
+
if (v == 1 || v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))
|
829
|
+
grid[(1 + y + 2 * (y / (matrix->FH - 2))) * W + 1 + x + 2 * (x / (matrix->FW - 2))] = 1;
|
830
|
+
}
|
831
|
+
}
|
832
|
+
free (places);
|
833
|
+
}
|
834
|
+
if (Wptr)
|
835
|
+
*Wptr = W;
|
836
|
+
if (Hptr)
|
837
|
+
*Hptr = H;
|
838
|
+
if (encodingptr)
|
839
|
+
*encodingptr = encoding;
|
840
|
+
else
|
841
|
+
free(encoding); // get rid of this if we aren't returning it
|
842
|
+
if (maxp)
|
843
|
+
*maxp = matrix->bytes;
|
844
|
+
if (eccp)
|
845
|
+
*eccp = (matrix->bytes + 2) / matrix->datablock * matrix->rsblock;
|
846
|
+
return grid;
|
847
|
+
}
|