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 Robin Stuart
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 static uk.org.okapibarcode.util.Arrays.positionOf;
17
 
18
import java.awt.geom.Rectangle2D;
19
import java.math.BigInteger;
20
import java.util.ArrayList;
21
import java.util.List;
22
 
23
import uk.org.okapibarcode.backend.DataBar14.Mode;
24
 
25
/**
26
 * <p>
27
 * Implements GS1 Composite symbology according to ISO/IEC 24723:2010.
28
 *
29
 * <p>
30
 * Composite symbols comprise a 2D element which encodes GS1 data and a "linear" element which can
31
 * be UPC, EAN, Code 128 or GS1 DataBar symbol.
32
 *
33
 * @author <a href="mailto:rstuart114@gmail.com">Robin Stuart</a>
34
 */
35
public class Composite extends Symbol {
36
 
37
    /** The linear component choices available. */
38
    public static enum LinearEncoding {
39
        UPCA, UPCE, EAN, CODE_128, DATABAR_14, DATABAR_14_STACK, DATABAR_14_STACK_OMNI, DATABAR_LIMITED, DATABAR_EXPANDED, DATABAR_EXPANDED_STACK
40
    }
41
 
42
    /** The 2D component choices available. */
43
    public static enum CompositeMode {
44
        /**
45
         * Indicates that the composite symbol uses a MicroPDF417 variant as the 2D component. Of
46
         * the 2D component choices, this one holds the least amount of data.
47
         */
48
        CC_A,
49
        /**
50
         * Indicates that the composite symbol uses a MicroPDF417 symbol as the 2D component,
51
         * starting with a codeword of 920.
52
         */
53
        CC_B,
54
        /**
55
         * Indicates that the composite symbol uses a PDF417 symbol as the 2D component, starting
56
         * with a codeword of 920. Of the 2D component choices, this one holds the most amount of
57
         * data. May only be used if the linear component is {@link LinearEncoding#CODE_128 Code
58
         * 128}.
59
         */
60
        CC_C
61
    }
62
 
63
    private static enum GeneralFieldMode {
64
        NUMERIC, ALPHA, ISOIEC, INVALID_CHAR, ANY_ENC, ALPHA_OR_ISO
65
    }
66
 
67
    /* CC-A component coefficients from ISO/IEC 24728:2006 Annex F */
68
    private static final int[] CCA_COEFFS = {
69
            /* k = 4 */
70
            522, 568, 723, 809,
71
            /* k = 5 */
72
            427, 919, 460, 155, 566,
73
            /* k = 6 */
74
            861, 285, 19, 803, 17, 766,
75
            /* k = 7 */
76
            76, 925, 537, 597, 784, 691, 437,
77
            /* k = 8 */
78
            237, 308, 436, 284, 646, 653, 428, 379 };
79
 
80
    private static final int[] COEFRS = {
81
            /* k = 2 */
82
            27, 917,
83
            /* k = 4 */
84
            522, 568, 723, 809,
85
            /* k = 8 */
86
            237, 308, 436, 284, 646, 653, 428, 379,
87
            /* k = 16 */
88
            274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65,
89
            /* k = 32 */
90
            361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410,
91
            /* k = 64 */
92
            539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, 877, 381, 612, 723, 476, 462, 172, 430, 609, 858, 822, 543, 376, 511, 400, 672, 762, 283, 184, 440, 35, 519, 31, 460, 594,
93
            225, 535, 517, 352, 605, 158, 651, 201, 488, 502, 648, 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, 623, 264, 543,
94
            /* k = 128 */
95
            521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, 925, 749, 415, 822, 93, 217, 208, 928, 244, 583, 620, 246, 148, 447, 631, 292, 908, 490, 704, 516, 258, 457, 907, 594, 723,
96
            674, 292, 272, 96, 684, 432, 686, 606, 860, 569, 193, 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, 463, 646, 776, 171, 491, 297, 763, 156, 732, 95, 270, 447, 90, 507, 48,
97
            228, 821, 808, 898, 784, 663, 627, 378, 382, 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, 157, 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, 587, 804, 34, 211, 330,
98
            539, 297, 827, 865, 37, 517, 834, 315, 550, 86, 801, 4, 108, 539,
99
            /* k = 256 */
100
            524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, 786, 138, 720, 858, 194, 311, 913, 275, 190, 375, 850, 438, 733, 194, 280, 201, 280, 828, 757, 710, 814, 919, 89, 68, 569, 11,
101
            204, 796, 605, 540, 913, 801, 700, 799, 137, 439, 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, 549, 209, 884, 315, 70, 329, 793, 490, 274, 877, 162, 749, 812, 684, 461, 334,
102
            376, 849, 521, 307, 291, 803, 712, 19, 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, 637, 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, 538, 906, 90, 2, 290, 743, 199,
103
            655, 903, 329, 49, 802, 580, 355, 588, 188, 462, 10, 134, 628, 320, 479, 130, 739, 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, 722, 384, 177, 752, 607, 640, 455, 193, 689, 707,
104
            805, 641, 48, 60, 732, 621, 895, 544, 261, 852, 655, 309, 697, 755, 756, 60, 231, 773, 434, 421, 726, 528, 503, 118, 49, 795, 32, 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, 73,
105
            914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, 791, 893, 754, 605, 383, 228, 749, 760, 213, 54, 297, 134, 54, 834, 299, 922, 191, 910, 532, 609, 829, 189, 20, 167, 29, 872, 449,
106
            83, 402, 41, 656, 505, 579, 481, 173, 404, 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, 55, 497, 10,
107
            /* k = 512 */
108
            352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, 380, 350, 492, 197, 265, 920, 155, 914, 299, 229, 643, 294, 871, 306, 88, 87, 193, 352, 781, 846, 75, 327, 520, 435, 543,
109
            203, 666, 249, 346, 781, 621, 640, 268, 794, 534, 539, 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, 916, 552, 41, 542, 289, 122, 272, 383, 800, 485, 98, 752, 472, 761, 107,
110
            784, 860, 658, 741, 290, 204, 681, 407, 855, 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, 808, 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, 192, 516, 258, 240, 518,
111
            794, 395, 768, 848, 51, 610, 384, 168, 190, 826, 328, 596, 786, 303, 570, 381, 415, 641, 156, 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, 40, 708, 575, 162, 864, 229, 65, 861,
112
            841, 512, 164, 477, 221, 92, 358, 785, 288, 357, 850, 836, 827, 736, 707, 94, 8, 494, 114, 521, 2, 499, 851, 543, 152, 729, 771, 95, 248, 361, 578, 323, 856, 797, 289, 51, 684, 466, 533,
113
            820, 669, 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, 591, 452, 578, 37, 124, 298, 332, 552, 43, 427, 119, 662, 777, 475, 850, 764, 364, 578, 911, 283, 711, 472, 420, 245,
114
            288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, 842, 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, 159, 672, 729, 624, 59, 193, 417, 158, 209, 563, 564, 343, 693, 109,
115
            608, 563, 365, 181, 772, 677, 310, 248, 353, 708, 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, 618, 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, 247, 184, 45, 787,
116
            680, 18, 66, 407, 369, 54, 492, 228, 613, 830, 922, 437, 519, 644, 905, 789, 420, 305, 441, 207, 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, 242, 797, 838, 837, 720, 224, 307,
117
            631, 61, 87, 560, 310, 756, 665, 397, 808, 851, 309, 473, 795, 378, 31, 647, 915, 459, 806, 590, 731, 425, 216, 548, 249, 321, 881, 699, 535, 673, 782, 210, 815, 905, 303, 843, 922, 281,
118
            73, 469, 791, 660, 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, 336, 286, 437, 375, 273, 610, 296, 183, 923, 116, 667, 751, 353, 62, 366, 691, 379, 687, 842, 37, 357, 720,
119
            742, 330, 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, 342, 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, 610, 46, 656, 447, 171, 616, 464, 190, 531, 297, 321, 762,
120
            752, 533, 175, 134, 14, 381, 433, 717, 45, 111, 20, 596, 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, 407, 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, 223, 849,
121
            647, 63, 310, 863, 251, 366, 304, 282, 738, 675, 410, 389, 244, 31, 121, 303, 263 };
122
 
123
    /* rows, error codewords, k-offset of valid CC-A sizes from ISO/IEC 24723:2006 Table 9 */
124
    private static final int[] CCA_VARIANTS = { 5, 6, 7, 8, 9, 10, 12, 4, 5, 6, 7, 8, 3, 4, 5, 6, 7, 4, 4, 5, 5, 6, 6, 7, 4, 5, 6, 7, 7, 4, 5, 6, 7, 8, 0, 0, 4, 4, 9, 9, 15, 0, 4, 9, 15, 15, 0, 4, 9,
125
            15, 22 };
126
 
127
    /*
128
     * following is Left RAP, Centre RAP, Right RAP and Start Cluster from ISO/IEC 24723:2006 tables
129
     * 10 and 11
130
     */
131
    private static final int[] A_RAP_TABLE = { 39, 1, 32, 8, 14, 43, 20, 11, 1, 5, 15, 21, 40, 43, 46, 34, 29, 0, 0, 0, 0, 0, 0, 0, 43, 33, 37, 47, 1, 20, 23, 26, 14, 9, 19, 33, 12, 40, 46, 23, 52,
132
            23, 13, 17, 27, 33, 52, 3, 6, 46, 41, 6, 0, 3, 3, 3, 0, 3, 3, 0, 3, 6, 6, 0, 0, 0, 0, 3 };
133
 
134
    private static final String[] CODAGEMC = { "urA", "xfs", "ypy", "unk", "xdw", "yoz", "pDA", "uls", "pBk", "eBA", "pAs", "eAk", "prA", "uvs", "xhy", "pnk", "utw", "xgz", "fDA", "pls", "fBk", "frA",
135
            "pvs", "uxy", "fnk", "ptw", "uwz", "fls", "psy", "fvs", "pxy", "ftw", "pwz", "fxy", "yrx", "ufk", "xFw", "ymz", "onA", "uds", "xEy", "olk", "ucw", "dBA", "oks", "uci", "dAk", "okg", "dAc",
136
            "ovk", "uhw", "xaz", "dnA", "ots", "ugy", "dlk", "osw", "ugj", "dks", "osi", "dvk", "oxw", "uiz", "dts", "owy", "dsw", "owj", "dxw", "oyz", "dwy", "dwj", "ofA", "uFs", "xCy", "odk", "uEw",
137
            "xCj", "clA", "ocs", "uEi", "ckk", "ocg", "ckc", "ckE", "cvA", "ohs", "uay", "ctk", "ogw", "uaj", "css", "ogi", "csg", "csa", "cxs", "oiy", "cww", "oij", "cwi", "cyy", "oFk", "uCw", "xBj",
138
            "cdA", "oEs", "uCi", "cck", "oEg", "uCb", "ccc", "oEa", "ccE", "oED", "chk", "oaw", "uDj", "cgs", "oai", "cgg", "oab", "cga", "cgD", "obj", "cib", "cFA", "oCs", "uBi", "cEk", "oCg", "uBb",
139
            "cEc", "oCa", "cEE", "oCD", "cEC", "cas", "cag", "caa", "cCk", "uAr", "oBa", "oBD", "cCB", "tfk", "wpw", "yez", "mnA", "tds", "woy", "mlk", "tcw", "woj", "FBA", "mks", "FAk", "mvk", "thw",
140
            "wqz", "FnA", "mts", "tgy", "Flk", "msw", "Fks", "Fkg", "Fvk", "mxw", "tiz", "Fts", "mwy", "Fsw", "Fsi", "Fxw", "myz", "Fwy", "Fyz", "vfA", "xps", "yuy", "vdk", "xow", "yuj", "qlA", "vcs",
141
            "xoi", "qkk", "vcg", "xob", "qkc", "vca", "mfA", "tFs", "wmy", "qvA", "mdk", "tEw", "wmj", "qtk", "vgw", "xqj", "hlA", "Ekk", "mcg", "tEb", "hkk", "qsg", "hkc", "EvA", "mhs", "tay", "hvA",
142
            "Etk", "mgw", "taj", "htk", "qww", "vij", "hss", "Esg", "hsg", "Exs", "miy", "hxs", "Eww", "mij", "hww", "qyj", "hwi", "Eyy", "hyy", "Eyj", "hyj", "vFk", "xmw", "ytj", "qdA", "vEs", "xmi",
143
            "qck", "vEg", "xmb", "qcc", "vEa", "qcE", "qcC", "mFk", "tCw", "wlj", "qhk", "mEs", "tCi", "gtA", "Eck", "vai", "tCb", "gsk", "Ecc", "mEa", "gsc", "qga", "mED", "EcC", "Ehk", "maw", "tDj",
144
            "gxk", "Egs", "mai", "gws", "qii", "mab", "gwg", "Ega", "EgD", "Eiw", "mbj", "gyw", "Eii", "gyi", "Eib", "gyb", "gzj", "qFA", "vCs", "xli", "qEk", "vCg", "xlb", "qEc", "vCa", "qEE", "vCD",
145
            "qEC", "qEB", "EFA", "mCs", "tBi", "ghA", "EEk", "mCg", "tBb", "ggk", "qag", "vDb", "ggc", "EEE", "mCD", "ggE", "qaD", "ggC", "Eas", "mDi", "gis", "Eag", "mDb", "gig", "qbb", "gia", "EaD",
146
            "giD", "gji", "gjb", "qCk", "vBg", "xkr", "qCc", "vBa", "qCE", "vBD", "qCC", "qCB", "ECk", "mBg", "tAr", "gak", "ECc", "mBa", "gac", "qDa", "mBD", "gaE", "ECC", "gaC", "ECB", "EDg", "gbg",
147
            "gba", "gbD", "vAq", "vAn", "qBB", "mAq", "EBE", "gDE", "gDC", "gDB", "lfA", "sps", "wey", "ldk", "sow", "ClA", "lcs", "soi", "Ckk", "lcg", "Ckc", "CkE", "CvA", "lhs", "sqy", "Ctk", "lgw",
148
            "sqj", "Css", "lgi", "Csg", "Csa", "Cxs", "liy", "Cww", "lij", "Cwi", "Cyy", "Cyj", "tpk", "wuw", "yhj", "ndA", "tos", "wui", "nck", "tog", "wub", "ncc", "toa", "ncE", "toD", "lFk", "smw",
149
            "wdj", "nhk", "lEs", "smi", "atA", "Cck", "tqi", "smb", "ask", "ngg", "lEa", "asc", "CcE", "asE", "Chk", "law", "snj", "axk", "Cgs", "trj", "aws", "nii", "lab", "awg", "Cga", "awa", "Ciw",
150
            "lbj", "ayw", "Cii", "ayi", "Cib", "Cjj", "azj", "vpA", "xus", "yxi", "vok", "xug", "yxb", "voc", "xua", "voE", "xuD", "voC", "nFA", "tms", "wti", "rhA", "nEk", "xvi", "wtb", "rgk", "vqg",
151
            "xvb", "rgc", "nEE", "tmD", "rgE", "vqD", "nEB", "CFA", "lCs", "sli", "ahA", "CEk", "lCg", "slb", "ixA", "agk", "nag", "tnb", "iwk", "rig", "vrb", "lCD", "iwc", "agE", "naD", "iwE", "CEB",
152
            "Cas", "lDi", "ais", "Cag", "lDb", "iys", "aig", "nbb", "iyg", "rjb", "CaD", "aiD", "Cbi", "aji", "Cbb", "izi", "ajb", "vmk", "xtg", "ywr", "vmc", "xta", "vmE", "xtD", "vmC", "vmB", "nCk",
153
            "tlg", "wsr", "rak", "nCc", "xtr", "rac", "vna", "tlD", "raE", "nCC", "raC", "nCB", "raB", "CCk", "lBg", "skr", "aak", "CCc", "lBa", "iik", "aac", "nDa", "lBD", "iic", "rba", "CCC", "iiE",
154
            "aaC", "CCB", "aaB", "CDg", "lBr", "abg", "CDa", "ijg", "aba", "CDD", "ija", "abD", "CDr", "ijr", "vlc", "xsq", "vlE", "xsn", "vlC", "vlB", "nBc", "tkq", "rDc", "nBE", "tkn", "rDE", "vln",
155
            "rDC", "nBB", "rDB", "CBc", "lAq", "aDc", "CBE", "lAn", "ibc", "aDE", "nBn", "ibE", "rDn", "CBB", "ibC", "aDB", "ibB", "aDq", "ibq", "ibn", "xsf", "vkl", "tkf", "nAm", "nAl", "CAo", "aBo",
156
            "iDo", "CAl", "aBl", "kpk", "BdA", "kos", "Bck", "kog", "seb", "Bcc", "koa", "BcE", "koD", "Bhk", "kqw", "sfj", "Bgs", "kqi", "Bgg", "kqb", "Bga", "BgD", "Biw", "krj", "Bii", "Bib", "Bjj",
157
            "lpA", "sus", "whi", "lok", "sug", "loc", "sua", "loE", "suD", "loC", "BFA", "kms", "sdi", "DhA", "BEk", "svi", "sdb", "Dgk", "lqg", "svb", "Dgc", "BEE", "kmD", "DgE", "lqD", "BEB", "Bas",
158
            "kni", "Dis", "Bag", "knb", "Dig", "lrb", "Dia", "BaD", "Bbi", "Dji", "Bbb", "Djb", "tuk", "wxg", "yir", "tuc", "wxa", "tuE", "wxD", "tuC", "tuB", "lmk", "stg", "nqk", "lmc", "sta", "nqc",
159
            "tva", "stD", "nqE", "lmC", "nqC", "lmB", "nqB", "BCk", "klg", "Dak", "BCc", "str", "bik", "Dac", "lna", "klD", "bic", "nra", "BCC", "biE", "DaC", "BCB", "DaB", "BDg", "klr", "Dbg", "BDa",
160
            "bjg", "Dba", "BDD", "bja", "DbD", "BDr", "Dbr", "bjr", "xxc", "yyq", "xxE", "yyn", "xxC", "xxB", "ttc", "wwq", "vvc", "xxq", "wwn", "vvE", "xxn", "vvC", "ttB", "vvB", "llc", "ssq", "nnc",
161
            "llE", "ssn", "rrc", "nnE", "ttn", "rrE", "vvn", "llB", "rrC", "nnB", "rrB", "BBc", "kkq", "DDc", "BBE", "kkn", "bbc", "DDE", "lln", "jjc", "bbE", "nnn", "BBB", "jjE", "rrn", "DDB", "jjC",
162
            "BBq", "DDq", "BBn", "bbq", "DDn", "jjq", "bbn", "jjn", "xwo", "yyf", "xwm", "xwl", "tso", "wwf", "vto", "xwv", "vtm", "tsl", "vtl", "lko", "ssf", "nlo", "lkm", "rno", "nlm", "lkl", "rnm",
163
            "nll", "rnl", "BAo", "kkf", "DBo", "lkv", "bDo", "DBm", "BAl", "jbo", "bDm", "DBl", "jbm", "bDl", "jbl", "DBv", "jbv", "xwd", "vsu", "vst", "nku", "rlu", "rlt", "DAu", "bBu", "jDu", "jDt",
164
            "ApA", "Aok", "keg", "Aoc", "AoE", "AoC", "Aqs", "Aqg", "Aqa", "AqD", "Ari", "Arb", "kuk", "kuc", "sha", "kuE", "shD", "kuC", "kuB", "Amk", "kdg", "Bqk", "kvg", "kda", "Bqc", "kva", "BqE",
165
            "kvD", "BqC", "AmB", "BqB", "Ang", "kdr", "Brg", "kvr", "Bra", "AnD", "BrD", "Anr", "Brr", "sxc", "sxE", "sxC", "sxB", "ktc", "lvc", "sxq", "sgn", "lvE", "sxn", "lvC", "ktB", "lvB", "Alc",
166
            "Bnc", "AlE", "kcn", "Drc", "BnE", "AlC", "DrE", "BnC", "AlB", "DrC", "BnB", "Alq", "Bnq", "Aln", "Drq", "Bnn", "Drn", "wyo", "wym", "wyl", "swo", "txo", "wyv", "txm", "swl", "txl", "kso",
167
            "sgf", "lto", "swv", "nvo", "ltm", "ksl", "nvm", "ltl", "nvl", "Ako", "kcf", "Blo", "ksv", "Dno", "Blm", "Akl", "bro", "Dnm", "Bll", "brm", "Dnl", "Akv", "Blv", "Dnv", "brv", "yze", "yzd",
168
            "wye", "xyu", "wyd", "xyt", "swe", "twu", "swd", "vxu", "twt", "vxt", "kse", "lsu", "ksd", "ntu", "lst", "rvu", "ypk", "zew", "xdA", "yos", "zei", "xck", "yog", "zeb", "xcc", "yoa", "xcE",
169
            "yoD", "xcC", "xhk", "yqw", "zfj", "utA", "xgs", "yqi", "usk", "xgg", "yqb", "usc", "xga", "usE", "xgD", "usC", "uxk", "xiw", "yrj", "ptA", "uws", "xii", "psk", "uwg", "xib", "psc", "uwa",
170
            "psE", "uwD", "psC", "pxk", "uyw", "xjj", "ftA", "pws", "uyi", "fsk", "pwg", "uyb", "fsc", "pwa", "fsE", "pwD", "fxk", "pyw", "uzj", "fws", "pyi", "fwg", "pyb", "fwa", "fyw", "pzj", "fyi",
171
            "fyb", "xFA", "yms", "zdi", "xEk", "ymg", "zdb", "xEc", "yma", "xEE", "ymD", "xEC", "xEB", "uhA", "xas", "yni", "ugk", "xag", "ynb", "ugc", "xaa", "ugE", "xaD", "ugC", "ugB", "oxA", "uis",
172
            "xbi", "owk", "uig", "xbb", "owc", "uia", "owE", "uiD", "owC", "owB", "dxA", "oys", "uji", "dwk", "oyg", "ujb", "dwc", "oya", "dwE", "oyD", "dwC", "dys", "ozi", "dyg", "ozb", "dya", "dyD",
173
            "dzi", "dzb", "xCk", "ylg", "zcr", "xCc", "yla", "xCE", "ylD", "xCC", "xCB", "uak", "xDg", "ylr", "uac", "xDa", "uaE", "xDD", "uaC", "uaB", "oik", "ubg", "xDr", "oic", "uba", "oiE", "ubD",
174
            "oiC", "oiB", "cyk", "ojg", "ubr", "cyc", "oja", "cyE", "ojD", "cyC", "cyB", "czg", "ojr", "cza", "czD", "czr", "xBc", "ykq", "xBE", "ykn", "xBC", "xBB", "uDc", "xBq", "uDE", "xBn", "uDC",
175
            "uDB", "obc", "uDq", "obE", "uDn", "obC", "obB", "cjc", "obq", "cjE", "obn", "cjC", "cjB", "cjq", "cjn", "xAo", "ykf", "xAm", "xAl", "uBo", "xAv", "uBm", "uBl", "oDo", "uBv", "oDm", "oDl",
176
            "cbo", "oDv", "cbm", "cbl", "xAe", "xAd", "uAu", "uAt", "oBu", "oBt", "wpA", "yes", "zFi", "wok", "yeg", "zFb", "woc", "yea", "woE", "yeD", "woC", "woB", "thA", "wqs", "yfi", "tgk", "wqg",
177
            "yfb", "tgc", "wqa", "tgE", "wqD", "tgC", "tgB", "mxA", "tis", "wri", "mwk", "tig", "wrb", "mwc", "tia", "mwE", "tiD", "mwC", "mwB", "FxA", "mys", "tji", "Fwk", "myg", "tjb", "Fwc", "mya",
178
            "FwE", "myD", "FwC", "Fys", "mzi", "Fyg", "mzb", "Fya", "FyD", "Fzi", "Fzb", "yuk", "zhg", "hjs", "yuc", "zha", "hbw", "yuE", "zhD", "hDy", "yuC", "yuB", "wmk", "ydg", "zEr", "xqk", "wmc",
179
            "zhr", "xqc", "yva", "ydD", "xqE", "wmC", "xqC", "wmB", "xqB", "tak", "wng", "ydr", "vik", "tac", "wna", "vic", "xra", "wnD", "viE", "taC", "viC", "taB", "viB", "mik", "tbg", "wnr", "qyk",
180
            "mic", "tba", "qyc", "vja", "tbD", "qyE", "miC", "qyC", "miB", "qyB", "Eyk", "mjg", "tbr", "hyk", "Eyc", "mja", "hyc", "qza", "mjD", "hyE", "EyC", "hyC", "EyB", "Ezg", "mjr", "hzg", "Eza",
181
            "hza", "EzD", "hzD", "Ezr", "ytc", "zgq", "grw", "ytE", "zgn", "gny", "ytC", "glz", "ytB", "wlc", "ycq", "xnc", "wlE", "ycn", "xnE", "ytn", "xnC", "wlB", "xnB", "tDc", "wlq", "vbc", "tDE",
182
            "wln", "vbE", "xnn", "vbC", "tDB", "vbB", "mbc", "tDq", "qjc", "mbE", "tDn", "qjE", "vbn", "qjC", "mbB", "qjB", "Ejc", "mbq", "gzc", "EjE", "mbn", "gzE", "qjn", "gzC", "EjB", "gzB", "Ejq",
183
            "gzq", "Ejn", "gzn", "yso", "zgf", "gfy", "ysm", "gdz", "ysl", "wko", "ycf", "xlo", "ysv", "xlm", "wkl", "xll", "tBo", "wkv", "vDo", "tBm", "vDm", "tBl", "vDl", "mDo", "tBv", "qbo", "vDv",
184
            "qbm", "mDl", "qbl", "Ebo", "mDv", "gjo", "Ebm", "gjm", "Ebl", "gjl", "Ebv", "gjv", "yse", "gFz", "ysd", "wke", "xku", "wkd", "xkt", "tAu", "vBu", "tAt", "vBt", "mBu", "qDu", "mBt", "qDt",
185
            "EDu", "gbu", "EDt", "gbt", "ysF", "wkF", "xkh", "tAh", "vAx", "mAx", "qBx", "wek", "yFg", "zCr", "wec", "yFa", "weE", "yFD", "weC", "weB", "sqk", "wfg", "yFr", "sqc", "wfa", "sqE", "wfD",
186
            "sqC", "sqB", "lik", "srg", "wfr", "lic", "sra", "liE", "srD", "liC", "liB", "Cyk", "ljg", "srr", "Cyc", "lja", "CyE", "ljD", "CyC", "CyB", "Czg", "ljr", "Cza", "CzD", "Czr", "yhc", "zaq",
187
            "arw", "yhE", "zan", "any", "yhC", "alz", "yhB", "wdc", "yEq", "wvc", "wdE", "yEn", "wvE", "yhn", "wvC", "wdB", "wvB", "snc", "wdq", "trc", "snE", "wdn", "trE", "wvn", "trC", "snB", "trB",
188
            "lbc", "snq", "njc", "lbE", "snn", "njE", "trn", "njC", "lbB", "njB", "Cjc", "lbq", "azc", "CjE", "lbn", "azE", "njn", "azC", "CjB", "azB", "Cjq", "azq", "Cjn", "azn", "zio", "irs", "rfy",
189
            "zim", "inw", "rdz", "zil", "ily", "ikz", "ygo", "zaf", "afy", "yxo", "ziv", "ivy", "adz", "yxm", "ygl", "itz", "yxl", "wco", "yEf", "wto", "wcm", "xvo", "yxv", "wcl", "xvm", "wtl", "xvl",
190
            "slo", "wcv", "tno", "slm", "vro", "tnm", "sll", "vrm", "tnl", "vrl", "lDo", "slv", "nbo", "lDm", "rjo", "nbm", "lDl", "rjm", "nbl", "rjl", "Cbo", "lDv", "ajo", "Cbm", "izo", "ajm", "Cbl",
191
            "izm", "ajl", "izl", "Cbv", "ajv", "zie", "ifw", "rFz", "zid", "idy", "icz", "yge", "aFz", "ywu", "ygd", "ihz", "ywt", "wce", "wsu", "wcd", "xtu", "wst", "xtt", "sku", "tlu", "skt", "vnu",
192
            "tlt", "vnt", "lBu", "nDu", "lBt", "rbu", "nDt", "rbt", "CDu", "abu", "CDt", "iju", "abt", "ijt", "ziF", "iFy", "iEz", "ygF", "ywh", "wcF", "wsh", "xsx", "skh", "tkx", "vlx", "lAx", "nBx",
193
            "rDx", "CBx", "aDx", "ibx", "iCz", "wFc", "yCq", "wFE", "yCn", "wFC", "wFB", "sfc", "wFq", "sfE", "wFn", "sfC", "sfB", "krc", "sfq", "krE", "sfn", "krC", "krB", "Bjc", "krq", "BjE", "krn",
194
            "BjC", "BjB", "Bjq", "Bjn", "yao", "zDf", "Dfy", "yam", "Ddz", "yal", "wEo", "yCf", "who", "wEm", "whm", "wEl", "whl", "sdo", "wEv", "svo", "sdm", "svm", "sdl", "svl", "kno", "sdv", "lro",
195
            "knm", "lrm", "knl", "lrl", "Bbo", "knv", "Djo", "Bbm", "Djm", "Bbl", "Djl", "Bbv", "Djv", "zbe", "bfw", "npz", "zbd", "bdy", "bcz", "yae", "DFz", "yiu", "yad", "bhz", "yit", "wEe", "wgu",
196
            "wEd", "wxu", "wgt", "wxt", "scu", "stu", "sct", "tvu", "stt", "tvt", "klu", "lnu", "klt", "nru", "lnt", "nrt", "BDu", "Dbu", "BDt", "bju", "Dbt", "bjt", "jfs", "rpy", "jdw", "roz", "jcy",
197
            "jcj", "zbF", "bFy", "zjh", "jhy", "bEz", "jgz", "yaF", "yih", "yyx", "wEF", "wgh", "wwx", "xxx", "sch", "ssx", "ttx", "vvx", "kkx", "llx", "nnx", "rrx", "BBx", "DDx", "bbx", "jFw", "rmz",
198
            "jEy", "jEj", "bCz", "jaz", "jCy", "jCj", "jBj", "wCo", "wCm", "wCl", "sFo", "wCv", "sFm", "sFl", "kfo", "sFv", "kfm", "kfl", "Aro", "kfv", "Arm", "Arl", "Arv", "yDe", "Bpz", "yDd", "wCe",
199
            "wau", "wCd", "wat", "sEu", "shu", "sEt", "sht", "kdu", "kvu", "kdt", "kvt", "Anu", "Bru", "Ant", "Brt", "zDp", "Dpy", "Doz", "yDF", "ybh", "wCF", "wah", "wix", "sEh", "sgx", "sxx", "kcx",
200
            "ktx", "lvx", "Alx", "Bnx", "Drx", "bpw", "nuz", "boy", "boj", "Dmz", "bqz", "jps", "ruy", "jow", "ruj", "joi", "job", "bmy", "jqy", "bmj", "jqj", "jmw", "rtj", "jmi", "jmb", "blj", "jnj",
201
            "jli", "jlb", "jkr", "sCu", "sCt", "kFu", "kFt", "Afu", "Aft", "wDh", "sCh", "sax", "kEx", "khx", "Adx", "Avx", "Buz", "Duy", "Duj", "buw", "nxj", "bui", "bub", "Dtj", "bvj", "jus", "rxi",
202
            "jug", "rxb", "jua", "juD", "bti", "jvi", "btb", "jvb", "jtg", "rwr", "jta", "jtD", "bsr", "jtr", "jsq", "jsn", "Bxj", "Dxi", "Dxb", "bxg", "nyr", "bxa", "bxD", "Dwr", "bxr", "bwq", "bwn",
203
            "pjk", "urw", "ejA", "pbs", "uny", "ebk", "pDw", "ulz", "eDs", "pBy", "eBw", "zfc", "fjk", "prw", "zfE", "fbs", "pny", "zfC", "fDw", "plz", "zfB", "fBy", "yrc", "zfq", "frw", "yrE", "zfn",
204
            "fny", "yrC", "flz", "yrB", "xjc", "yrq", "xjE", "yrn", "xjC", "xjB", "uzc", "xjq", "uzE", "xjn", "uzC", "uzB", "pzc", "uzq", "pzE", "uzn", "pzC", "djA", "ors", "ufy", "dbk", "onw", "udz",
205
            "dDs", "oly", "dBw", "okz", "dAy", "zdo", "drs", "ovy", "zdm", "dnw", "otz", "zdl", "dly", "dkz", "yno", "zdv", "dvy", "ynm", "dtz", "ynl", "xbo", "ynv", "xbm", "xbl", "ujo", "xbv", "ujm",
206
            "ujl", "ozo", "ujv", "ozm", "ozl", "crk", "ofw", "uFz", "cns", "ody", "clw", "ocz", "cky", "ckj", "zcu", "cvw", "ohz", "zct", "cty", "csz", "ylu", "cxz", "ylt", "xDu", "xDt", "ubu", "ubt",
207
            "oju", "ojt", "cfs", "oFy", "cdw", "oEz", "ccy", "ccj", "zch", "chy", "cgz", "ykx", "xBx", "uDx", "cFw", "oCz", "cEy", "cEj", "caz", "cCy", "cCj", "FjA", "mrs", "tfy", "Fbk", "mnw", "tdz",
208
            "FDs", "mly", "FBw", "mkz", "FAy", "zFo", "Frs", "mvy", "zFm", "Fnw", "mtz", "zFl", "Fly", "Fkz", "yfo", "zFv", "Fvy", "yfm", "Ftz", "yfl", "wro", "yfv", "wrm", "wrl", "tjo", "wrv", "tjm",
209
            "tjl", "mzo", "tjv", "mzm", "mzl", "qrk", "vfw", "xpz", "hbA", "qns", "vdy", "hDk", "qlw", "vcz", "hBs", "qky", "hAw", "qkj", "hAi", "Erk", "mfw", "tFz", "hrk", "Ens", "mdy", "hns", "qty",
210
            "mcz", "hlw", "Eky", "hky", "Ekj", "hkj", "zEu", "Evw", "mhz", "zhu", "zEt", "hvw", "Ety", "zht", "hty", "Esz", "hsz", "ydu", "Exz", "yvu", "ydt", "hxz", "yvt", "wnu", "xru", "wnt", "xrt",
211
            "tbu", "vju", "tbt", "vjt", "mju", "mjt", "grA", "qfs", "vFy", "gnk", "qdw", "vEz", "gls", "qcy", "gkw", "qcj", "gki", "gkb", "Efs", "mFy", "gvs", "Edw", "mEz", "gtw", "qgz", "gsy", "Ecj",
212
            "gsj", "zEh", "Ehy", "zgx", "gxy", "Egz", "gwz", "ycx", "ytx", "wlx", "xnx", "tDx", "vbx", "mbx", "gfk", "qFw", "vCz", "gds", "qEy", "gcw", "qEj", "gci", "gcb", "EFw", "mCz", "ghw", "EEy",
213
            "ggy", "EEj", "ggj", "Eaz", "giz", "gFs", "qCy", "gEw", "qCj", "gEi", "gEb", "ECy", "gay", "ECj", "gaj", "gCw", "qBj", "gCi", "gCb", "EBj", "gDj", "gBi", "gBb", "Crk", "lfw", "spz", "Cns",
214
            "ldy", "Clw", "lcz", "Cky", "Ckj", "zCu", "Cvw", "lhz", "zCt", "Cty", "Csz", "yFu", "Cxz", "yFt", "wfu", "wft", "sru", "srt", "lju", "ljt", "arA", "nfs", "tpy", "ank", "ndw", "toz", "als",
215
            "ncy", "akw", "ncj", "aki", "akb", "Cfs", "lFy", "avs", "Cdw", "lEz", "atw", "ngz", "asy", "Ccj", "asj", "zCh", "Chy", "zax", "axy", "Cgz", "awz", "yEx", "yhx", "wdx", "wvx", "snx", "trx",
216
            "lbx", "rfk", "vpw", "xuz", "inA", "rds", "voy", "ilk", "rcw", "voj", "iks", "rci", "ikg", "rcb", "ika", "afk", "nFw", "tmz", "ivk", "ads", "nEy", "its", "rgy", "nEj", "isw", "aci", "isi",
217
            "acb", "isb", "CFw", "lCz", "ahw", "CEy", "ixw", "agy", "CEj", "iwy", "agj", "iwj", "Caz", "aiz", "iyz", "ifA", "rFs", "vmy", "idk", "rEw", "vmj", "ics", "rEi", "icg", "rEb", "ica", "icD",
218
            "aFs", "nCy", "ihs", "aEw", "nCj", "igw", "raj", "igi", "aEb", "igb", "CCy", "aay", "CCj", "iiy", "aaj", "iij", "iFk", "rCw", "vlj", "iEs", "rCi", "iEg", "rCb", "iEa", "iED", "aCw", "nBj",
219
            "iaw", "aCi", "iai", "aCb", "iab", "CBj", "aDj", "ibj", "iCs", "rBi", "iCg", "rBb", "iCa", "iCD", "aBi", "iDi", "aBb", "iDb", "iBg", "rAr", "iBa", "iBD", "aAr", "iBr", "iAq", "iAn", "Bfs",
220
            "kpy", "Bdw", "koz", "Bcy", "Bcj", "Bhy", "Bgz", "yCx", "wFx", "sfx", "krx", "Dfk", "lpw", "suz", "Dds", "loy", "Dcw", "loj", "Dci", "Dcb", "BFw", "kmz", "Dhw", "BEy", "Dgy", "BEj", "Dgj",
221
            "Baz", "Diz", "bfA", "nps", "tuy", "bdk", "now", "tuj", "bcs", "noi", "bcg", "nob", "bca", "bcD", "DFs", "lmy", "bhs", "DEw", "lmj", "bgw", "DEi", "bgi", "DEb", "bgb", "BCy", "Day", "BCj",
222
            "biy", "Daj", "bij", "rpk", "vuw", "xxj", "jdA", "ros", "vui", "jck", "rog", "vub", "jcc", "roa", "jcE", "roD", "jcC", "bFk", "nmw", "ttj", "jhk", "bEs", "nmi", "jgs", "rqi", "nmb", "jgg",
223
            "bEa", "jga", "bED", "jgD", "DCw", "llj", "baw", "DCi", "jiw", "bai", "DCb", "jii", "bab", "jib", "BBj", "DDj", "bbj", "jjj", "jFA", "rms", "vti", "jEk", "rmg", "vtb", "jEc", "rma", "jEE",
224
            "rmD", "jEC", "jEB", "bCs", "nli", "jas", "bCg", "nlb", "jag", "rnb", "jaa", "bCD", "jaD", "DBi", "bDi", "DBb", "jbi", "bDb", "jbb", "jCk", "rlg", "vsr", "jCc", "rla", "jCE", "rlD", "jCC",
225
            "jCB", "bBg", "nkr", "jDg", "bBa", "jDa", "bBD", "jDD", "DAr", "bBr", "jDr", "jBc", "rkq", "jBE", "rkn", "jBC", "jBB", "bAq", "jBq", "bAn", "jBn", "jAo", "rkf", "jAm", "jAl", "bAf", "jAv",
226
            "Apw", "kez", "Aoy", "Aoj", "Aqz", "Bps", "kuy", "Bow", "kuj", "Boi", "Bob", "Amy", "Bqy", "Amj", "Bqj", "Dpk", "luw", "sxj", "Dos", "lui", "Dog", "lub", "Doa", "DoD", "Bmw", "ktj", "Dqw",
227
            "Bmi", "Dqi", "Bmb", "Dqb", "Alj", "Bnj", "Drj", "bpA", "nus", "txi", "bok", "nug", "txb", "boc", "nua", "boE", "nuD", "boC", "boB", "Dms", "lti", "bqs", "Dmg", "ltb", "bqg", "nvb", "bqa",
228
            "DmD", "bqD", "Bli", "Dni", "Blb", "bri", "Dnb", "brb", "ruk", "vxg", "xyr", "ruc", "vxa", "ruE", "vxD", "ruC", "ruB", "bmk", "ntg", "twr", "jqk", "bmc", "nta", "jqc", "rva", "ntD", "jqE",
229
            "bmC", "jqC", "bmB", "jqB", "Dlg", "lsr", "bng", "Dla", "jrg", "bna", "DlD", "jra", "bnD", "jrD", "Bkr", "Dlr", "bnr", "jrr", "rtc", "vwq", "rtE", "vwn", "rtC", "rtB", "blc", "nsq", "jnc",
230
            "blE", "nsn", "jnE", "rtn", "jnC", "blB", "jnB", "Dkq", "blq", "Dkn", "jnq", "bln", "jnn", "rso", "vwf", "rsm", "rsl", "bko", "nsf", "jlo", "bkm", "jlm", "bkl", "jll", "Dkf", "bkv", "jlv",
231
            "rse", "rsd", "bke", "jku", "bkd", "jkt", "Aey", "Aej", "Auw", "khj", "Aui", "Aub", "Adj", "Avj", "Bus", "kxi", "Bug", "kxb", "Bua", "BuD", "Ati", "Bvi", "Atb", "Bvb", "Duk", "lxg", "syr",
232
            "Duc", "lxa", "DuE", "lxD", "DuC", "DuB", "Btg", "kwr", "Dvg", "lxr", "Dva", "BtD", "DvD", "Asr", "Btr", "Dvr", "nxc", "tyq", "nxE", "tyn", "nxC", "nxB", "Dtc", "lwq", "bvc", "nxq", "lwn",
233
            "bvE", "DtC", "bvC", "DtB", "bvB", "Bsq", "Dtq", "Bsn", "bvq", "Dtn", "bvn", "vyo", "xzf", "vym", "vyl", "nwo", "tyf", "rxo", "nwm", "rxm", "nwl", "rxl", "Dso", "lwf", "bto", "Dsm", "jvo",
234
            "btm", "Dsl", "jvm", "btl", "jvl", "Bsf", "Dsv", "btv", "jvv", "vye", "vyd", "nwe", "rwu", "nwd", "rwt", "Dse", "bsu", "Dsd", "jtu", "bst", "jtt", "vyF", "nwF", "rwh", "DsF", "bsh", "jsx",
235
            "Ahi", "Ahb", "Axg", "kir", "Axa", "AxD", "Agr", "Axr", "Bxc", "kyq", "BxE", "kyn", "BxC", "BxB", "Awq", "Bxq", "Awn", "Bxn", "lyo", "szf", "lym", "lyl", "Bwo", "kyf", "Dxo", "lyv", "Dxm",
236
            "Bwl", "Dxl", "Awf", "Bwv", "Dxv", "tze", "tzd", "lye", "nyu", "lyd", "nyt", "Bwe", "Dwu", "Bwd", "bxu", "Dwt", "bxt", "tzF", "lyF", "nyh", "BwF", "Dwh", "bwx", "Aiq", "Ain", "Ayo", "kjf",
237
            "Aym", "Ayl", "Aif", "Ayv", "kze", "kzd", "Aye", "Byu", "Ayd", "Byt", "szp" };
238
 
239
    private static final char[] BR_SET = { 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
240
            'z', '*', '+', '-' };
241
 
242
    private static final String[] PDF_TTF = { "00000", "00001", "00010", "00011", "00100", "00101", "00110", "00111", "01000", "01001", "01010", "01011", "01100", "01101", "01110", "01111", "10000",
243
            "10001", "10010", "10011", "10100", "10101", "10110", "10111", "11000", "11001", "11010", "11011", "11100", "11101", "11110", "11111", "01", "1111111101010100", "11111101000101001" };
244
 
245
    /* Left and Right Row Address Pattern from Table 2 */
246
    private static final String[] RAPLR = { "", "221311", "311311", "312211", "222211", "213211", "214111", "223111", "313111", "322111", "412111", "421111", "331111", "241111", "232111", "231211",
247
            "321211", "411211", "411121", "411112", "321112", "312112", "311212", "311221", "311131", "311122", "311113", "221113", "221122", "221131", "221221", "222121", "312121", "321121",
248
            "231121", "231112", "222112", "213112", "212212", "212221", "212131", "212122", "212113", "211213", "211123", "211132", "211141", "211231", "211222", "211312", "211321", "211411",
249
            "212311" };
250
 
251
    /* Centre Row Address Pattern from Table 2 */
252
    private static final String[] RAPC = { "", "112231", "121231", "122131", "131131", "131221", "132121", "141121", "141211", "142111", "133111", "132211", "131311", "122311", "123211", "124111",
253
            "115111", "114211", "114121", "123121", "123112", "122212", "122221", "121321", "121411", "112411", "113311", "113221", "113212", "113122", "122122", "131122", "131113", "122113",
254
            "113113", "112213", "112222", "112312", "112321", "111421", "111331", "111322", "111232", "111223", "111133", "111124", "111214", "112114", "121114", "121123", "121132", "112132",
255
            "112141" };
256
 
257
    private static final int[] MICRO_VARIANTS = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 11, 14, 17, 20, 24, 28, 8, 11, 14, 17, 20, 23,
258
            26, 6, 8, 10, 12, 15, 20, 26, 32, 38, 44, 4, 6, 8, 10, 12, 15, 20, 26, 32, 38, 44, 7, 7, 7, 8, 8, 8, 8, 9, 9, 10, 11, 13, 15, 12, 14, 16, 18, 21, 26, 32, 38, 44, 50, 8, 12, 14, 16, 18, 21,
259
            26, 32, 38, 44, 50, 0, 0, 0, 7, 7, 7, 7, 15, 15, 24, 34, 57, 84, 45, 70, 99, 115, 133, 154, 180, 212, 250, 294, 7, 45, 70, 99, 115, 133, 154, 180, 212, 250, 294 };
