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