OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
181 ilm 1
/*
2
 * Copyright 2014-2018 Robin Stuart, Daniel Gredler
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
 * in compliance with the License. You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software distributed under the License
10
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
 * or implied. See the License for the specific language governing permissions and limitations under
12
 * the License.
13
 */
14
package uk.org.okapibarcode.backend;
15
 
16
import java.math.BigInteger;
17
 
18
/**
19
 * <p>
20
 * Implements GS1 DataBar Limited according to ISO/IEC 24724:2011.
21
 *
22
 * <p>
23
 * Input data should be a 12-digit or 13-digit Global Trade Identification Number (GTIN) without
24
 * check digit or Application Identifier [01].
25
 *
26
 * @author <a href="mailto:rstuart114@gmail.com">Robin Stuart</a>
27
 */
28
public class DataBarLimited extends Symbol {
29
 
30
    private static final int[] T_EVEN_LTD = { 28, 728, 6454, 203, 2408, 1, 16632 };
31
 
32
    private static final int[] MODULES_ODD_LTD = { 17, 13, 9, 15, 11, 19, 7 };
33
 
34
    private static final int[] MODULES_EVEN_LTD = { 9, 13, 17, 11, 15, 7, 19 };
35
 
36
    private static final int[] WIDEST_ODD_LTD = { 6, 5, 3, 5, 4, 8, 1 };
37
 
38
    private static final int[] WIDEST_EVEN_LTD = { 3, 4, 6, 4, 5, 1, 8 };
39
 
40
    private static final int[] CHECKSUM_WEIGHT_LTD = { /* Table 7 */
41
            1, 3, 9, 27, 81, 65, 17, 51, 64, 14, 42, 37, 22, 66, 20, 60, 2, 6, 18, 54, 73, 41, 34, 13, 39, 28, 84, 74 };
42
 
43
    private static final int[] FINDER_PATTERN_LTD = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
44
            2, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 1, 1, 1,
45
            1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
46
            2, 1, 1, 3, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1,
47
            1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
48
            1, 2, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1,
49
            1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1,
50
            1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 1, 1,
51
            1, 1, 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1,
52
            1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 1, 1,
53
            1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2,
54
            1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1,
55
            1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2,
56
            1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 2, 1, 1, 1,
57
            1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1,
58
            1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1,
59
            1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1,
60
            2, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 3, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1,
61
            2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1,
62
            3, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1,
63
            1 /* ISO/IEC 24724-2011 57 */
64
    };
65
 
66
    private boolean linkageFlag;
67
 
68
    /**
69
     * Although this is a GS1 symbology, input data is expected to omit the [01] Application
70
     * Identifier, as well as the check digit. Thus, the input data is not considered GS1-format
71
     * data.
72
     */
73
    @Override
74
    protected boolean gs1Supported() {
75
        return false;
76
    }
77
 
78
    protected void setLinkageFlag() {
79
        this.linkageFlag = true;
80
    }
81
 
82
    protected void unsetLinkageFlag() {
83
        this.linkageFlag = false;
84
    }
85
 
86
    @Override