260
 
261
    /* rows, columns, error codewords, k-offset */
262
    /* MicroPDF417 coefficients from ISO/IEC 24728:2006 Annex F */
263
    private static final int[] MICROCOEFFS = {
264
            /* k = 7 */
265
            76, 925, 537, 597, 784, 691, 437,
266
            /* k = 8 */
267
            237, 308, 436, 284, 646, 653, 428, 379,
268
            /* k = 9 */
269
            567, 527, 622, 257, 289, 362, 501, 441, 205,
270
            /* k = 10 */
271
            377, 457, 64, 244, 826, 841, 818, 691, 266, 612,
272
            /* k = 11 */
273
            462, 45, 565, 708, 825, 213, 15, 68, 327, 602, 904,
274
            /* k = 12 */
275
            597, 864, 757, 201, 646, 684, 347, 127, 388, 7, 69, 851,
276
            /* k = 13 */
277
            764, 713, 342, 384, 606, 583, 322, 592, 678, 204, 184, 394, 692,
278
            /* k = 14 */
279
            669, 677, 154, 187, 241, 286, 274, 354, 478, 915, 691, 833, 105, 215,
280
            /* k = 15 */
281
            460, 829, 476, 109, 904, 664, 230, 5, 80, 74, 550, 575, 147, 868, 642,
282
            /* k = 16 */
283
            274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, 42, 176, 65,
284
            /* k = 18 */
285
            279, 577, 315, 624, 37, 855, 275, 739, 120, 297, 312, 202, 560, 321, 233, 756, 760, 573,
286
            /* k = 21 */
287
            108, 519, 781, 534, 129, 425, 681, 553, 422, 716, 763, 693, 624, 610, 310, 691, 347, 165, 193, 259, 568,
288
            /* k = 26 */
289
            443, 284, 887, 544, 788, 93, 477, 760, 331, 608, 269, 121, 159, 830, 446, 893, 699, 245, 441, 454, 325, 858, 131, 847, 764, 169,
290
            /* k = 32 */
291
            361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, 284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803, 133, 231, 390, 685, 330, 63, 410,
292
            /* k = 38 */
293
            234, 228, 438, 848, 133, 703, 529, 721, 788, 322, 280, 159, 738, 586, 388, 684, 445, 680, 245, 595, 614, 233, 812, 32, 284, 658, 745, 229, 95, 689, 920, 771, 554, 289, 231, 125, 117, 518,
294
            /* k = 44 */
295
            476, 36, 659, 848, 678, 64, 764, 840, 157, 915, 470, 876, 109, 25, 632, 405, 417, 436, 714, 60, 376, 97, 413, 706, 446, 21, 3, 773, 569, 267, 272, 213, 31, 560, 231, 758, 103, 271, 572,
296
            436, 339, 730, 82, 285,
297
            /* k = 50 */
298
            923, 797, 576, 875, 156, 706, 63, 81, 257, 874, 411, 416, 778, 50, 205, 303, 188, 535, 909, 155, 637, 230, 534, 96, 575, 102, 264, 233, 919, 593, 865, 26, 579, 623, 766, 146, 10, 739, 246,
299
            127, 71, 244, 211, 477, 920, 876, 427, 820, 718, 435 };
300
 
301
    /*
302
     * following is Left RAP, Centre RAP, Right RAP and Start Cluster from ISO/IEC 24728:2006 tables
303
     * 10, 11 and 12
304
     */
305
    private static final int[] RAP_TABLE = { 1, 8, 36, 19, 9, 25, 1, 1, 8, 36, 19, 9, 27, 1, 7, 15, 25, 37, 1, 1, 21, 15, 1, 47, 1, 7, 15, 25, 37, 1, 1, 21, 15, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
306
            0, 1, 7, 15, 25, 37, 17, 9, 29, 31, 25, 19, 1, 7, 15, 25, 37, 17, 9, 29, 31, 25, 9, 8, 36, 19, 17, 33, 1, 9, 8, 36, 19, 17, 35, 1, 7, 15, 25, 37, 33, 17, 37, 47, 49, 43, 1, 7, 15, 25, 37,
307
            33, 17, 37, 47, 49, 0, 3, 6, 0, 6, 0, 0, 0, 3, 6, 0, 6, 6, 0, 0, 6, 0, 0, 0, 0, 6, 6, 0, 3, 0, 0, 6, 0, 0, 0, 0, 6, 6, 0 };
308
 
309
    private String binary_string;
310
    private int ecc;
311
    private LinearEncoding symbology = LinearEncoding.CODE_128;
312
    private String general_field;
313
    private GeneralFieldMode[] general_field_type;
314
    private int cc_width;
315
    private final int[][] pwr928 = new int[69][7];
316
    private final int[] codeWords = new int[180];
317
    private int codeWordCount;
318
    private final int[] bitStr = new int[13];
319
    private int[] inputData;
320
    private CompositeMode cc_mode;
321
    private String linearContent;
322
    private CompositeMode userPreferredMode = CompositeMode.CC_A;
323
    private int target_bitsize;
324
    private int remainder;
325
    private int linearWidth; // Width of Code 128 linear
326
 
327
    public Composite() {
328
        this.inputDataType = Symbol.DataType.GS1;
329
    }
330
 
331
    @Override
332
    public void setDataType(final DataType dataType) {
333
        if (dataType != Symbol.DataType.GS1) {
334
            throw new IllegalArgumentException("Only GS1 data type is supported for GS1 Composite symbology.");
335
        }
336
    }
337
 
338
    @Override
339
    protected boolean gs1Supported() {
340
        return true;
341
    }
342
 
343
    /**
344
     * Set the type of linear component included in the composite symbol, this will determine how
345
     * the lower part of the symbol is encoded.
346
     *
347
     * @param linearSymbology The symbology of the linear component
348
     */
349
    public void setSymbology(final LinearEncoding linearSymbology) {
350
        this.symbology = linearSymbology;
351
    }
352
 
353
    /**
354
     * Returns the type of linear component included in the composite symbol.
355
     *
356
     * @return the type of linear component included in the composite symbol
357
     */
358
    public LinearEncoding getSymbology() {
359
        return this.symbology;
360
    }
361
 
362
    /**
363
     * Set the data to be encoded in the linear component of the composite symbol.
364
     *
365
     * @param linearContent the linear data in GS1 format
366
     */
367
    public void setLinearContent(final String linearContent) {
368
        this.linearContent = linearContent;
369
    }
370
 
371
    /**
372
     * Returns the data encoded in the linear component of the composite symbol.
373
     *
374
     * @return the data encoded in the linear component of the composite symbol
375
     */
376
    public String getLinearContent() {
377
        return this.linearContent;
378
    }
379
 
380
    /**
381
     * Set the preferred encoding method for the 2D component of the composite symbol. This value
382
     * may be ignored if the amount of data supplied is too big for the selected encoding. Mode CC-C
383
     * can only be used with a Code 128 linear component.
384
     *
385
     * @param userMode Preferred mode
386
     */
387
    public void setPreferredMode(final CompositeMode userMode) {
388
        this.userPreferredMode = userMode;
389
    }