87
    protected void encode() {
88
        BigInteger accum;
89
        BigInteger left_reg;
90
        BigInteger right_reg;
91
        int left_group;
92
        int right_group;
93
        int i, j;
94
        int left_character;
95
        int right_character;
96
        int left_odd;
97
        int right_odd;
98
        int left_even;
99
        int right_even;
100
        final int[] left_widths = new int[14];
101
        final int[] right_widths = new int[14];
102
        int checksum;
103
        final int[] check_elements = new int[14];
104
        final int[] total_widths = new int[46];
105
        boolean bar_latch;
106
        int check_digit = 0;
107
        int count = 0;
108
        String hrt;
109
        int compositeOffset = 0;
110
 
111
        if (this.content.length() > 13) {
112
            throw new OkapiException("Input too long");
113
        }
114
 
115
        if (!this.content.matches("[0-9]+?")) {
116
            throw new OkapiException("Invalid characters in input");
117
        }
118
 
119
        if (this.content.length() == 13 && this.content.charAt(0) != '0' && this.content.charAt(0) != '1') {
120
            throw new OkapiException("Input out of range");
121
        }
122
 
123
        accum = new BigInteger(this.content);
124
 
125
        if (this.linkageFlag) {
126
            /* Add symbol linkage flag */
127
            accum = accum.add(new BigInteger("2015133531096"));
128
        }
129
 
130
        /* Calculate left and right pair values */
131
        left_reg = accum.divide(new BigInteger("2013571"));
132
        right_reg = accum.mod(new BigInteger("2013571"));
133
 
134
        left_group = 0;
135
        if (left_reg.compareTo(new BigInteger("183063")) == 1) {
136
            left_group = 1;
137
        }
138
        if (left_reg.compareTo(new BigInteger("820063")) == 1) {
139
            left_group = 2;
140
        }
141
        if (left_reg.compareTo(new BigInteger("1000775")) == 1) {
142
            left_group = 3;
143
        }
144
        if (left_reg.compareTo(new BigInteger("1491020")) == 1) {
145
            left_group = 4;
146
        }
147
        if (left_reg.compareTo(new BigInteger("1979844")) == 1) {
148
            left_group = 5;
149
        }
150
        if (left_reg.compareTo(new BigInteger("1996938")) == 1) {
151
            left_group = 6;
152
        }
153
 
154
        right_group = 0;
155
        if (right_reg.compareTo(new BigInteger("183063")) == 1) {
156
            right_group = 1;
157
        }
158
        if (right_reg.compareTo(new BigInteger("820063")) == 1) {
159
            right_group = 2;
160
        }
161
        if (right_reg.compareTo(new BigInteger("1000775")) == 1) {
162
            right_group = 3;
163
        }
164
        if (right_reg.compareTo(new BigInteger("1491020")) == 1) {
165
            right_group = 4;
166
        }
167
        if (right_reg.compareTo(new BigInteger("1979844")) == 1) {
168
            right_group = 5;
169
        }
170
        if (right_reg.compareTo(new BigInteger("1996938")) == 1) {
171
            right_group = 6;
172
        }
173
 
174
        infoLine("Data Characters: " + (left_group + 1) + " " + (right_group + 1));
175
 
176
        switch (left_group) {
177
        case 1:
178
            left_reg = left_reg.subtract(new BigInteger("183064"));
179
            break;
180
        case 2:
181
            left_reg = left_reg.subtract(new BigInteger("820064"));
182
            break;
183
        case 3:
184
            left_reg = left_reg.subtract(new BigInteger("1000776"));
185
            break;
186
        case 4:
187
            left_reg = left_reg.subtract(new BigInteger("1491021"));
188
            break;
189
        case 5:
190
            left_reg = left_reg.subtract(new BigInteger("1979845"));
191
            break;
192
        case 6:
193
            left_reg = left_reg.subtract(new BigInteger("1996939"));
194
            break;
195
        }
196
 
197
        switch (right_group) {
198
        case 1:
199
            right_reg = right_reg.subtract(new BigInteger("183064"));
200
            break;
201
        case 2:
202
            right_reg = right_reg.subtract(new BigInteger("820064"));
203
            break;
204
        case 3:
205
            right_reg = right_reg.subtract(new BigInteger("1000776"));
206
            break;
207
        case 4:
208
            right_reg = right_reg.subtract(new BigInteger("1491021"));
209
            break;
210
        case 5:
211
            right_reg = right_reg.subtract(new BigInteger("1979845"));
212
            break;
213
        case 6:
214
            right_reg = right_reg.subtract(new BigInteger("1996939"));
215
            break;
216
        }
217
 
218
        left_character = left_reg.intValue();
219
        right_character = right_reg.intValue();
220
 
221
        left_odd = left_character / T_EVEN_LTD[left_group];
222
        left_even = left_character % T_EVEN_LTD[left_group];
223
        right_odd = right_character / T_EVEN_LTD[right_group];
224
        right_even = right_character % T_EVEN_LTD[right_group];
225
 
226
        int[] widths = getWidths(left_odd, MODULES_ODD_LTD[left_group], 7, WIDEST_ODD_LTD[left_group], 1);
227
        left_widths[0] = widths[0];
228
        left_widths[2] = widths[1];
229
        left_widths[4] = widths[2];
230
        left_widths[6] = widths[3];
231
        left_widths[8] = widths[4];
232
        left_widths[10] = widths[5];
233
        left_widths[12] = widths[6];
234
 
235
        widths = getWidths(left_even, MODULES_EVEN_LTD[left_group], 7, WIDEST_EVEN_LTD[left_group], 0);
236
        left_widths[1] = widths[0];
237
        left_widths[3] = widths[1];
238
        left_widths[5] = widths[2];
239
        left_widths[7] = widths[3];
240
        left_widths[9] = widths[4];
241
        left_widths[11] = widths[5];
242
        left_widths[13] = widths[6];
243
 
244
        widths = getWidths(right_odd, MODULES_ODD_LTD[right_group], 7, WIDEST_ODD_LTD[right_group], 1);
245
        right_widths[0] = widths[0];
246
        right_widths[2] = widths[1];
247
        right_widths[4] = widths[2];
248
        right_widths[6] = widths[3];
249
        right_widths[8] = widths[4];
250
        right_widths[10] = widths[5];
251
        right_widths[12] = widths[6];
252
 
253
        widths = getWidths(right_even, MODULES_EVEN_LTD[right_group], 7, WIDEST_EVEN_LTD[right_group], 0);
254
        right_widths[1] = widths[0];
255
        right_widths[3] = widths[1];
256
        right_widths[5] = widths[2];
257
        right_widths[7] = widths[3];
258
        right_widths[9] = widths[4];
259
        right_widths[11] = widths[5];
260
        right_widths[13] = widths[6];
261
 
262
        checksum = 0;
263
        /* Calculate the checksum */
264
        for (i = 0; i < 14; i++) {
265
            checksum += CHECKSUM_WEIGHT_LTD[i] * left_widths[i];
266
            checksum += CHECKSUM_WEIGHT_LTD[i + 14] * right_widths[i];
267
        }
268
        checksum %= 89;
269
 
270
        infoLine("Checksum: " + checksum);
271
 
272
        for (i = 0; i < 14; i++) {
273
            check_elements[i] = FINDER_PATTERN_LTD[i + checksum * 14];
274
        }
275
 
276
        total_widths[0] = 1;
277
        total_widths[1] = 1;
278
        total_widths[44] = 1;
279
        total_widths[45] = 1;
280
        for (i = 0; i < 14; i++) {
281
            total_widths[i + 2] = left_widths[i];
282
            total_widths[i + 16] = check_elements[i];
283
            total_widths[i + 30] = right_widths[i];
284
        }
285
 
286
        final StringBuilder bin = new StringBuilder();
287
        final StringBuilder notbin = new StringBuilder();
288
 
289
        bar_latch = false;
290
        for (i = 0; i < 46; i++) {
291
            for (j = 0; j < total_widths[i]; j++) {
292
                if (bar_latch) {
293
                    bin.append('1');
294
                    notbin.append('0');
295
                } else {
296
                    bin.append('0');
297
                    notbin.append('1');
298
                }
299
            }
300
            if (bar_latch) {
301
                bar_latch = false;
302
            } else {
303
                bar_latch = true;
304
            }
305
        }
306
 
307
        /* Calculate check digit from Annex A and place human readable text */
308
 
309
        this.readable = "(01)";
310
        hrt = "";
311
        for (i = this.content.length(); i < 13; i++) {
312
            hrt += "0";
313
        }
314
        hrt += this.content;
315
 
316
        for (i = 0; i < 13; i++) {
317
            count += hrt.charAt(i) - '0';
318
            if ((i & 1) == 0) {
319
                count += 2 * (hrt.charAt(i) - '0');
320
            }
321
        }
322
 
323
        check_digit = 10 - count % 10;
324
        if (check_digit == 10) {
325
            check_digit = 0;
326
        }
327
 
328
        hrt += (char) (check_digit + '0');
329
        this.readable += hrt;
330
 
331
        if (this.linkageFlag) {
332
            compositeOffset = 1;
333
        }
334
 
335
        this.row_count = 1 + compositeOffset;
336
        this.row_height = new int[1 + compositeOffset];
337
        this.row_height[0 + compositeOffset] = -1;
338
        this.pattern = new String[1 + compositeOffset];
339
        this.pattern[0 + compositeOffset] = bin2pat(bin);
340
 
341
        if (this.linkageFlag) {
342
            // Add composite symbol separator
343
            notbin.delete(70, notbin.length());
344
            notbin.delete(0, 4);
345
            this.row_height[0] = 1;
346
            this.pattern[0] = "04" + bin2pat(notbin);
347
        }
348
    }