390
 
391
    /**
392
     * Returns the preferred encoding method for the 2D component of the composite symbol.
393
     *
394
     * @return the preferred encoding method for the 2D component of the composite symbol
395
     */
396
    public CompositeMode getPreferredMode() {
397
        return this.userPreferredMode;
398
    }
399
 
400
    @Override
401
    protected void encode() {
402
 
403
        List<Rectangle2D.Double> linear_rect;
404
        List<TextBox> linear_txt;
405
        final List<Rectangle2D.Double> combine_rect = new ArrayList<>();
406
        final List<TextBox> combine_txt = new ArrayList<>();
407
        String linear_encodeInfo;
408
        int linear_height;
409
        int top_shift = 0; // 2D component x-coordinate shift
410
        int bottom_shift = 0; // linear component x-coordinate shift
411
        this.linearWidth = 0;
412
 
413
        if (this.linearContent.isEmpty()) {
414
            throw new OkapiException("No linear data set");
415
        }
416
 
417
        // Manage composite component encoding first
418
        encodeComposite();
419
 
420
        // Then encode linear component
421
        switch (this.symbology) {
422
        case UPCA:
423
            final Upc upca = new Upc();
424
            upca.setMode(Upc.Mode.UPCA);
425
            upca.setLinkageFlag(true);
426
            upca.setContent(this.linearContent);
427
            linear_rect = upca.rectangles;
428
            linear_txt = upca.texts;
429
            linear_height = upca.symbol_height;
430
            linear_encodeInfo = upca.getEncodeInfo();
431
            bottom_shift = 6;
432
            top_shift = 3;
433
            break;
434
        case UPCE:
435
            final Upc upce = new Upc();
436
            upce.setMode(Upc.Mode.UPCE);
437
            upce.setLinkageFlag(true);
438
            upce.setContent(this.linearContent);
439
            linear_rect = upce.rectangles;
440
            linear_txt = upce.texts;
441
            linear_height = upce.symbol_height;
442
            linear_encodeInfo = upce.getEncodeInfo();
443
            bottom_shift = 6;
444
            top_shift = 3;
445
            break;
446
        case EAN:
447
            final Ean ean = new Ean();
448
            if (eanCalculateVersion() == 8) {
449
                ean.setMode(Ean.Mode.EAN8);
450
                bottom_shift = 14;
451
            } else {
452
                ean.setMode(Ean.Mode.EAN13);
453
                bottom_shift = 6;
454
                top_shift = 3;
455
            }
456
            ean.setLinkageFlag(true);
457
            ean.setContent(this.linearContent);
458
            linear_rect = ean.rectangles;
459
            linear_txt = ean.texts;
460
            linear_height = ean.symbol_height;
461
            linear_encodeInfo = ean.getEncodeInfo();
462
            break;
463
        case CODE_128:
464
            final Code128 code128 = new Code128();
465
            switch (this.cc_mode) {
466
            case CC_A:
467
                code128.setCca();
468
                break;
469
            case CC_B:
470
                code128.setCcb();
471
                break;
472
            case CC_C:
473
                code128.setCcc();
474
                bottom_shift = 7;
475
                break;
476
            }
477
            code128.setDataType(Symbol.DataType.GS1);
478
            code128.setContent(this.linearContent);
479
            this.linearWidth = code128.symbol_width;
480
            linear_rect = code128.rectangles;
481
            linear_txt = code128.texts;
482
            linear_height = code128.symbol_height;
483
            linear_encodeInfo = code128.getEncodeInfo();
484
            break;
485
        case DATABAR_14:
486
            final DataBar14 dataBar14 = new DataBar14();
487
            dataBar14.setLinkageFlag(true);
488
            dataBar14.setMode(Mode.LINEAR);
489
            dataBar14.setContent(this.linearContent);
490
            linear_rect = dataBar14.rectangles;
491
            linear_txt = dataBar14.texts;
492
            linear_height = dataBar14.symbol_height;
493
            linear_encodeInfo = dataBar14.getEncodeInfo();
494
            bottom_shift = 4;
495
            break;
496
        case DATABAR_14_STACK_OMNI:
497
            final DataBar14 dataBar14SO = new DataBar14();
498
            dataBar14SO.setLinkageFlag(true);
499
            dataBar14SO.setMode(Mode.OMNI);
500
            dataBar14SO.setContent(this.linearContent);
501
            linear_rect = dataBar14SO.rectangles;
502
            linear_txt = dataBar14SO.texts;
503
            linear_height = dataBar14SO.symbol_height;
504
            linear_encodeInfo = dataBar14SO.getEncodeInfo();
505
            top_shift = 1;
506
            break;
507
        case DATABAR_14_STACK:
508
            final DataBar14 dataBar14S = new DataBar14();
509
            dataBar14S.setLinkageFlag(true);
510
            dataBar14S.setMode(Mode.STACKED);
511
            dataBar14S.setContent(this.linearContent);
512
            linear_rect = dataBar14S.rectangles;
513
            linear_txt = dataBar14S.texts;
514
            linear_height = dataBar14S.symbol_height;
515
            linear_encodeInfo = dataBar14S.getEncodeInfo();
516
            top_shift = 1;
517
            break;
518
        case DATABAR_LIMITED:
519
            final DataBarLimited dataBarLimited = new DataBarLimited();
520
            dataBarLimited.setLinkageFlag();
521
            dataBarLimited.setContent(this.linearContent);
522
            linear_rect = dataBarLimited.rectangles;
523
            linear_txt = dataBarLimited.texts;
524
            linear_height = dataBarLimited.symbol_height;
525
            linear_encodeInfo = dataBarLimited.getEncodeInfo();
526
            top_shift = 1;
527
            bottom_shift = 10;
528
            break;
529
        case DATABAR_EXPANDED:
530
            final DataBarExpanded dataBarExpanded = new DataBarExpanded();
531
            dataBarExpanded.setLinkageFlag(true);
532
            dataBarExpanded.setStacked(false);
533
            dataBarExpanded.setContent(this.linearContent);
534
            linear_rect = dataBarExpanded.rectangles;
535
            linear_txt = dataBarExpanded.texts;
536
            linear_height = dataBarExpanded.symbol_height;
537
            linear_encodeInfo = dataBarExpanded.getEncodeInfo();
538
            top_shift = 2;
539
            break;
540
        case DATABAR_EXPANDED_STACK:
541
            final DataBarExpanded dataBarExpandedS = new DataBarExpanded();
542
            dataBarExpandedS.setLinkageFlag(true);
543
            dataBarExpandedS.setStacked(true);
544
            dataBarExpandedS.setContent(this.linearContent);
545
            linear_rect = dataBarExpandedS.rectangles;
546
            linear_txt = dataBarExpandedS.texts;
547
            linear_height = dataBarExpandedS.symbol_height;
548
            linear_encodeInfo = dataBarExpandedS.getEncodeInfo();
549
            top_shift = 2;
550
            break;
551
        default:
552
            throw new OkapiException("Linear symbol not recognised");
553
        }
554
 
555
        if (this.cc_mode == CompositeMode.CC_C && this.symbology == LinearEncoding.CODE_128) {
556
            /*
557
             * Width of composite component depends on width of linear component, so recalculate.
558
             */
559
            this.row_count = 0;
560
            this.rectangles.clear();
561
            this.symbol_height = 0;
562
            this.symbol_width = 0;
563
            this.encodeInfo.setLength(0);
564
            encodeComposite();
565
        }
566
 
567
        if (this.cc_mode != CompositeMode.CC_C && this.symbology == LinearEncoding.CODE_128) {
568
            if (this.linearWidth > this.symbol_width) {
569
                top_shift = (this.linearWidth - this.symbol_width) / 2;
570
            }
571
        }
572
 
573
        for (final Rectangle2D.Double orig : this.rectangles) {
574
            combine_rect.add(new Rectangle2D.Double(orig.x + top_shift, orig.y, orig.width, orig.height));
575
        }
576
 
577
        for (final Rectangle2D.Double orig : linear_rect) {
578
            combine_rect.add(new Rectangle2D.Double(orig.x + bottom_shift, orig.y + this.symbol_height, orig.width, orig.height));
579
        }
580
 
581
        int max_x = 0;
582
        for (final Rectangle2D.Double rect : combine_rect) {
583
            if (rect.x + rect.width > max_x) {
584
                max_x = (int) Math.ceil(rect.x + rect.width);
585
            }
586
        }
587
 
588
        for (final TextBox orig : linear_txt) {
589
            combine_txt.add(new TextBox(orig.x + bottom_shift, orig.y + this.symbol_height, orig.width, orig.text, this.humanReadableAlignment));
590
        }
591
 
592
        this.rectangles = combine_rect;
593
        this.texts = combine_txt;
594
        this.symbol_height += linear_height;
595
        this.symbol_width = max_x;
596
        info(linear_encodeInfo);
597
    }
598
 
599
    private void encodeComposite() {
600
 
601
        if (this.content.length() > 2990) {
602
            throw new OkapiException("2D component input data too long");
603
        }
604
 
605
        this.cc_mode = this.userPreferredMode;
606
 
607
        if (this.cc_mode == CompositeMode.CC_C && this.symbology != LinearEncoding.CODE_128) {
608
            /* CC-C can only be used with a GS1-128 linear part */
609
            throw new OkapiException("Invalid mode (CC-C only valid with GS1-128 linear component)");
610
        }
611
 
612
        switch (this.symbology) {
613
        /* Determine width of 2D component according to ISO/IEC 24723 Table 1 */
614
        case EAN:
615
            if (eanCalculateVersion() == 8) {
616
                this.cc_width = 3;
617
            } else {
618
                this.cc_width = 4;
619
            }
620
            break;
621
        case UPCE:
622
        case DATABAR_14_STACK_OMNI:
623
        case DATABAR_14_STACK:
624
            this.cc_width = 2;
625
            break;
626
        case DATABAR_LIMITED:
627
            this.cc_width = 3;
628
            break;
629
        case CODE_128:
630
        case DATABAR_14:
631
        case DATABAR_EXPANDED:
632
        case UPCA:
633
        case DATABAR_EXPANDED_STACK:
634
            this.cc_width = 4;
635
            break;
636
        }
637
 
638
        infoLine("Composite Width: " + this.cc_width);
639
 
640
        if (this.cc_mode == CompositeMode.CC_A && !cc_binary_string()) {
641
            this.cc_mode = CompositeMode.CC_B;
642
        }
643
 
644
        if (this.cc_mode == CompositeMode.CC_B) { /*
645
                                                   * If the data didn't fit into CC-A it is
646
                                                   * recalculated for CC-B
647
                                                   */
648
            if (!cc_binary_string()) {
649
                if (this.symbology != LinearEncoding.CODE_128) {
650
                    throw new OkapiException("Input too long");
651
                } else {
652
                    this.cc_mode = CompositeMode.CC_C;
653
                }
654
            }
655
        }
656
 
657
        if (this.cc_mode == CompositeMode.CC_C) {
658
            /*
659
             * If the data didn't fit in CC-B (and linear part is GS1-128) it is recalculated for
660
             * CC-C
661
             */
662
            if (!cc_binary_string()) {
663
                throw new OkapiException("Input too long");
664
            }
665
        }
666
 
667
        switch (this.cc_mode) { /* Note that ecc_level is only relevant to CC-C */
668
        case CC_A:
669
            cc_a();
670
            infoLine("Composite Type: CC-A");
671
            break;
672
        case CC_B:
673
            cc_b();
674
            infoLine("Composite Type: CC-B");
675
            break;
676
        case CC_C:
677
            cc_c();
678
            infoLine("Composite Type: CC-C");
679
            break;
680
        }
681
 
682
        super.plotSymbol();
683
    }
684
 
685
    @Override
686
    protected void plotSymbol() {
687
        // empty
688
    }
689
 
690
    private int eanCalculateVersion() {
691
        /* Determine if EAN-8 or EAN-13 is being used */
692
 
693
        int length = 0;
694
        int i;
695
        boolean latch;
696
 
697
        latch = true;
698
        for (i = 0; i < this.linearContent.length(); i++) {
699
            if (this.linearContent.charAt(i) >= '0' && this.linearContent.charAt(i) <= '9') {
700
                if (latch) {
701
                    length++;
702
                }
703
            } else {
704
                latch = false;
705
            }
706
        }
707
 
708
        if (length <= 7) {
709
            // EAN-8
710
            return 8;
711
        } else {
712
            // EAN-13
713
            return 13;
714
        }
715
    }
716
 
717
    private boolean calculateSymbolSize() {
718
        int i;
719
        final int binary_length = this.binary_string.length();
720
        if (this.cc_mode == CompositeMode.CC_A) {
721
            /* CC-A 2D component - calculate remaining space */
722
            switch (this.cc_width) {
723
            case 2:
724
                if (binary_length > 167) {
725
                    return false;
726
                }
727
                if (binary_length <= 167) {
728
                    this.target_bitsize = 167;
729
                }
730
                if (binary_length <= 138) {
731
                    this.target_bitsize = 138;
732
                }
733
                if (binary_length <= 118) {
734
                    this.target_bitsize = 118;
735
                }
736
                if (binary_length <= 108) {
737
                    this.target_bitsize = 108;
738
                }
739
                if (binary_length <= 88) {
740
                    this.target_bitsize = 88;
741
                }
742
                if (binary_length <= 78) {
743
                    this.target_bitsize = 78;
744
                }
745
                if (binary_length <= 59) {
746
                    this.target_bitsize = 59;
747
                }
748
                break;
749
            case 3:
750
                if (binary_length > 167) {
751
                    return false;
752
                }
753
                if (binary_length <= 167) {
754
                    this.target_bitsize = 167;
755
                }
756
                if (binary_length <= 138) {
757
                    this.target_bitsize = 138;
758
                }
759
                if (binary_length <= 118) {
760
                    this.target_bitsize = 118;
761
                }
762
                if (binary_length <= 98) {
763
                    this.target_bitsize = 98;
764
                }
765
                if (binary_length <= 78) {
766
                    this.target_bitsize = 78;
767
                }
768
                break;
769
            case 4:
770
                if (binary_length > 197) {
771
                    return false;
772
                }
773
                if (binary_length <= 197) {
774
                    this.target_bitsize = 197;
775
                }
776
                if (binary_length <= 167) {
777
                    this.target_bitsize = 167;
778
                }
779
                if (binary_length <= 138) {
780
                    this.target_bitsize = 138;
781
                }
782
                if (binary_length <= 108) {
783
                    this.target_bitsize = 108;
784
                }
785
                if (binary_length <= 78) {
786
                    this.target_bitsize = 78;
787
                }
788
                break;
789
            }
790
        }
791
 
792
        if (this.cc_mode == CompositeMode.CC_B) {
793
            /* CC-B 2D component - calculated from ISO/IEC 24728 Table 1 */
794
            switch (this.cc_width) {
795
            case 2:
796
                if (binary_length > 336) {
797
                    return false;
798
                }
799
                if (binary_length <= 336) {
800
                    this.target_bitsize = 336;
801
                }
802
                if (binary_length <= 296) {
803
                    this.target_bitsize = 296;
804
                }
805
                if (binary_length <= 256) {
806
                    this.target_bitsize = 256;
807
                }
808
                if (binary_length <= 208) {
809
                    this.target_bitsize = 208;
810
                }
811
                if (binary_length <= 160) {
812
                    this.target_bitsize = 160;
813
                }
814
                if (binary_length <= 104) {
815
                    this.target_bitsize = 104;
816
                }
817
                if (binary_length <= 56) {
818
                    this.target_bitsize = 56;
819
                }
820
                break;
821
            case 3:
822
                if (binary_length > 768) {
823
                    return false;
824
                }
825
                if (binary_length <= 768) {
826
                    this.target_bitsize = 768;
827
                }
828
                if (binary_length <= 648) {
829
                    this.target_bitsize = 648;
830
                }
831
                if (binary_length <= 536) {
832
                    this.target_bitsize = 536;
833
                }
834
                if (binary_length <= 416) {
835
                    this.target_bitsize = 416;
836
                }
837
                if (binary_length <= 304) {
838
                    this.target_bitsize = 304;
839
                }
840
                if (binary_length <= 208) {
841
                    this.target_bitsize = 208;
842
                }
843
                if (binary_length <= 152) {
844
                    this.target_bitsize = 152;
845
                }
846
                if (binary_length <= 112) {
847
                    this.target_bitsize = 112;
848
                }
849
                if (binary_length <= 72) {
850
                    this.target_bitsize = 72;
851
                }
852
                if (binary_length <= 32) {
853
                    this.target_bitsize = 32;
854
                }
855
                break;
856
            case 4:
857
                if (binary_length > 1184) {
858
                    return false;
859
                }
860
                if (binary_length <= 1184) {
861
                    this.target_bitsize = 1184;
862
                }
863
                if (binary_length <= 1016) {
864
                    this.target_bitsize = 1016;
865
                }
866
                if (binary_length <= 840) {
867
                    this.target_bitsize = 840;
868
                }
869
                if (binary_length <= 672) {
870
                    this.target_bitsize = 672;
871
                }
872
                if (binary_length <= 496) {
873
                    this.target_bitsize = 496;
874
                }
875
                if (binary_length <= 352) {
876
                    this.target_bitsize = 352;
877
                }
878
                if (binary_length <= 264) {
879
                    this.target_bitsize = 264;
880
                }
881
                if (binary_length <= 208) {
882
                    this.target_bitsize = 208;
883
                }
884
                if (binary_length <= 152) {
885
                    this.target_bitsize = 152;
886
                }
887
                if (binary_length <= 96) {
888
                    this.target_bitsize = 96;
889
                }
890
                if (binary_length <= 56) {
891
                    this.target_bitsize = 56;
892
                }
893
                break;
894
            }
895
        }
896
 
897
        if (this.cc_mode == CompositeMode.CC_C) {
898
            /* CC-C 2D Component is a bit more complex! */
899
            int byte_length, codewords_used, ecc_level, ecc_codewords, rows;
900
            int codewords_total, target_codewords, target_bytesize;
901
 
902
            byte_length = binary_length / 8;
903
            if (binary_length % 8 != 0) {
904
                byte_length++;
905
            }
906
 
907
            codewords_used = byte_length / 6 * 5;
908
            codewords_used += byte_length % 6;
909
 
910
            ecc_level = 7;
911
            if (codewords_used <= 1280) {
912
                ecc_level = 6;
913
            }
914
            if (codewords_used <= 640) {
915
                ecc_level = 5;
916
            }
917
            if (codewords_used <= 320) {
918
                ecc_level = 4;
919
            }
920
            if (codewords_used <= 160) {
921
                ecc_level = 3;
922
            }
923
            if (codewords_used <= 40) {
924
                ecc_level = 2;
925
            }
926
            this.ecc = ecc_level;
927
            ecc_codewords = 1;
928
            for (i = 1; i <= ecc_level + 1; i++) {
929
                ecc_codewords *= 2;
930
            }
931
 
932
            codewords_used += ecc_codewords;
933
            codewords_used += 3;
934
 
935
            if (this.linearWidth == 0) {
936
                /* Linear component not yet calculated */
937
                this.cc_width = (int) (0.5 + Math.sqrt(codewords_used / 3.0));
938
            } else {
939
                this.cc_width = (this.linearWidth - 53) / 17;
940
            }
941
 
942
            if (codewords_used / this.cc_width > 90) {
943
                /* stop the symbol from becoming too high */
944
                this.cc_width = this.cc_width + 1;
945
            }
946
 
947
            rows = codewords_used / this.cc_width;
948
            if (codewords_used % this.cc_width != 0) {
949
                rows++;
950
            }
951
 
952
            while (this.cc_width > 3 * rows) {
953
                /* stop the symbol from becoming too wide (section 10) */
954
                this.cc_width--;
955
 
956
                rows = codewords_used / this.cc_width;
957
                if (codewords_used % this.cc_width != 0) {
958
                    rows++;
959
                }
960
            }
961
 
962
            codewords_total = this.cc_width * rows;
963
 
964
            target_codewords = codewords_total - ecc_codewords;
965
            target_codewords -= 3;
966
 
967
            target_bytesize = 6 * (target_codewords / 5);
968
            target_bytesize += target_codewords % 5;
969
 
970
            this.target_bitsize = 8 * target_bytesize;
971
        }
972
 
973
        this.remainder = this.target_bitsize - binary_length;
974
        return true;
975
    }
976
 
977
    private boolean cc_binary_string() {
978
        /* Handles all data encodation from section 5 of ISO/IEC 24723 */
979
        int encoding_method, read_posn, d1, d2, value, alpha_pad;
980
        int i, j, ai_crop, fnc1_latch;
981
        int group_val;
982
        int ai90_mode;
983
        boolean latch;
984
        int alpha, alphanum, numeric, test1, test2, test3, next_ai_posn;
985
        int numeric_value, table3_letter;
986
        String numeric_part;
987
        String ninety;
988
        int latchOffset;
989
 
990
        encoding_method = 1;
991
        read_posn = 0;
992
        ai_crop = 0;
993
        fnc1_latch = 0;
994
        alpha_pad = 0;
995
        ai90_mode = 0;
996
        this.ecc = 0;
997
        value = 0;
998
        this.target_bitsize = 0;
999
 
1000
        if (this.content.charAt(0) == '1' && (this.content.charAt(1) == '0' || this.content.charAt(1) == '1' || this.content.charAt(1) == '7') && this.content.length() >= 8) {
1001
            /* Source starts (10), (11) or (17) */
1002
            encoding_method = 2;
1003
        }
1004
 
1005
        if (this.content.charAt(0) == '9' && this.content.charAt(1) == '0') {
1006
            /* Source starts (90) */
1007
            encoding_method = 3;
1008
        }
1009
 
1010
        info("Composite Encodation: ");
1011
        switch (encoding_method) {
1012
        case 1:
1013
            infoLine("0");
1014
            break;
1015
        case 2:
1016
            infoLine("10");
1017
            break;
1018
        case 3:
1019
            infoLine("11");
1020
            break;
1021
        }
1022
 
1023
        this.binary_string = "";
1024
 
1025
        if (encoding_method == 1) {
1026
            this.binary_string += "0";
1027
        }
1028
 
1029
        if (encoding_method == 2) {
1030
            /* Encoding Method field "10" - date and lot number */
1031
 
1032
            this.binary_string += "10";
1033
 
1034
            if (this.content.charAt(1) == '0') {
1035
                /* No date data */
1036
                this.binary_string += "11";
1037
                read_posn = 2;
1038
            } else {
1039
                /* Production Date (11) or Expiration Date (17) */
1040
                group_val = (10 * (this.content.charAt(2) - '0') + this.content.charAt(3) - '0') * 384;
1041
                group_val += (10 * (this.content.charAt(4) - '0') + this.content.charAt(5) - '0' - 1) * 32;
1042
                group_val += 10 * (this.content.charAt(6) - '0') + this.content.charAt(7) - '0';
1043
 
1044
                for (j = 0; j < 16; j++) {
1045
                    if ((group_val & 0x8000 >> j) == 0) {
1046
                        this.binary_string += "0";
1047
                    } else {
1048
                        this.binary_string += "1";
1049
                    }
1050
                }
1051
 
1052
                if (this.content.charAt(1) == '1') {
1053
                    /* Production Date AI 11 */
1054
                    this.binary_string += "0";
1055
                } else {
1056
                    /* Expiration Date AI 17 */
1057
                    this.binary_string += "1";
1058
                }
1059
                read_posn = 8;
1060
            }
1061
 
1062
            if (read_posn + 2 < this.content.length()) {
1063
                if (this.content.charAt(read_posn) == '1' && this.content.charAt(read_posn + 1) == '0') {
1064
                    /* Followed by AI 10 - strip this from general field */
1065
                    read_posn += 2;
1066
                } else {
1067
                    /* An FNC1 character needs to be inserted in the general field */
1068
                    fnc1_latch = 1;
1069
                }
1070
            } else {
1071
                fnc1_latch = 1;
1072
            }
1073
        }
1074
 
1075
        if (encoding_method == 3) {
1076
            /* Encodation Method field of "11" - AI 90 */
1077
            /*
1078
             * "This encodation method may be used if an element string with an AI 90 occurs at the
1079
             * start of the data message, and if the data field following the two-digit AI 90 starts
1080
             * with an alphanumeric string which complies with a specific format." (para 5.2.2)
1081
             */
1082
 
1083
            j = this.content.length();
1084
            for (i = this.content.length(); i > 2; i--) {
1085
                if (this.content.charAt(i - 1) == '[') {
1086
                    j = i;
1087
                }
1088
            }
1089
 
1090
            ninety = this.content.substring(2, j - 1);
1091
 
1092
            /* Find out if the AI 90 data is alphabetic or numeric or both */
1093
 
1094
            alpha = 0;
1095
            alphanum = 0;
1096
            numeric = 0;
1097
 
1098
            for (i = 0; i < ninety.length(); i++) {
1099
 
1100
                if (ninety.charAt(i) >= 'A' && ninety.charAt(i) <= 'Z') {
1101
                    /* Character is alphabetic */
1102
                    alpha += 1;
1103
                }
1104
 
1105
                if (ninety.charAt(i) >= '0' && ninety.charAt(i) <= '9') {
1106
                    /* Character is numeric */
1107
                    numeric += 1;
1108
                }
1109
 
1110
                switch (ninety.charAt(i)) {
1111
                case '*':
1112
                case ',':
1113
                case '-':
1114
                case '.':
1115
                case '/':
1116
                    alphanum += 1;
1117
                    break;
1118
                }
1119
 
1120
                if (!(ninety.charAt(i) >= '0' && ninety.charAt(i) <= '9' || ninety.charAt(i) >= 'A' && ninety.charAt(i) <= 'Z')) {
1121
                    if (ninety.charAt(i) != '*' && ninety.charAt(i) != ',' && ninety.charAt(i) != '-' && ninety.charAt(i) != '.' && ninety.charAt(i) != '/') {
1122
                        /* An Invalid AI 90 character */
1123
                        throw new OkapiException("Invalid AI 90 data");
1124
                    }
1125
                }
1126
            }
1127
 
1128
            /* must start with 0, 1, 2 or 3 digits followed by an uppercase character */
1129
            test1 = -1;
1130
            for (i = 3; i >= 0; i--) {
1131
                if (ninety.charAt(i) >= 'A' && ninety.charAt(i) <= 'Z') {
1132
                    test1 = i;
1133
                }
1134
            }
1135
 
1136
            test2 = 0;
1137
            for (i = 0; i < test1; i++) {
1138
                if (!(ninety.charAt(i) >= '0' && ninety.charAt(i) <= '9')) {
1139
                    test2 = 1;
1140
                }
1141
            }
1142
 
1143
            /* leading zeros are not permitted */
1144
            test3 = 0;
1145
            if (test1 >= 1 && ninety.charAt(0) == '0') {
1146
                test3 = 1;
1147
            }
1148
 
1149
            if (test1 != -1 && test2 != 1 && test3 == 0) {
1150
                /* Encodation method "11" can be used */
1151
                this.binary_string += "11";
1152
 
1153
                numeric -= test1;
1154
                alpha--;
1155
 
1156
                /* Decide on numeric, alpha or alphanumeric mode */
1157
                /* Alpha mode is a special mode for AI 90 */
1158
 
1159
                if (alphanum > 0) {
1160
                    /* Alphanumeric mode */
1161
                    this.binary_string += "0";
1162
                    ai90_mode = 1;
1163
                } else {
1164
                    if (alpha > numeric) {
1165
                        /* Alphabetic mode */
1166
                        this.binary_string += "11";
1167
                        ai90_mode = 2;
1168
                    } else {
1169
                        /* Numeric mode */
1170
                        this.binary_string += "10";
1171
                        ai90_mode = 3;
1172
                    }
1173
                }
1174
 
1175
                next_ai_posn = 2 + ninety.length();
1176
 
1177
                if (this.content.charAt(next_ai_posn) == '[') {
1178
                    /* There are more AIs afterwords */
1179
                    if (this.content.charAt(next_ai_posn + 1) == '2' && this.content.charAt(next_ai_posn + 2) == '1') {
1180
                        /* AI 21 follows */
1181
                        ai_crop = 1;
1182
                    }
1183
 
1184
                    if (this.content.charAt(next_ai_posn + 1) == '8' && this.content.charAt(next_ai_posn + 2) == '0' && this.content.charAt(next_ai_posn + 3) == '0'
1185
                            && this.content.charAt(next_ai_posn + 4) == '4') {
1186
                        /* AI 8004 follows */
1187
                        ai_crop = 2;
1188
                    }
1189
                }
1190
 
1191
                switch (ai_crop) {
1192
                case 0:
1193
                    this.binary_string += "0";
1194
                    break;
1195
                case 1:
1196
                    this.binary_string += "10";
1197
                    break;
1198
                case 2:
1199
                    this.binary_string += "11";
1200
                    break;
1201
                }
1202
 
1203
                if (test1 == 0) {
1204
                    numeric_part = "0";
1205
                } else {
1206
                    numeric_part = ninety.substring(0, test1);
1207
                }
1208
 
1209
                numeric_value = 0;
1210
                for (i = 0; i < numeric_part.length(); i++) {
1211
                    numeric_value *= 10;
1212
                    numeric_value += numeric_part.charAt(i) - '0';
1213
                }
1214
 
1215
                table3_letter = -1;
1216
                if (numeric_value < 31) {
1217
                    switch (ninety.charAt(test1)) {
1218
                    case 'B':
1219
                        table3_letter = 0;
1220
                        break;
1221
                    case 'D':
1222
                        table3_letter = 1;
1223
                        break;
1224
                    case 'H':
1225
                        table3_letter = 2;
1226
                        break;
1227
                    case 'I':
1228
                        table3_letter = 3;
1229
                        break;
1230
                    case 'J':
1231
                        table3_letter = 4;
1232
                        break;
1233
                    case 'K':
1234
                        table3_letter = 5;
1235
                        break;
1236
                    case 'L':
1237
                        table3_letter = 6;
1238
                        break;
1239
                    case 'N':
1240
                        table3_letter = 7;
1241
                        break;
1242
                    case 'P':
1243
                        table3_letter = 8;
1244
                        break;
1245
                    case 'Q':
1246
                        table3_letter = 9;
1247
                        break;
1248
                    case 'R':
1249
                        table3_letter = 10;
1250
                        break;
1251
                    case 'S':
1252
                        table3_letter = 11;
1253
                        break;
1254
                    case 'T':
1255
                        table3_letter = 12;
1256
                        break;
1257
                    case 'V':
1258
                        table3_letter = 13;
1259
                        break;
1260
                    case 'W':
1261
                        table3_letter = 14;
1262
                        break;
1263
                    case 'Z':
1264
                        table3_letter = 15;
1265
                        break;
1266
                    }
1267
                }
1268
 
1269
                if (table3_letter != -1) {
1270
                    /* Encoding can be done according to 5.2.2 c) 2) */
1271
                    /* five bit binary string representing value before letter */
1272
                    for (j = 0; j < 5; j++) {
1273
                        if ((numeric_value & 0x10 >> j) == 0x00) {
1274
                            this.binary_string += "0";
1275
                        } else {
1276
                            this.binary_string += "1";
1277
                        }
1278
                    }
1279
 
1280
                    /* followed by four bit representation of letter from Table 3 */
1281
                    for (j = 0; j < 4; j++) {
1282
                        if ((table3_letter & 0x08 >> j) == 0x00) {
1283
                            this.binary_string += "0";
1284
                        } else {
1285
                            this.binary_string += "1";
1286
                        }
1287
                    }
1288
                } else {
1289
                    /* Encoding is done according to 5.2.2 c) 3) */
1290
                    this.binary_string += "11111";
1291
                    /* ten bit representation of number */
1292
                    for (j = 0; j < 10; j++) {
1293
                        if ((numeric_value & 0x200 >> j) == 0x00) {
1294
                            this.binary_string += "0";
1295
                        } else {
1296
                            this.binary_string += "1";
1297
                        }
1298
                    }
1299
 
1300
                    /* five bit representation of ASCII character */
1301
                    for (j = 0; j < 5; j++) {
1302
                        if ((ninety.charAt(test1) - 65 & 0x10 >> j) == 0x00) {
1303
                            this.binary_string += "0";
1304
                        } else {
1305
                            this.binary_string += "1";
1306
                        }
1307
                    }
1308
                }
1309
 
1310
                read_posn = test1 + 3;
1311
            } else {
1312
                /* Use general field encodation instead */
1313
                this.binary_string += "0";
1314
                read_posn = 0;
1315
            }
1316
 
1317
            /* Now encode the rest of the AI 90 data field */
1318
            if (ai90_mode == 2) {
1319
                /* Alpha encodation (section 5.2.3) */
1320
                do {
1321
                    if (this.content.charAt(read_posn) >= '0' && this.content.charAt(read_posn) <= '9') {
1322
                        for (j = 0; j < 5; j++) {
1323
                            if ((this.content.charAt(read_posn) + 4 & 0x10 >> j) == 0x00) {
1324
                                this.binary_string += "0";
1325
                            } else {
1326
                                this.binary_string += "1";
1327
                            }
1328
                        }
1329
                    }
1330
 
1331
                    if (this.content.charAt(read_posn) >= 'A' && this.content.charAt(read_posn) <= 'Z') {
1332
                        for (j = 0; j < 6; j++) {
1333
                            if ((this.content.charAt(read_posn) - 65 & 0x20 >> j) == 0x00) {
1334
                                this.binary_string += "0";
1335
                            } else {
1336
                                this.binary_string += "1";
1337
                            }
1338
                        }
1339
                    }
1340
 
1341
                    if (this.content.charAt(read_posn) == '[') {
1342
                        this.binary_string += "11111";
1343
                    }
1344
 
1345
                    read_posn++;
1346
                } while (this.content.charAt(read_posn - 1) != '[' && read_posn < this.content.length());
1347
                alpha_pad = 1; /* This is overwritten if a general field is encoded */
1348
            }
1349
 
1350
            if (ai90_mode == 1) {
1351
                /* Alphanumeric mode */
1352
                do {
1353
                    if (this.content.charAt(read_posn) >= '0' && this.content.charAt(read_posn) <= '9') {
1354
                        for (j = 0; j < 5; j++) {
1355
                            if ((this.content.charAt(read_posn) - 43 & 0x10 >> j) == 0x00) {
1356
                                this.binary_string += "0";
1357
                            } else {
1358
                                this.binary_string += "1";
1359
                            }
1360
                        }
1361
                    }
1362
 
1363
                    if (this.content.charAt(read_posn) >= 'A' && this.content.charAt(read_posn) <= 'Z') {
1364
                        for (j = 0; j < 6; j++) {
1365
                            if ((this.content.charAt(read_posn) - 33 & 0x20 >> j) == 0x00) {
1366
                                this.binary_string += "0";
1367
                            } else {
1368
                                this.binary_string += "1";
1369
                            }
1370
                        }
1371
                    }
1372
 
1373
                    switch (this.content.charAt(read_posn)) {
1374
                    case '[':
1375
                        this.binary_string += "01111";
1376
                        break;
1377
                    case '*':
1378
                        this.binary_string += "111010";
1379
                        break;
1380
                    case ',':
1381
                        this.binary_string += "111011";
1382
                        break;
1383
                    case '-':
1384
                        this.binary_string += "111100";
1385
                        break;
1386
                    case '.':
1387
                        this.binary_string += "111101";
1388
                        break;
1389
                    case '/':
1390
                        this.binary_string += "111110";
1391
                        break;
1392
                    }
1393
 
1394
                    read_posn++;
1395
                } while (this.content.charAt(read_posn - 1) != '[' && this.content.charAt(read_posn - 1) != '\0');
1396
            }
1397
 
1398
            read_posn += 2 * ai_crop;
1399
        }
1400
 
1401
        /*
1402
         * The compressed data field has been processed if appropriate - the rest of the data (if
1403
         * any) goes into a general-purpose data compaction field
1404
         */
1405
 
1406
        j = 0;
1407
        this.general_field = "";
1408
        if (fnc1_latch == 1) {
1409
            /*
1410
             * Encodation method "10" has been used but it is not followed by AI 10, so a FNC1
1411
             * character needs to be added
1412
             */
1413
            this.general_field += "[";
1414
        }
1415
 
1416
        this.general_field += this.content.substring(read_posn);
1417
 
1418
        latch = false;
1419
        if (this.general_field.length() != 0) {
1420
            alpha_pad = 0;
1421
 
1422
            this.general_field_type = new GeneralFieldMode[this.general_field.length()];
1423
 
1424
            for (i = 0; i < this.general_field.length(); i++) {
1425
                /* Table 13 - ISO/IEC 646 encodation */
1426
                if (this.general_field.charAt(i) < ' ' || this.general_field.charAt(i) > 'z') {
1427
                    this.general_field_type[i] = GeneralFieldMode.INVALID_CHAR;
1428
                    latch = true;
1429
                } else {
1430
                    this.general_field_type[i] = GeneralFieldMode.ISOIEC;
1431
                }
1432
 
1433
                if (this.general_field.charAt(i) == '#') {
1434
                    this.general_field_type[i] = GeneralFieldMode.INVALID_CHAR;
1435
                    latch = true;
1436
                }
1437
                if (this.general_field.charAt(i) == '$') {
1438
                    this.general_field_type[i] = GeneralFieldMode.INVALID_CHAR;
1439
                    latch = true;
1440
                }
1441
                if (this.general_field.charAt(i) == '@') {
1442
                    this.general_field_type[i] = GeneralFieldMode.INVALID_CHAR;
1443
                    latch = true;
1444
                }
1445
                if (this.general_field.charAt(i) == 92) {
1446
                    this.general_field_type[i] = GeneralFieldMode.INVALID_CHAR;
1447
                    latch = true;
1448
                }
1449
                if (this.general_field.charAt(i) == '^') {
1450
                    this.general_field_type[i] = GeneralFieldMode.INVALID_CHAR;
1451
                    latch = true;
1452
                }
1453
                if (this.general_field.charAt(i) == 96) {
1454
                    this.general_field_type[i] = GeneralFieldMode.INVALID_CHAR;
1455
                    latch = true;
1456
                }
1457
 
1458
                /* Table 12 - Alphanumeric encodation */
1459
                if (this.general_field.charAt(i) >= 'A' && this.general_field.charAt(i) <= 'Z') {
1460
                    this.general_field_type[i] = GeneralFieldMode.ALPHA_OR_ISO;
1461
                }
1462
                if (this.general_field.charAt(i) == '*') {
1463
                    this.general_field_type[i] = GeneralFieldMode.ALPHA_OR_ISO;
1464
                }
1465
                if (this.general_field.charAt(i) == ',') {
1466
                    this.general_field_type[i] = GeneralFieldMode.ALPHA_OR_ISO;
1467
                }
1468
                if (this.general_field.charAt(i) == '-') {
1469
                    this.general_field_type[i] = GeneralFieldMode.ALPHA_OR_ISO;
1470
                }
1471
                if (this.general_field.charAt(i) == '.') {
1472
                    this.general_field_type[i] = GeneralFieldMode.ALPHA_OR_ISO;
1473
                }
1474
                if (this.general_field.charAt(i) == '/') {
1475
                    this.general_field_type[i] = GeneralFieldMode.ALPHA_OR_ISO;
1476
                }
1477
 
1478
                /* Numeric encodation */
1479
                if (this.general_field.charAt(i) >= '0' && this.general_field.charAt(i) <= '9') {
1480
                    this.general_field_type[i] = GeneralFieldMode.ANY_ENC;
1481
                }
1482
                if (this.general_field.charAt(i) == '[') {
1483
                    /* FNC1 can be encoded in any system */
1484
                    this.general_field_type[i] = GeneralFieldMode.ANY_ENC;
1485
                }
1486
 
1487
            }
1488
 
1489
            if (latch) {
1490
                /* Invalid characters in input data */
1491
                throw new OkapiException("Invalid characters in input data");
1492
            }
1493
 
1494
            for (i = 0; i < this.general_field.length() - 1; i++) {
1495
                if (this.general_field_type[i] == GeneralFieldMode.ISOIEC && this.general_field.charAt(i + 1) == '[') {
1496
                    this.general_field_type[i + 1] = GeneralFieldMode.ISOIEC;
1497
                }
1498
            }
1499
 
1500
            for (i = 0; i < this.general_field.length() - 1; i++) {
1501
                if (this.general_field_type[i] == GeneralFieldMode.ALPHA_OR_ISO && this.general_field.charAt(i + 1) == '[') {
1502
                    this.general_field_type[i + 1] = GeneralFieldMode.ALPHA_OR_ISO;
1503
                }
1504
            }
1505
 
1506
            latch = applyGeneralFieldRules();
1507
 
1508
            i = 0;
1509
            do {
1510
                switch (this.general_field_type[i]) {
1511
                case NUMERIC:
1512
                    if (i != 0) {
1513
                        if (this.general_field_type[i - 1] != GeneralFieldMode.NUMERIC && this.general_field.charAt(i - 1) != '[') {
1514
                            this.binary_string += "000"; /* Numeric latch */
1515
                        }
1516
                    }
1517
 
1518
                    if (this.general_field.charAt(i) != '[') {
1519
                        d1 = this.general_field.charAt(i) - '0';
1520
                    } else {
1521
                        d1 = 10;
1522
                    }
1523
 
1524
                    if (i < this.general_field.length() - 1) {
1525
                        if (this.general_field.charAt(i + 1) != '[') {
1526
                            d2 = this.general_field.charAt(i + 1) - '0';
1527
                        } else {
1528
                            d2 = 10;
1529
                        }
1530
                    } else {
1531
                        d2 = 10;
1532
                    }
1533
 
1534
                    if (d1 != 10 || d2 != 10) {
1535
                        /* If (d1==10)&&(d2==10) then input is either FNC1,FNC1 or FNC1,EOL */
1536
                        value = 11 * d1 + d2 + 8;
1537
 
1538
                        for (j = 0; j < 7; j++) {
1539
                            if ((value & 0x40 >> j) == 0x00) {
1540
                                this.binary_string += "0";
1541
                            } else {
1542
                                this.binary_string += "1";
1543
                            }
1544
                        }
1545
 
1546
                        i += 2;
1547
                    }
1548
                    break;
1549
 
1550
                case ALPHA:
1551
                    if (i != 0) {
1552
                        if (this.general_field_type[i - 1] == GeneralFieldMode.NUMERIC || this.general_field.charAt(i - 1) == '[') {
1553
                            this.binary_string += "0000"; /* Alphanumeric latch */
1554
                        }
1555
                        if (this.general_field_type[i - 1] == GeneralFieldMode.ISOIEC) {
1556
                            this.binary_string += "00100"; /* ISO/IEC 646 latch */
1557
                        }
1558
                    }
1559
 
1560
                    if (this.general_field.charAt(i) >= '0' && this.general_field.charAt(i) <= '9') {
1561
 
1562
                        value = this.general_field.charAt(i) - 43;
1563
 
1564
                        for (j = 0; j < 5; j++) {
1565
                            if ((value & 0x10 >> j) == 0x00) {
1566
                                this.binary_string += "0";
1567
                            } else {
1568
                                this.binary_string += "1";
1569
                            }
1570
                        }
1571
                    }
1572
 
1573
                    if (this.general_field.charAt(i) >= 'A' && this.general_field.charAt(i) <= 'Z') {
1574
 
1575
                        value = this.general_field.charAt(i) - 33;
1576
 
1577
                        for (j = 0; j < 6; j++) {
1578
                            if ((value & 0x20 >> j) == 0x00) {
1579
                                this.binary_string += "0";
1580
                            } else {
1581
                                this.binary_string += "1";
1582
                            }
1583
                        }
1584
                    }
1585
 
1586
                    if (this.general_field.charAt(i) == '[') {
1587
                        this.binary_string += "01111"; /* FNC1/Numeric latch */
1588
                    }
1589
                    if (this.general_field.charAt(i) == '*') {
1590
                        this.binary_string += "111010"; /* asterisk */
1591
                    }
1592
                    if (this.general_field.charAt(i) == ',') {
1593
                        this.binary_string += "111011"; /* comma */
1594
                    }
1595
                    if (this.general_field.charAt(i) == '-') {
1596
                        this.binary_string += "111100"; /* minus or hyphen */
1597
                    }
1598
                    if (this.general_field.charAt(i) == '.') {
1599
                        this.binary_string += "111101"; /* period or full stop */
1600
                    }
1601
                    if (this.general_field.charAt(i) == '/') {
1602
                        this.binary_string += "111110"; /* slash or solidus */
1603
                    }
1604
 
1605
                    i++;
1606
                    break;
1607
 
1608
                case ISOIEC:
1609
                    if (i != 0) {
1610
                        if (this.general_field_type[i - 1] == GeneralFieldMode.NUMERIC || this.general_field.charAt(i - 1) == '[') {
1611
                            this.binary_string += "0000"; /* Alphanumeric latch */
1612
                            this.binary_string += "00100"; /* ISO/IEC 646 latch */
1613
                        }
1614
                        if (this.general_field_type[i - 1] == GeneralFieldMode.ALPHA) {
1615
                            this.binary_string += "00100"; /* ISO/IEC 646 latch */
1616
                        }
1617
                    }
1618
 
1619
                    if (this.general_field.charAt(i) >= '0' && this.general_field.charAt(i) <= '9') {
1620
 
1621
                        value = this.general_field.charAt(i) - 43;
1622
 
1623
                        for (j = 0; j < 5; j++) {
1624
                            if ((value & 0x10 >> j) == 0x00) {
1625
                                this.binary_string += "0";
1626
                            } else {
1627
                                this.binary_string += "1";
1628
                            }
1629
                        }
1630
                    }
1631
 
1632
                    if (this.general_field.charAt(i) >= 'A' && this.general_field.charAt(i) <= 'Z') {
1633
 
1634
                        value = this.general_field.charAt(i) - 1;
1635
 
1636
                        for (j = 0; j < 7; j++) {
1637
                            if ((value & 0x40 >> j) == 0x00) {
1638
                                this.binary_string += "0";
1639
                            } else {
1640
                                this.binary_string += "1";
1641
                            }
1642
                        }
1643
                    }
1644
 
1645
                    if (this.general_field.charAt(i) >= 'a' && this.general_field.charAt(i) <= 'z') {
1646
 
1647
                        value = this.general_field.charAt(i) - 7;
1648
 
1649
                        for (j = 0; j < 7; j++) {
1650
                            if ((value & 0x40 >> j) == 0x00) {
1651
                                this.binary_string += "0";
1652
                            } else {
1653
                                this.binary_string += "1";
1654
                            }
1655
                        }
1656
                    }
1657
 
1658
                    if (this.general_field.charAt(i) == '[') {
1659
                        this.binary_string += "01111"; /* FNC1/Numeric latch */
1660
                    }
1661
                    if (this.general_field.charAt(i) == '!') {
1662
                        this.binary_string += "11101000"; /* exclamation mark */
1663
                    }
1664
                    if (this.general_field.charAt(i) == 34) {
1665
                        this.binary_string += "11101001"; /* quotation mark */
1666
                    }
1667
                    if (this.general_field.charAt(i) == 37) {
1668
                        this.binary_string += "11101010"; /* percent sign */
1669
                    }
1670
                    if (this.general_field.charAt(i) == '&') {
1671
                        this.binary_string += "11101011"; /* ampersand */
1672
                    }
1673
                    if (this.general_field.charAt(i) == 39) {
1674
                        this.binary_string += "11101100"; /* apostrophe */
1675
                    }
1676
                    if (this.general_field.charAt(i) == '(') {
1677
                        this.binary_string += "11101101"; /* left parenthesis */
1678
                    }
1679
                    if (this.general_field.charAt(i) == ')') {
1680
                        this.binary_string += "11101110"; /* right parenthesis */
1681
                    }
1682
                    if (this.general_field.charAt(i) == '*') {
1683
                        this.binary_string += "11101111"; /* asterisk */
1684
                    }
1685
                    if (this.general_field.charAt(i) == '+') {
1686
                        this.binary_string += "11110000"; /* plus sign */
1687
                    }
1688
                    if (this.general_field.charAt(i) == ',') {
1689
                        this.binary_string += "11110001"; /* comma */
1690
                    }
1691
                    if (this.general_field.charAt(i) == '-') {
1692
                        this.binary_string += "11110010"; /* minus or hyphen */
1693
                    }
1694
                    if (this.general_field.charAt(i) == '.') {
1695
                        this.binary_string += "11110011"; /* period or full stop */
1696
                    }
1697
                    if (this.general_field.charAt(i) == '/') {
1698
                        this.binary_string += "11110100"; /* slash or solidus */
1699
                    }
1700
                    if (this.general_field.charAt(i) == ':') {
1701
                        this.binary_string += "11110101"; /* colon */
1702
                    }
1703
                    if (this.general_field.charAt(i) == ';') {
1704
                        this.binary_string += "11110110"; /* semicolon */
1705
                    }
1706
                    if (this.general_field.charAt(i) == '<') {
1707
                        this.binary_string += "11110111"; /* less-than sign */
1708
                    }
1709
                    if (this.general_field.charAt(i) == '=') {
1710
                        this.binary_string += "11111000"; /* equals sign */
1711
                    }
1712
                    if (this.general_field.charAt(i) == '>') {
1713
                        this.binary_string += "11111001"; /* greater-than sign */
1714
                    }
1715
                    if (this.general_field.charAt(i) == '?') {
1716
                        this.binary_string += "11111010"; /* question mark */
1717
                    }
1718
                    if (this.general_field.charAt(i) == '_') {
1719
                        this.binary_string += "11111011"; /* underline or low line */
1720
                    }
1721
                    if (this.general_field.charAt(i) == ' ') {
1722
                        this.binary_string += "11111100"; /* space */
1723
                    }
1724
 
1725
                    i++;
1726
                    break;
1727
                }
1728
 
1729
                latchOffset = 0;
1730
                if (latch) {
1731
                    latchOffset = 1;
1732
                }
1733
            } while (i + latchOffset < this.general_field.length());
1734
        }
1735
 
1736
        if (!calculateSymbolSize()) {
1737
            return false;
1738
        }
1739
 
1740
        if (latch) {
1741
            i = this.general_field.length() - 1;
1742
            /* There is still one more numeric digit to encode */
1743
 
1744
            if (this.general_field.charAt(i) == '[') {
1745
                this.binary_string += "000001111";
1746
            } else {
1747
                if (this.remainder >= 4 && this.remainder <= 6) {
1748
                    d1 = this.general_field.charAt(i) - '0';
1749
                    d1++;
1750
 
1751
                    for (j = 0; j < 4; j++) {
1752
                        if ((value & 0x08 >> j) == 0x00) {
1753
                            this.binary_string += "0";
1754
                        } else {
1755
                            this.binary_string += "1";
1756
                        }
1757
                    }
1758
                } else {
1759
                    d1 = this.general_field.charAt(i) - '0';
1760
                    d2 = 10;
1761
 
1762
                    value = 11 * d1 + d2 + 8;
1763
 
1764
                    for (j = 0; j < 7; j++) {
1765
                        if ((value & 0x40 >> j) == 0x00) {
1766
                            this.binary_string += "0";
1767
                        } else {
1768
                            this.binary_string += "1";
1769
                        }
1770
                    }
1771
                    /* This may push the symbol up to the next size */
1772
                }
1773
            }
1774
        }
1775
 
1776
        if (this.binary_string.length() > 11805) { /* (2361 * 5) */
1777
            throw new OkapiException("Input too long");
1778
        }
1779
 
1780
        /* size of the symbol may have changed when adding data in the above sequence */
1781
        if (!calculateSymbolSize()) {
1782
            return false;
1783
        }
1784
 
1785
        infoLine("Composite Binary Length: " + this.binary_string.length());
1786
        displayBinaryString();
1787
 
1788
        if (this.binary_string.length() < this.target_bitsize) {
1789
            /* Now add padding to binary string */
1790
            if (alpha_pad == 1) {
1791
                this.binary_string += "11111";
1792
                alpha_pad = 0;
1793
                /* Extra FNC1 character required after Alpha encodation (section 5.2.3) */
1794
            }
1795
 
1796
            if (this.general_field.length() != 0 && this.general_field_type[this.general_field.length() - 1] == GeneralFieldMode.NUMERIC) {
1797
                this.binary_string += "0000";
1798
            }
1799
 
1800
            while (this.binary_string.length() < this.target_bitsize) {
1801
                this.binary_string += "00100";
1802
            }
1803
 
1804
            this.binary_string = this.binary_string.substring(0, this.target_bitsize);
1805
        }
1806
 
1807
        return true;
1808
    }