349
 
350
    private static int getCombinations(final int n, final int r) {
351
 
352
        int i, j;
353
        int maxDenom, minDenom;
354
        int val;
355
 
356
        if (n - r > r) {
357
            minDenom = r;
358
            maxDenom = n - r;
359
        } else {
360
            minDenom = n - r;
361
            maxDenom = r;
362
        }
363
 
364
        val = 1;
365
        j = 1;
366
 
367
        for (i = n; i > maxDenom; i--) {
368
            val *= i;
369
            if (j <= minDenom) {
370
                val /= j;
371
                j++;
372
            }
373
        }
374
 
375
        for (; j <= minDenom; j++) {
376
            val /= j;
377
        }
378
 
379
        return val;
380
    }
381
 
382
    static int[] getWidths(int val, int n, final int elements, final int maxWidth, final int noNarrow) {
383
 
384
        int bar;
385
        int elmWidth;
386
        int mxwElement;
387
        int subVal, lessVal;
388
        int narrowMask = 0;
389
        final int[] widths = new int[elements];
390
 
391
        for (bar = 0; bar < elements - 1; bar++) {
392
            for (elmWidth = 1, narrowMask |= 1 << bar;; elmWidth++, narrowMask &= ~(1 << bar)) {
393
                /* get all combinations */
394
                subVal = getCombinations(n - elmWidth - 1, elements - bar - 2);
395
                /* less combinations with no single-module element */
396
                if (noNarrow == 0 && narrowMask == 0 && n - elmWidth - (elements - bar - 1) >= elements - bar - 1) {
397
                    subVal -= getCombinations(n - elmWidth - (elements - bar), elements - bar - 2);
398
                }
399
                /* less combinations with elements > maxVal */
400
                if (elements - bar - 1 > 1) {
401
                    lessVal = 0;
402
                    for (mxwElement = n - elmWidth - (elements - bar - 2); mxwElement > maxWidth; mxwElement--) {
403
                        lessVal += getCombinations(n - elmWidth - mxwElement - 1, elements - bar - 3);
404
                    }
405
                    subVal -= lessVal * (elements - 1 - bar);
406
                } else if (n - elmWidth > maxWidth) {
407
                    subVal--;
408
                }
409
                val -= subVal;
410
                if (val < 0) {
411
                    break;
412
                }
413
            }
414
            val += subVal;
415
            n -= elmWidth;
416
            widths[bar] = elmWidth;
417
        }
418
 
419
        widths[bar] = n;
420
 
421
        return widths;
422
    }
423
}