1809
 
1810
    private void displayBinaryString() {
1811
        int i, nibble;
1812
        /* Display binary string as hexadecimal */
1813
 
1814
        info("Composite Binary String: ");
1815
        nibble = 0;
1816
        for (i = 0; i < this.binary_string.length(); i++) {
1817
            switch (i % 4) {
1818
            case 0:
1819
                if (this.binary_string.charAt(i) == '1') {
1820
                    nibble += 8;
1821
                }
1822
                break;
1823
            case 1:
1824
                if (this.binary_string.charAt(i) == '1') {
1825
                    nibble += 4;
1826
                }
1827
                break;
1828
            case 2:
1829
                if (this.binary_string.charAt(i) == '1') {
1830
                    nibble += 2;
1831
                }
1832
                break;
1833
            case 3:
1834
                if (this.binary_string.charAt(i) == '1') {
1835
                    nibble += 1;
1836
                }
1837
                info(Integer.toHexString(nibble));
1838
                nibble = 0;
1839
                break;
1840
            }
1841
        }
1842
 
1843
        if (this.binary_string.length() % 4 != 0) {
1844
            info(Integer.toHexString(nibble));
1845
        }
1846
        infoLine();
1847
    }
1848
 
1849
    private boolean applyGeneralFieldRules() {
1850
        /*
1851
         * Attempts to apply encoding rules from secions 7.2.5.5.1 to 7.2.5.5.3 of ISO/IEC
1852
         * 24724:2006
1853
         */
1854
 
1855
        int block_count, i, j, k;
1856
        GeneralFieldMode current, next, last;
1857
        final int[] blockLength = new int[200];
1858
        final GeneralFieldMode[] blockType = new GeneralFieldMode[200];
1859
 
1860
        block_count = 0;
1861
 
1862
        blockLength[block_count] = 1;
1863
        blockType[block_count] = this.general_field_type[0];
1864
 
1865
        for (i = 1; i < this.general_field.length(); i++) {
1866
            current = this.general_field_type[i];
1867
            last = this.general_field_type[i - 1];
1868
 
1869
            if (current == last) {
1870
                blockLength[block_count] = blockLength[block_count] + 1;
1871
            } else {
1872
                block_count++;
1873
                blockLength[block_count] = 1;
1874
                blockType[block_count] = this.general_field_type[i];
1875
            }
1876
        }
1877
 
1878
        block_count++;
1879
 
1880
        for (i = 0; i < block_count; i++) {
1881
            current = blockType[i];
1882
            next = blockType[i + 1];
1883
 
1884
            if (current == GeneralFieldMode.ISOIEC && i != block_count - 1) {
1885
                if (next == GeneralFieldMode.ANY_ENC && blockLength[i + 1] >= 4) {
1886
                    blockType[i + 1] = GeneralFieldMode.NUMERIC;
1887
                }
1888
                if (next == GeneralFieldMode.ANY_ENC && blockLength[i + 1] < 4) {
1889
                    blockType[i + 1] = GeneralFieldMode.ISOIEC;
1890
                }
1891
                if (next == GeneralFieldMode.ALPHA_OR_ISO && blockLength[i + 1] >= 5) {
1892
                    blockType[i + 1] = GeneralFieldMode.ALPHA;
1893
                }
1894
                if (next == GeneralFieldMode.ALPHA_OR_ISO && blockLength[i + 1] < 5) {
1895
                    blockType[i + 1] = GeneralFieldMode.ISOIEC;
1896
                }
1897
            }
1898
 
1899
            if (current == GeneralFieldMode.ALPHA_OR_ISO) {
1900
                blockType[i] = GeneralFieldMode.ALPHA;
1901
            }
1902
 
1903
            if (current == GeneralFieldMode.ALPHA && i != block_count - 1) {
1904
                if (next == GeneralFieldMode.ANY_ENC && blockLength[i + 1] >= 6) {
1905
                    blockType[i + 1] = GeneralFieldMode.NUMERIC;
1906
                }
1907
                if (next == GeneralFieldMode.ANY_ENC && blockLength[i + 1] < 6) {
1908
                    if (i == block_count - 2 && blockLength[i + 1] >= 4) {
1909
                        blockType[i + 1] = GeneralFieldMode.NUMERIC;
1910
                    } else {
1911
                        blockType[i + 1] = GeneralFieldMode.ALPHA;
1912
                    }
1913
                }
1914
            }
1915
 
1916
            if (current == GeneralFieldMode.ANY_ENC) {
1917
                blockType[i] = GeneralFieldMode.NUMERIC;
1918
            }
1919
        }
1920
 
1921
        if (block_count > 1) {
1922
            i = 1;
1923
            while (i < block_count) {
1924
                if (blockType[i - 1] == blockType[i]) {
1925
                    /* bring together */
1926
                    blockLength[i - 1] = blockLength[i - 1] + blockLength[i];
1927
                    j = i + 1;
1928
 
1929
                    /* decreace the list */
1930
                    while (j < block_count) {
1931
                        blockLength[j - 1] = blockLength[j];
1932
                        blockType[j - 1] = blockType[j];
1933
                        j++;
1934
                    }
1935
                    block_count--;
1936
                    i--;
1937
                }
1938
                i++;
1939
            }
1940
        }
1941
 
1942
        for (i = 0; i < block_count - 1; i++) {
1943
            if (blockType[i] == GeneralFieldMode.NUMERIC && (blockLength[i] & 1) != 0) {
1944
                /* Odd size numeric block */
1945
                blockLength[i] = blockLength[i] - 1;
1946
                blockLength[i + 1] = blockLength[i + 1] + 1;
1947
            }
1948
        }
1949
 
1950
        j = 0;
1951
        for (i = 0; i < block_count; i++) {
1952
            for (k = 0; k < blockLength[i]; k++) {
1953
                this.general_field_type[j] = blockType[i];
1954
                j++;
1955
            }
1956
        }
1957
 
1958
        if (blockType[block_count - 1] == GeneralFieldMode.NUMERIC && (blockLength[block_count - 1] & 1) != 0) {
1959
            /*
1960
             * If the last block is numeric and an odd size, further processing needs to be done
1961
             * outside this procedure
1962
             */
1963
            return true;
1964
        } else {
1965
            return false;
1966
        }
1967
    }
1968
 
1969
    private void cc_a() {
1970
        /* CC-A 2D component */
1971
        int i, strpos, segment, cwCnt, variant, rows;
1972
        int k, offset, j, total;
1973
        final int[] rsCodeWords = new int[8];
1974
        int LeftRAPStart, RightRAPStart, CentreRAPStart, StartCluster;
1975
        int LeftRAP, RightRAP, CentreRAP, Cluster;
1976
        final int[] dummy = new int[5];
1977
        int flip, loop;
1978
        String codebarre;
1979
        final StringBuilder bin = new StringBuilder();
1980
        String local_source; /* A copy of source but with padding zeroes to make 208 bits */
1981
 
1982
        variant = 0;
1983
 
1984
        for (i = 0; i < 13; i++) {
1985
            this.bitStr[i] = 0;
1986
        }
1987
        for (i = 0; i < 28; i++) {
1988
            this.codeWords[i] = 0;
1989
        }
1990
 
1991
        local_source = this.binary_string;
1992
        for (i = this.binary_string.length(); i < 208; i++) {
1993
            local_source += "0";
1994
        }
1995
 
1996
        for (segment = 0; segment < 13; segment++) {
1997
            strpos = segment * 16;
1998
            this.bitStr[segment] = 0;
1999
            for (i = 0; i < 16; i++) {
2000
                if (local_source.charAt(strpos + i) == '1') {
2001
                    this.bitStr[segment] += 0x8000 >> i;
2002
                }
2003
            }
2004
        }
2005
 
2006
        init928();
2007
        /* encode codeWords from bitStr */
2008
        cwCnt = encode928(this.binary_string.length());
2009
 
2010
        switch (this.cc_width) {
2011
        case 2:
2012
            switch (cwCnt) {
2013
            case 6:
2014
                variant = 0;
2015
                break;
2016
            case 8:
2017
                variant = 1;
2018
                break;
2019
            case 9:
2020
                variant = 2;
2021
                break;
2022
            case 11:
2023
                variant = 3;
2024
                break;
2025
            case 12:
2026
                variant = 4;
2027
                break;
2028
            case 14:
2029
                variant = 5;
2030
                break;
2031
            case 17:
2032
                variant = 6;
2033
                break;
2034
            }
2035
            break;
2036
        case 3:
2037
            switch (cwCnt) {
2038
            case 8:
2039
                variant = 7;
2040
                break;
2041
            case 10:
2042
                variant = 8;
2043
                break;
2044
            case 12:
2045
                variant = 9;
2046
                break;
2047
            case 14:
2048
                variant = 10;
2049
                break;
2050
            case 17:
2051
                variant = 11;
2052
                break;
2053
            }
2054
            break;
2055
        case 4:
2056
            switch (cwCnt) {
2057
            case 8:
2058
                variant = 12;
2059
                break;
2060
            case 11:
2061
                variant = 13;
2062
                break;
2063
            case 14:
2064
                variant = 14;
2065
                break;
2066
            case 17:
2067
                variant = 15;
2068
                break;
2069
            case 20:
2070
                variant = 16;
2071
                break;
2072
            }
2073
            break;
2074
        }
2075
 
2076
        rows = CCA_VARIANTS[variant];
2077
        k = CCA_VARIANTS[17 + variant];
2078
        offset = CCA_VARIANTS[34 + variant];
2079
 
2080
        /* Reed-Solomon error correction */
2081
 
2082
        for (i = 0; i < 8; i++) {
2083
            rsCodeWords[i] = 0;
2084
        }
2085
        total = 0;
2086
        info("Composite Codewords: ");
2087
        for (i = 0; i < cwCnt; i++) {
2088
            total = (this.codeWords[i] + rsCodeWords[k - 1]) % 929;
2089
            for (j = k - 1; j >= 0; j--) {
2090
                if (j == 0) {
2091
                    rsCodeWords[j] = (929 - total * CCA_COEFFS[offset + j] % 929) % 929;
2092
                } else {
2093
                    rsCodeWords[j] = (rsCodeWords[j - 1] + 929 - total * CCA_COEFFS[offset + j] % 929) % 929;
2094
                }
2095
            }
2096
            infoSpace(this.codeWords[i]);
2097
        }
2098
        infoLine();
2099
 
2100
        for (j = 0; j < k; j++) {
2101
            if (rsCodeWords[j] != 0) {
2102
                rsCodeWords[j] = 929 - rsCodeWords[j];
2103
            }
2104
        }
2105
 
2106
        for (i = k - 1; i >= 0; i--) {
2107
            this.codeWords[cwCnt] = rsCodeWords[i];
2108
            cwCnt++;
2109
        }
2110
 
2111
        /* Place data into table */
2112
        LeftRAPStart = A_RAP_TABLE[variant];
2113
        CentreRAPStart = A_RAP_TABLE[variant + 17];
2114
        RightRAPStart = A_RAP_TABLE[variant + 34];
2115
        StartCluster = A_RAP_TABLE[variant + 51] / 3;
2116
 
2117
        LeftRAP = LeftRAPStart;
2118
        CentreRAP = CentreRAPStart;
2119
        RightRAP = RightRAPStart;
2120
        Cluster = StartCluster; /*
2121
                                 * Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and
2122
                                 * Cluster(6)
2123
                                 */
2124
 
2125
        this.readable = "";
2126
        this.row_count = rows;
2127
        this.pattern = new String[this.row_count];
2128
        this.row_height = new int[this.row_count];
2129
 
2130
        for (i = 0; i < rows; i++) {
2131
            codebarre = "";
2132
            offset = 929 * Cluster;
2133
            for (j = 0; j < 5; j++) {
2134
                dummy[j] = 0;
2135
            }
2136
            for (j = 0; j < this.cc_width; j++) {
2137
                dummy[j + 1] = this.codeWords[i * this.cc_width + j];
2138
            }
2139
            /* Copy the data into codebarre */
2140
            codebarre += RAPLR[LeftRAP];
2141
            codebarre += "1";
2142
            codebarre += CODAGEMC[offset + dummy[1]];
2143
            codebarre += "1";
2144
            if (this.cc_width == 3) {
2145
                codebarre += RAPC[CentreRAP];
2146
            }
2147
            if (this.cc_width >= 2) {
2148
                codebarre += "1";
2149
                codebarre += CODAGEMC[offset + dummy[2]];
2150
                codebarre += "1";
2151
            }
2152
            if (this.cc_width == 4) {
2153
                codebarre += RAPC[CentreRAP];
2154
            }
2155
            if (this.cc_width >= 3) {
2156
                codebarre += "1";
2157
                codebarre += CODAGEMC[offset + dummy[3]];
2158
                codebarre += "1";
2159
            }
2160
            if (this.cc_width == 4) {
2161
                codebarre += "1";
2162
                codebarre += CODAGEMC[offset + dummy[4]];
2163
                codebarre += "1";
2164
            }
2165
            codebarre += RAPLR[RightRAP];
2166
            codebarre += "1"; /* stop */
2167
 
2168
            /* Now codebarre is a mixture of letters and numbers */
2169
 
2170
            flip = 1;
2171
            bin.setLength(0);
2172
            for (loop = 0; loop < codebarre.length(); loop++) {
2173
                if (codebarre.charAt(loop) >= '0' && codebarre.charAt(loop) <= '9') {
2174
                    for (k = 0; k < codebarre.charAt(loop) - '0'; k++) {
2175
                        if (flip == 0) {
2176
                            bin.append('0');
2177
                        } else {
2178
                            bin.append('1');
2179
                        }
2180
                    }
2181
                    if (flip == 0) {
2182
                        flip = 1;
2183
                    } else {
2184
                        flip = 0;
2185
                    }
2186
                } else {
2187
                    bin.append(PDF_TTF[positionOf(codebarre.charAt(loop), BR_SET)]);
2188
                }
2189
            }
2190
 
2191
            this.row_height[i] = 2;
2192
            this.pattern[i] = bin2pat(bin);
2193
 
2194
            /* Set up RAPs and Cluster for next row */
2195
            LeftRAP++;
2196
            CentreRAP++;
2197
            RightRAP++;
2198
            Cluster++;
2199
 
2200
            if (LeftRAP == 53) {
2201
                LeftRAP = 1;
2202
            }
2203
            if (CentreRAP == 53) {
2204
                CentreRAP = 1;
2205
            }
2206
            if (RightRAP == 53) {
2207
                RightRAP = 1;
2208
            }
2209
            if (Cluster == 3) {
2210
                Cluster = 0;
2211
            }
2212
        }
2213
    }
2214
 
2215
    /* initialize pwr928 encoding table */
2216
    private void init928() {
2217
        int i, j, v;
2218
        final int[] cw = new int[7];
2219
        cw[6] = 1;
2220
        for (i = 5; i >= 0; i--) {
2221
            cw[i] = 0;
2222
        }
2223
 
2224
        for (i = 0; i < 7; i++) {
2225
            this.pwr928[0][i] = cw[i];
2226
        }
2227
        for (j = 1; j < 69; j++) {
2228
            for (v = 0, i = 6; i >= 1; i--) {
2229
                v = 2 * cw[i] + v / 928;
2230
                this.pwr928[j][i] = cw[i] = v % 928;
2231
            }
2232
            this.pwr928[j][0] = cw[0] = 2 * cw[0] + v / 928;
2233
        }
2234
    }
2235
 
2236
    /* converts bit string to base 928 values, codeWords[0] is highest order */
2237
    private int encode928(final int bitLng) {
2238
        int i, j, b, bitCnt, cwNdx, cwCnt, cwLng;
2239
        for (cwNdx = cwLng = b = 0; b < bitLng; b += 69, cwNdx += 7) {
2240
            bitCnt = min(bitLng - b, 69);
2241
            cwLng += cwCnt = bitCnt / 10 + 1;
2242
            for (i = 0; i < cwCnt; i++) {
2243
                this.codeWords[cwNdx + i] = 0; /* init 0 */
2244
            }
2245
            for (i = 0; i < bitCnt; i++) {
2246
                if (getBit(b + bitCnt - i - 1)) {
2247
                    for (j = 0; j < cwCnt; j++) {
2248
                        this.codeWords[cwNdx + j] += this.pwr928[i][j + 7 - cwCnt];
2249
                    }
2250
                }
2251
            }
2252
            for (i = cwCnt - 1; i > 0; i--) {
2253
                /* add "carries" */
2254
                this.codeWords[cwNdx + i - 1] += this.codeWords[cwNdx + i] / 928;
2255
                this.codeWords[cwNdx + i] %= 928;
2256
            }
2257
        }
2258
        return cwLng;
2259
    }
2260
 
2261
    private int min(final int first, final int second) {
2262
        if (first <= second) {
2263
            return first;
2264
        } else {
2265
            return second;
2266
        }
2267
    }
2268
 
2269
    /* gets bit in bitString at bitPos */
2270
    private boolean getBit(final int arg) {
2271
        if ((this.bitStr[arg >> 4] & 0x8000 >> (arg & 15)) != 0) {
2272
            return true;
2273
        } else {
2274
            return false;
2275
        }
2276
    }
2277
 
2278
    private void cc_b() {
2279
        /* CC-B 2D component */
2280
        int length, i, binloc;
2281
        int k, j, longueur, offset;
2282
        final int[] mccorrection = new int[50];
2283
        int total;
2284
        final int[] dummy = new int[5];
2285
        String codebarre;
2286
        final StringBuilder bin = new StringBuilder();
2287
        int variant, LeftRAPStart, CentreRAPStart, RightRAPStart, StartCluster;
2288
        int LeftRAP, CentreRAP, RightRAP, Cluster, flip, loop;
2289
        int option_2, rows;
2290
        this.inputData = new int[this.binary_string.length() / 8 + 3];
2291
 
2292
        length = this.binary_string.length() / 8;
2293
 
2294
        for (i = 0; i < length; i++) {
2295
            binloc = i * 8;
2296
 
2297
            this.inputData[i] = 0;
2298
            for (j = 0; j < 8; j++) {
2299
                if (this.binary_string.charAt(binloc + j) == '1') {
2300
                    this.inputData[i] += 0x80 >> j;
2301
                }
2302
            }
2303
        }
2304
 
2305
        this.codeWordCount = 0;
2306
 
2307
        /*
2308
         * "the CC-B component shall have codeword 920 in the first symbol character position"
2309
         * (section 9a)
2310
         */
2311
        this.codeWords[this.codeWordCount] = 920;
2312
        this.codeWordCount++;
2313
 
2314
        byteprocess(0, length);
2315
 
2316
        /* Now figure out which variant of the symbol to use and load values accordingly */
2317
 
2318
        variant = 0;
2319
 
2320
        if (this.cc_width == 2) {
2321
            variant = 13;
2322
            if (this.codeWordCount <= 33) {
2323
                variant = 12;
2324
            }
2325
            if (this.codeWordCount <= 29) {
2326
                variant = 11;
2327
            }
2328
            if (this.codeWordCount <= 24) {
2329
                variant = 10;
2330
            }
2331
            if (this.codeWordCount <= 19) {
2332
                variant = 9;
2333
            }
2334
            if (this.codeWordCount <= 13) {
2335
                variant = 8;
2336
            }
2337
            if (this.codeWordCount <= 8) {
2338
                variant = 7;
2339
            }
2340
        }
2341
 
2342
        if (this.cc_width == 3) {
2343
            variant = 23;
2344
            if (this.codeWordCount <= 70) {
2345
                variant = 22;
2346
            }
2347
            if (this.codeWordCount <= 58) {
2348
                variant = 21;
2349
            }
2350
            if (this.codeWordCount <= 46) {
2351
                variant = 20;
2352
            }
2353
            if (this.codeWordCount <= 34) {
2354
                variant = 19;
2355
            }
2356
            if (this.codeWordCount <= 24) {
2357
                variant = 18;
2358
            }
2359
            if (this.codeWordCount <= 18) {
2360
                variant = 17;
2361
            }
2362
            if (this.codeWordCount <= 14) {
2363
                variant = 16;
2364
            }
2365
            if (this.codeWordCount <= 10) {
2366
                variant = 15;
2367
            }
2368
            if (this.codeWordCount <= 6) {
2369
                variant = 14;
2370
            }
2371
        }
2372
 
2373
        if (this.cc_width == 4) {
2374
            variant = 34;
2375
            if (this.codeWordCount <= 108) {
2376
                variant = 33;
2377
            }
2378
            if (this.codeWordCount <= 90) {
2379
                variant = 32;
2380
            }
2381
            if (this.codeWordCount <= 72) {
2382
                variant = 31;
2383
            }
2384
            if (this.codeWordCount <= 54) {
2385
                variant = 30;
2386
            }
2387
            if (this.codeWordCount <= 39) {
2388
                variant = 29;
2389
            }
2390
            if (this.codeWordCount <= 30) {
2391
                variant = 28;
2392
            }
2393
            if (this.codeWordCount <= 24) {
2394
                variant = 27;
2395
            }
2396
            if (this.codeWordCount <= 18) {
2397
                variant = 26;
2398
            }
2399
            if (this.codeWordCount <= 12) {
2400
                variant = 25;
2401
            }
2402
            if (this.codeWordCount <= 8) {
2403
                variant = 24;
2404
            }
2405
        }
2406
 
2407
        /*
2408
         * Now we have the variant we can load the data - from here on the same as MicroPDF417 code
2409
         */
2410
        variant--;
2411
        option_2 = MICRO_VARIANTS[variant]; /* columns */
2412
        rows = MICRO_VARIANTS[variant + 34]; /* rows */
2413
        k = MICRO_VARIANTS[variant + 68]; /* number of EC CWs */
2414
        longueur = option_2 * rows - k; /* number of non-EC CWs */
2415
        i = longueur - this.codeWordCount; /* amount of padding required */
2416
        offset = MICRO_VARIANTS[variant + 102]; /* coefficient offset */
2417
 
2418
        /* We add the padding */
2419
        while (i > 0) {
2420
            this.codeWords[this.codeWordCount] = 900;
2421
            this.codeWordCount++;
2422
            i--;
2423
        }
2424
 
2425
        /* Reed-Solomon error correction */
2426
        longueur = this.codeWordCount;
2427
        for (loop = 0; loop < 50; loop++) {
2428
            mccorrection[loop] = 0;
2429
        }
2430
        total = 0;
2431
        info("Composite Codewords: ");
2432
        for (i = 0; i < longueur; i++) {
2433
            total = (this.codeWords[i] + mccorrection[k - 1]) % 929;
2434
            for (j = k - 1; j >= 0; j--) {
2435
                if (j == 0) {
2436
                    mccorrection[j] = (929 - total * MICROCOEFFS[offset + j] % 929) % 929;
2437
                } else {
2438
                    mccorrection[j] = (mccorrection[j - 1] + 929 - total * MICROCOEFFS[offset + j] % 929) % 929;
2439
                }
2440
            }
2441
            infoSpace(this.codeWords[i]);
2442
        }
2443
        infoLine();
2444
 
2445
        for (j = 0; j < k; j++) {
2446
            if (mccorrection[j] != 0) {
2447
                mccorrection[j] = 929 - mccorrection[j];
2448
            }
2449
        }
2450
        /* we add these codes to the string */
2451
        for (i = k - 1; i >= 0; i--) {
2452
            this.codeWords[this.codeWordCount] = mccorrection[i];
2453
            this.codeWordCount++;
2454
        }
2455
 
2456
        /* Now get the RAP (Row Address Pattern) start values */
2457
        LeftRAPStart = RAP_TABLE[variant];
2458
        CentreRAPStart = RAP_TABLE[variant + 34];
2459
        RightRAPStart = RAP_TABLE[variant + 68];
2460
        StartCluster = RAP_TABLE[variant + 102] / 3;
2461
 
2462
        /* That's all values loaded, get on with the encoding */
2463
 
2464
        LeftRAP = LeftRAPStart;
2465
        CentreRAP = CentreRAPStart;
2466
        RightRAP = RightRAPStart;
2467
        Cluster = StartCluster; /*
2468
                                 * Cluster can be 0, 1 or 2 for Cluster(0), Cluster(3) and
2469
                                 * Cluster(6)
2470
                                 */
2471
 
2472
        this.readable = "";
2473
        this.row_count = rows;
2474
        this.pattern = new String[this.row_count];
2475
        this.row_height = new int[this.row_count];
2476
 
2477
        for (i = 0; i < rows; i++) {
2478
            codebarre = "";
2479
            offset = 929 * Cluster;
2480
            for (j = 0; j < 5; j++) {
2481
                dummy[j] = 0;
2482
            }
2483
            for (j = 0; j < option_2; j++) {
2484
                dummy[j + 1] = this.codeWords[i * option_2 + j];
2485
            }
2486
            /* Copy the data into codebarre */
2487
            codebarre += RAPLR[LeftRAP];
2488
            codebarre += "1";
2489
            codebarre += CODAGEMC[offset + dummy[1]];
2490
            codebarre += "1";
2491
            if (this.cc_width == 3) {
2492
                codebarre += RAPC[CentreRAP];
2493
            }
2494
            if (this.cc_width >= 2) {
2495
                codebarre += "1";
2496
                codebarre += CODAGEMC[offset + dummy[2]];
2497
                codebarre += "1";
2498
            }
2499
            if (this.cc_width == 4) {
2500
                codebarre += RAPC[CentreRAP];
2501
            }
2502
            if (this.cc_width >= 3) {
2503
                codebarre += "1";
2504
                codebarre += CODAGEMC[offset + dummy[3]];
2505
                codebarre += "1";
2506
            }
2507
            if (this.cc_width == 4) {
2508
                codebarre += "1";
2509
                codebarre += CODAGEMC[offset + dummy[4]];
2510
                codebarre += "1";
2511
            }
2512
            codebarre += RAPLR[RightRAP];
2513
            codebarre += "1"; /* stop */
2514
 
2515
            /* Now codebarre is a mixture of letters and numbers */
2516
 
2517
            flip = 1;
2518
            bin.setLength(0);
2519
            for (loop = 0; loop < codebarre.length(); loop++) {
2520
                if (codebarre.charAt(loop) >= '0' && codebarre.charAt(loop) <= '9') {
2521
                    for (k = 0; k < codebarre.charAt(loop) - '0'; k++) {
2522
                        if (flip == 0) {
2523
                            bin.append('0');
2524
                        } else {
2525
                            bin.append('1');
2526
                        }
2527
                    }
2528
                    if (flip == 0) {
2529
                        flip = 1;
2530
                    } else {
2531
                        flip = 0;
2532
                    }
2533
                } else {
2534
                    bin.append(PDF_TTF[positionOf(codebarre.charAt(loop), BR_SET)]);
2535
                }
2536
            }
2537
 
2538
            this.pattern[i] = bin2pat(bin);
2539
            this.row_height[i] = 2;
2540
 
2541
            /* Set up RAPs and Cluster for next row */
2542
            LeftRAP++;
2543
            CentreRAP++;
2544
            RightRAP++;
2545
            Cluster++;
2546
 
2547
            if (LeftRAP == 53) {
2548
                LeftRAP = 1;
2549
            }
2550
            if (CentreRAP == 53) {
2551
                CentreRAP = 1;
2552
            }
2553
            if (RightRAP == 53) {
2554
                RightRAP = 1;
2555
            }
2556
            if (Cluster == 3) {
2557
                Cluster = 0;
2558
            }
2559
 
2560
        }
2561
    }
2562
 
2563
    private void cc_c() {
2564
        /* CC-C 2D component - byte compressed PDF417 */
2565
        int length, i, binloc, k;
2566
        int offset, longueur, loop, total, j;
2567
        final int[] mccorrection = new int[520];
2568
        int c1, c2, c3;
2569
        final int[] dummy = new int[35];
2570
        String codebarre;
2571
        final StringBuilder bin = new StringBuilder();
2572
        this.inputData = new int[this.binary_string.length() / 8 + 4];
2573
 
2574
        length = this.binary_string.length() / 8;
2575
 
2576
        for (i = 0; i < length; i++) {
2577
            binloc = i * 8;
2578
            this.inputData[i] = 0;
2579
            for (j = 0; j < 8; j++) {
2580
                if (this.binary_string.charAt(binloc + j) == '1') {
2581
                    this.inputData[i] += 0x80 >> j;
2582
                }
2583
            }
2584
        }
2585
 
2586
        this.codeWordCount = 0;
2587
        this.codeWords[this.codeWordCount] = 0; /* space for length descriptor */
2588
        this.codeWordCount++;
2589
        this.codeWords[this.codeWordCount] = 920; /* CC-C identifier */
2590
        this.codeWordCount++;
2591
 
2592
        byteprocess(0, length);
2593
 
2594
        this.codeWords[0] = this.codeWordCount;
2595
 
2596
        k = 1;
2597
        for (i = 1; i <= this.ecc + 1; i++) {
2598
            k *= 2;
2599
        }
2600
 
2601
        /* 796 - we now take care of the Reed Solomon codes */
2602
        switch (this.ecc) {
2603
        case 1:
2604
            offset = 2;
2605
            break;
2606
        case 2:
2607
            offset = 6;
2608
            break;
2609
        case 3:
2610
            offset = 14;
2611
            break;
2612
        case 4:
2613
            offset = 30;
2614
            break;
2615
        case 5:
2616
            offset = 62;
2617
            break;
2618
        case 6:
2619
            offset = 126;
2620
            break;
2621
        case 7:
2622
            offset = 254;
2623
            break;
2624
        case 8:
2625
            offset = 510;
2626
            break;
2627
        default:
2628
            offset = 0;
2629
            break;
2630
        }
2631
 
2632
        longueur = this.codeWordCount;
2633
        for (loop = 0; loop < 520; loop++) {
2634
            mccorrection[loop] = 0;
2635
        }
2636
        total = 0;
2637
        info("Composite Codewords: ");
2638
        for (i = 0; i < longueur; i++) {
2639
            total = (this.codeWords[i] + mccorrection[k - 1]) % 929;
2640
            for (j = k - 1; j >= 0; j--) {
2641
                if (j == 0) {
2642
                    mccorrection[j] = (929 - total * COEFRS[offset + j] % 929) % 929;
2643
                } else {
2644
                    mccorrection[j] = (mccorrection[j - 1] + 929 - total * COEFRS[offset + j] % 929) % 929;
2645
                }
2646
            }
2647
            infoSpace(this.codeWords[i]);
2648
        }
2649
        infoLine();
2650
 
2651
        for (j = 0; j < k; j++) {
2652
            if (mccorrection[j] != 0) {
2653
                mccorrection[j] = 929 - mccorrection[j];
2654
            }
2655
        }
2656
        /* we add these codes to the string */
2657
        for (i = k - 1; i >= 0; i--) {
2658
            this.codeWords[this.codeWordCount] = mccorrection[i];
2659
            this.codeWordCount++;
2660
        }
2661
 
2662
        /* 818 - The CW string is finished */
2663
        c1 = (this.codeWordCount / this.cc_width - 1) / 3;
2664
        c2 = this.ecc * 3 + (this.codeWordCount / this.cc_width - 1) % 3;
2665
        c3 = this.cc_width - 1;
2666
 
2667
        this.readable = "";
2668
        this.row_count = this.codeWordCount / this.cc_width;
2669
        this.pattern = new String[this.row_count];
2670
        this.row_height = new int[this.row_count];
2671
 
2672
        /* we now encode each row */
2673
        for (i = 0; i <= this.codeWordCount / this.cc_width - 1; i++) {
2674
            for (j = 0; j < this.cc_width; j++) {
2675
                dummy[j + 1] = this.codeWords[i * this.cc_width + j];
2676
            }
2677
            k = i / 3 * 30;
2678
            switch (i % 3) {
2679
            /*
2680
             * follows this pattern from US Patent 5,243,655: Row 0: L0 (row #, # of rows) R0 (row
2681
             * #, # of columns) Row 1: L1 (row #, security level) R1 (row #, # of rows) Row 2: L2
2682
             * (row #, # of columns) R2 (row #, security level) Row 3: L3 (row #, # of rows) R3 (row
2683
             * #, # of columns) etc.
2684
             */
2685
            case 0:
2686
                dummy[0] = k + c1;
2687
                dummy[this.cc_width + 1] = k + c3;
2688
                break;
2689
            case 1:
2690
                dummy[0] = k + c2;
2691
                dummy[this.cc_width + 1] = k + c1;
2692
                break;
2693
            case 2:
2694
                dummy[0] = k + c3;
2695
                dummy[this.cc_width + 1] = k + c2;
2696
                break;
2697
            }
2698
            codebarre = "+*"; /* Start with a start char and a separator */
2699
 
2700
            for (j = 0; j <= this.cc_width + 1; j++) {
2701
                switch (i % 3) {
2702
                case 1:
2703
                    offset = 929;
2704
                    /* cluster(3) */ break;
2705
                case 2:
2706
                    offset = 1858;
2707
                    /* cluster(6) */ break;
2708
                default:
2709
                    offset = 0;
2710
                    /* cluster(0) */ break;
2711
                }
2712
                codebarre += CODAGEMC[offset + dummy[j]];
2713
                codebarre += "*";
2714
            }
2715
            codebarre += "-";
2716
 
2717
            bin.setLength(0);
2718
            for (loop = 0; loop < codebarre.length(); loop++) {
2719
                bin.append(PDF_TTF[positionOf(codebarre.charAt(loop), BR_SET)]);
2720
            }
2721
            this.pattern[i] = bin2pat(bin);
2722
            this.row_height[i] = 3;
2723
        }
2724
    }
2725
 
2726
    private void byteprocess(int start, final int length) {
2727
        int len = 0;
2728
        int chunkLen = 0;
2729
        BigInteger mantisa;
2730
        BigInteger total;
2731
        BigInteger word;
2732
 
2733
        /* select the switch for multiple of 6 bytes */
2734
        if (this.binary_string.length() % 6 == 0) {
2735
            this.codeWords[this.codeWordCount++] = 924;
2736
        } else {
2737
            this.codeWords[this.codeWordCount++] = 901;
2738
        }
2739
 
2740
        while (len < length) {
2741
            chunkLen = length - len;
2742
            if (6 <= chunkLen) /* Take groups of 6 */ {
2743
                chunkLen = 6;
2744
                len += chunkLen;
2745
                total = BigInteger.valueOf(0);
2746
 
2747
                while (chunkLen-- != 0) {
2748
                    mantisa = BigInteger.valueOf(this.inputData[start++]);
2749
                    total = total.or(mantisa.shiftLeft(chunkLen * 8));
2750
                }
2751
 
2752
                chunkLen = 5;
2753
 
2754
                while (chunkLen-- != 0) {
2755
 
2756
                    word = total.mod(BigInteger.valueOf(900));
2757
                    this.codeWords[this.codeWordCount + chunkLen] = word.intValue();
2758
                    total = total.divide(BigInteger.valueOf(900));
2759
                }
2760
                this.codeWordCount += 5;
2761
            } else /* If it remain a group of less than 6 bytes */ {
2762
                len += chunkLen;
2763
                while (chunkLen-- != 0) {
2764
                    this.codeWords[this.codeWordCount++] = this.inputData[start++];
2765
                }
2766
            }
2767
        }
2768
    }
2769
}