001/*
002 * $Id: BarcodeDatamatrix.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.pdf;
045
046import java.awt.Canvas;
047import java.awt.image.MemoryImageSource;
048import java.io.UnsupportedEncodingException;
049import java.util.Arrays;
050import java.util.Hashtable;
051
052import com.itextpdf.text.BadElementException;
053import com.itextpdf.text.Image;
054import com.itextpdf.text.pdf.codec.CCITTG4Encoder;
055
056/**
057 * A DataMatrix 2D barcode generator.
058 */
059public class BarcodeDatamatrix {
060    /**
061     * No error.
062     */
063    public static final int DM_NO_ERROR = 0;
064    /**
065     * The text is too big for the symbology capabilities.
066     */
067    public static final int DM_ERROR_TEXT_TOO_BIG = 1;
068    /**
069     * The dimensions given for the symbol are illegal.
070     */
071    public static final int DM_ERROR_INVALID_SQUARE = 3;
072    /**
073     * An error while parsing an extension.
074     */
075    public static final int DM_ERROR_EXTENSION = 5;
076
077    /**
078     * The best encodation will be used.
079     */
080    public static final int DM_AUTO = 0;
081    /**
082     * ASCII encodation.
083     */
084    public static final int DM_ASCII = 1;
085    /**
086     * C40 encodation.
087     */
088    public static final int DM_C40 = 2;
089    /**
090     * TEXT encodation.
091     */
092    public static final int DM_TEXT = 3;
093    /**
094     * Binary encodation.
095     */
096    public static final int DM_B256 = 4;
097    /**
098     * X21 encodation.
099     */
100    public static final int DM_X21 = 5;
101    /**
102     * EDIFACT encodation.
103     */
104    public static final int DM_EDIFACT = 6;
105    /**
106     * No encodation needed. The bytes provided are already encoded.
107     */
108    public static final int DM_RAW = 7;
109
110    /**
111     * Allows extensions to be embedded at the start of the text.
112     */
113    public static final int DM_EXTENSION = 32;
114    /**
115     * Doesn't generate the image but returns all the other information.
116     */
117    public static final int DM_TEST = 64;
118
119    private final static DmParams[] dmSizes = {
120        new DmParams(10, 10, 10, 10, 3, 3, 5),
121        new DmParams(12, 12, 12, 12, 5, 5, 7),
122        new DmParams(8, 18, 8, 18, 5, 5, 7),
123        new DmParams(14, 14, 14, 14, 8, 8, 10),
124        new DmParams(8, 32, 8, 16, 10, 10, 11),
125        new DmParams(16, 16, 16, 16, 12, 12, 12),
126        new DmParams(12, 26, 12, 26, 16, 16, 14),
127        new DmParams(18, 18, 18, 18, 18, 18, 14),
128        new DmParams(20, 20, 20, 20, 22, 22, 18),
129        new DmParams(12, 36, 12, 18, 22, 22, 18),
130        new DmParams(22, 22, 22, 22, 30, 30, 20),
131        new DmParams(16, 36, 16, 18, 32, 32, 24),
132        new DmParams(24, 24, 24, 24, 36, 36, 24),
133        new DmParams(26, 26, 26, 26, 44, 44, 28),
134        new DmParams(16, 48, 16, 24, 49, 49, 28),
135        new DmParams(32, 32, 16, 16, 62, 62, 36),
136        new DmParams(36, 36, 18, 18, 86, 86, 42),
137        new DmParams(40, 40, 20, 20, 114, 114, 48),
138        new DmParams(44, 44, 22, 22, 144, 144, 56),
139        new DmParams(48, 48, 24, 24, 174, 174, 68),
140        new DmParams(52, 52, 26, 26, 204, 102, 42),
141        new DmParams(64, 64, 16, 16, 280, 140, 56),
142        new DmParams(72, 72, 18, 18, 368, 92, 36),
143        new DmParams(80, 80, 20, 20, 456, 114, 48),
144        new DmParams(88, 88, 22, 22, 576, 144, 56),
145        new DmParams(96, 96, 24, 24, 696, 174, 68),
146        new DmParams(104, 104, 26, 26, 816, 136, 56),
147        new DmParams(120, 120, 20, 20, 1050, 175, 68),
148        new DmParams(132, 132, 22, 22, 1304, 163, 62),
149        new DmParams(144, 144, 24, 24, 1558, 156, 62)};
150
151    private static final String x12 = "\r*> 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
152    private int extOut;
153    private short[] place;
154    private byte[] image;
155    private int height;
156    private int width;
157    private int ws;
158    private int options;
159
160    /**
161     * Creates an instance of this class.
162     */
163    public BarcodeDatamatrix() {
164    }
165
166    private void setBit(int x, int y, int xByte) {
167        image[y * xByte + x / 8] |= (byte)(128 >> (x & 7));
168    }
169
170    private void draw(byte[] data, int dataSize, DmParams dm) {
171        int i, j, p, x, y, xs, ys, z;
172        int xByte = (dm.width + ws * 2 + 7) / 8;
173        Arrays.fill(image, (byte)0);
174        //alignment patterns
175        //dotted horizontal line
176        for (i = ws; i < dm.height + ws; i += dm.heightSection) {
177            for (j = ws; j < dm.width + ws; j += 2) {
178                setBit(j, i, xByte);
179            }
180        }
181        //solid horizontal line
182        for (i = dm.heightSection - 1 + ws; i < dm.height + ws; i += dm.heightSection) {
183            for (j = ws; j < dm.width + ws; ++j) {
184                setBit(j, i, xByte);
185            }
186        }
187        //solid vertical line
188        for (i = ws; i < dm.width + ws; i += dm.widthSection) {
189            for (j = ws; j < dm.height + ws; ++j) {
190                setBit(i, j, xByte);
191            }
192        }
193        //dotted vertical line
194        for (i = dm.widthSection - 1 + ws; i < dm.width + ws; i += dm.widthSection) {
195            for (j = 1 + ws; j < dm.height + ws; j += 2) {
196                setBit(i, j, xByte);
197            }
198        }
199        p = 0;
200        for (ys = 0; ys < dm.height; ys += dm.heightSection) {
201            for (y = 1; y < dm.heightSection - 1; ++y) {
202                for (xs = 0; xs < dm.width; xs += dm.widthSection) {
203                    for (x = 1; x < dm.widthSection - 1; ++x) {
204                        z = place[p++];
205                        if (z == 1 || z > 1 && (data[z/8-1] & 0xff & 128 >> z%8) != 0)
206                            setBit(x + xs + ws, y + ys + ws, xByte);
207                    }
208                }
209            }
210        }
211    }
212
213    private static void makePadding(byte[] data, int position, int count) {
214        //already in ascii mode
215        if (count <= 0)
216            return;
217        data[position++] = (byte)129;
218        while (--count > 0) {
219            int t = 129 + (position + 1) * 149 % 253 + 1;
220            if (t > 254)
221                t -= 254;
222            data[position++] = (byte)t;
223        }
224    }
225
226    private static boolean isDigit(int c) {
227        return c >= '0' && c <= '9';
228    }
229
230    private static int asciiEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) {
231        int ptrIn, ptrOut, c;
232        ptrIn = textOffset;
233        ptrOut = dataOffset;
234        textLength += textOffset;
235        dataLength += dataOffset;
236        while (ptrIn < textLength) {
237            if (ptrOut >= dataLength)
238                return -1;
239            c = text[ptrIn++] & 0xff;
240            if (isDigit(c) && ptrIn < textLength && isDigit(text[ptrIn] & 0xff)) {
241                data[ptrOut++] = (byte)((c - '0') * 10 + (text[ptrIn++] & 0xff) - '0' + 130);
242            }
243            else if (c > 127) {
244                if (ptrOut + 1 >= dataLength)
245                    return -1;
246                data[ptrOut++] = (byte)235;
247                data[ptrOut++] = (byte)(c - 128 + 1);
248            }
249            else {
250                data[ptrOut++] = (byte)(c + 1);
251            }
252        }
253        return ptrOut - dataOffset;
254    }
255
256    private static int b256Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) {
257        int k, j, prn, tv, c;
258        if (textLength == 0)
259            return 0;
260        if (textLength < 250 && textLength + 2 > dataLength)
261            return -1;
262        if (textLength >= 250 && textLength + 3 > dataLength)
263            return -1;
264        data[dataOffset] = (byte)231;
265        if (textLength < 250) {
266            data[dataOffset + 1] = (byte)textLength;
267            k = 2;
268        }
269        else {
270            data[dataOffset + 1] = (byte)(textLength / 250 + 249);
271            data[dataOffset + 2] = (byte)(textLength % 250);
272            k = 3;
273        }
274        System.arraycopy(text, textOffset, data, k + dataOffset, textLength);
275        k += textLength + dataOffset;
276        for (j = dataOffset + 1; j < k; ++j) {
277            c = data[j] & 0xff;
278            prn = 149 * (j + 1) % 255 + 1;
279            tv = c + prn;
280            if (tv > 255)
281                tv -= 256;
282            data[j] = (byte)tv;
283
284        }
285        return k - dataOffset;
286    }
287
288    private static int X12Encodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) {
289        int ptrIn, ptrOut, count, k, n, ci;
290        byte c;
291        if (textLength == 0)
292            return 0;
293        ptrIn = 0;
294        ptrOut = 0;
295        byte[] x = new byte[textLength];
296        count = 0;
297        for (; ptrIn < textLength; ++ptrIn) {
298            int i = x12.indexOf((char)text[ptrIn + textOffset]);
299            if (i >= 0) {
300                x[ptrIn] = (byte)i;
301                ++count;
302            }
303            else {
304                x[ptrIn] = 100;
305                if (count >= 6)
306                    count -= count / 3 * 3;
307                for (k = 0; k < count; ++k)
308                    x[ptrIn - k - 1] = 100;
309                count = 0;
310            }
311        }
312        if (count >= 6)
313            count -= count / 3 * 3;
314        for (k = 0; k < count; ++k)
315            x[ptrIn - k - 1] = 100;
316        ptrIn = 0;
317        c = 0;
318        for (; ptrIn < textLength; ++ptrIn) {
319            c = x[ptrIn];
320            if (ptrOut >= dataLength)
321                break;
322            if (c < 40) {
323                if (ptrIn == 0 || ptrIn > 0 && x[ptrIn - 1] > 40)
324                    data[dataOffset + ptrOut++] = (byte)238;
325                if (ptrOut + 2 > dataLength)
326                    break;
327                n = 1600 * x[ptrIn] + 40 * x[ptrIn + 1] + x[ptrIn + 2] + 1;
328                data[dataOffset + ptrOut++] = (byte)(n / 256);
329                data[dataOffset + ptrOut++] = (byte)n;
330                ptrIn += 2;
331            }
332            else {
333                if (ptrIn > 0 && x[ptrIn - 1] < 40)
334                    data[dataOffset + ptrOut++] = (byte)254;
335                ci = text[ptrIn + textOffset] & 0xff;
336                if (ci > 127) {
337                    data[dataOffset + ptrOut++] = (byte)235;
338                    ci -= 128;
339                }
340                if (ptrOut >= dataLength)
341                    break;
342                data[dataOffset + ptrOut++] = (byte)(ci + 1);
343            }
344        }
345        c = 100;
346        if (textLength > 0)
347            c = x[textLength - 1];
348        if (ptrIn != textLength || c < 40 && ptrOut >= dataLength)
349            return -1;
350        if (c < 40)
351            data[dataOffset + ptrOut++] = (byte)254;
352        return ptrOut;
353    }
354
355    private static int EdifactEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength) {
356        int ptrIn, ptrOut, edi, pedi, c;
357        if (textLength == 0)
358            return 0;
359        ptrIn = 0;
360        ptrOut = 0;
361        edi = 0;
362        pedi = 18;
363        boolean ascii = true;
364        for (; ptrIn < textLength; ++ptrIn) {
365            c = text[ptrIn + textOffset] & 0xff;
366            if (((c & 0xe0) == 0x40 || (c & 0xe0) == 0x20) && c != '_') {
367                if (ascii) {
368                    if (ptrOut + 1 > dataLength)
369                        break;
370                    data[dataOffset + ptrOut++] = (byte)240;
371                    ascii = false;
372                }
373                c &= 0x3f;
374                edi |= c << pedi;
375                if (pedi == 0) {
376                    if (ptrOut + 3 > dataLength)
377                        break;
378                    data[dataOffset + ptrOut++] = (byte)(edi >> 16);
379                    data[dataOffset + ptrOut++] = (byte)(edi >> 8);
380                    data[dataOffset + ptrOut++] = (byte)edi;
381                    edi = 0;
382                    pedi = 18;
383                }
384                else
385                    pedi -= 6;
386            }
387            else {
388                if (!ascii) {
389                    edi |= ('_' & 0x3f) << pedi;
390                    if (ptrOut + 3 - pedi / 8 > dataLength)
391                        break;
392                    data[dataOffset + ptrOut++] = (byte)(edi >> 16);
393                    if (pedi <= 12)
394                        data[dataOffset + ptrOut++] = (byte)(edi >> 8);
395                    if (pedi <= 6)
396                        data[dataOffset + ptrOut++] = (byte)edi;
397                    ascii = true;
398                    pedi = 18;
399                    edi = 0;
400                }
401                if (c > 127) {
402                    if (ptrOut >= dataLength)
403                        break;
404                    data[dataOffset + ptrOut++] = (byte)235;
405                    c -= 128;
406                }
407                if (ptrOut >= dataLength)
408                    break;
409                data[dataOffset + ptrOut++] = (byte)(c + 1);
410            }
411        }
412        if (ptrIn != textLength)
413            return -1;
414        if (!ascii) {
415            edi |= ('_' & 0x3f) << pedi;
416            if (ptrOut + 3 - pedi / 8 > dataLength)
417                return -1;
418            data[dataOffset + ptrOut++] = (byte)(edi >> 16);
419            if (pedi <= 12)
420                data[dataOffset + ptrOut++] = (byte)(edi >> 8);
421            if (pedi <= 6)
422                data[dataOffset + ptrOut++] = (byte)edi;
423        }
424        return ptrOut;
425    }
426
427    private static int C40OrTextEncodation(byte[] text, int textOffset, int textLength, byte[] data, int dataOffset, int dataLength, boolean c40) {
428        int ptrIn, ptrOut, encPtr, last0, last1, i, a, c;
429        String basic, shift2, shift3;
430        if (textLength == 0)
431            return 0;
432        ptrIn = 0;
433        ptrOut = 0;
434        if (c40)
435            data[dataOffset + ptrOut++] = (byte)230;
436        else
437            data[dataOffset + ptrOut++] = (byte)239;
438        shift2 = "!\"#$%&'()*+,-./:;<=>?@[\\]^_";
439        if (c40) {
440            basic = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
441            shift3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177";
442        }
443        else {
444            basic = " 0123456789abcdefghijklmnopqrstuvwxyz";
445            shift3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177";
446        }
447        int[] enc = new int[textLength * 4 + 10];
448        encPtr = 0;
449        last0 = 0;
450        last1 = 0;
451        while (ptrIn < textLength) {
452            if (encPtr % 3 == 0) {
453                last0 = ptrIn;
454                last1 = encPtr;
455            }
456            c = text[textOffset + ptrIn++] & 0xff;
457            if (c > 127) {
458                c -= 128;
459                enc[encPtr++] = 1;
460                enc[encPtr++] = 30;
461            }
462            int idx = basic.indexOf((char)c);
463            if (idx >= 0) {
464                enc[encPtr++] = idx + 3;
465            }
466            else if (c < 32) {
467                enc[encPtr++] = 0;
468                enc[encPtr++] = c;
469            }
470            else if ((idx = shift2.indexOf((char)c)) >= 0) {
471                enc[encPtr++] = 1;
472                enc[encPtr++] = idx;
473            }
474            else if ((idx = shift3.indexOf((char)c)) >= 0) {
475                enc[encPtr++] = 2;
476                enc[encPtr++] = idx;
477            }
478        }
479        if (encPtr % 3 != 0) {
480            ptrIn = last0;
481            encPtr = last1;
482        }
483        if (encPtr / 3 * 2 > dataLength - 2) {
484            return -1;
485        }
486        i = 0;
487        for (; i < encPtr; i += 3) {
488            a = 1600 * enc[i] + 40 * enc[i + 1] + enc[i + 2] + 1;
489            data[dataOffset + ptrOut++] = (byte)(a / 256);
490            data[dataOffset + ptrOut++] = (byte)a;
491        }
492        data[ptrOut++] = (byte)254;
493        i = asciiEncodation(text, ptrIn, textLength - ptrIn, data, ptrOut, dataLength - ptrOut);
494        if (i < 0)
495            return i;
496        return ptrOut + i;
497    }
498
499    private static int getEncodation(byte[] text, int textOffset, int textSize, byte[] data, int dataOffset, int dataSize, int options, boolean firstMatch) {
500        int e, j, k;
501        int[] e1 = new int[6];
502        if (dataSize < 0)
503            return -1;
504        e = -1;
505        options &= 7;
506        if (options == 0) {
507            e1[0] = asciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize);
508            if (firstMatch && e1[0] >= 0)
509                return e1[0];
510            e1[1] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false);
511            if (firstMatch && e1[1] >= 0)
512                return e1[1];
513            e1[2] = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true);
514            if (firstMatch && e1[2] >= 0)
515                return e1[2];
516            e1[3] = b256Encodation(text, textOffset, textSize, data, dataOffset, dataSize);
517            if (firstMatch && e1[3] >= 0)
518                return e1[3];
519            e1[4] = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize);
520            if (firstMatch && e1[4] >= 0)
521                return e1[4];
522            e1[5] = EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize);
523            if (firstMatch && e1[5] >= 0)
524                return e1[5];
525            if (e1[0] < 0 && e1[1] < 0 && e1[2] < 0 && e1[3] < 0 && e1[4] < 0 && e1[5] < 0) {
526                return -1;
527            }
528            j = 0;
529            e = 99999;
530            for (k = 0; k < 6; ++k) {
531                if (e1[k] >= 0 && e1[k] < e) {
532                    e = e1[k];
533                    j = k;
534                }
535            }
536            if (j == 0)
537                e = asciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize);
538            else if (j == 1)
539                e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false);
540            else if (j == 2)
541                e = C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true);
542            else if (j == 3)
543                e = b256Encodation(text, textOffset, textSize, data, dataOffset, dataSize);
544            else if (j == 4)
545                e = X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize);
546            return e;
547        }
548        switch (options) {
549        case DM_ASCII:
550            return asciiEncodation(text, textOffset, textSize, data, dataOffset, dataSize);
551        case DM_C40:
552            return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, true);
553        case DM_TEXT:
554            return C40OrTextEncodation(text, textOffset, textSize, data, dataOffset, dataSize, false);
555        case DM_B256:
556            return b256Encodation(text, textOffset, textSize, data, dataOffset, dataSize);
557        case DM_X21:
558            return X12Encodation(text, textOffset, textSize, data, dataOffset, dataSize);
559        case DM_EDIFACT:
560            return EdifactEncodation(text, textOffset, textSize, data, dataOffset, dataSize);
561        case DM_RAW:
562            if (textSize > dataSize)
563                return -1;
564            System.arraycopy(text, textOffset, data, dataOffset, textSize);
565            return textSize;
566        }
567        return -1;
568    }
569
570    private static int getNumber(byte[] text, int ptrIn, int n) {
571        int v, j, c;
572        v = 0;
573        for (j = 0; j < n; ++j) {
574            c = text[ptrIn++] &0xff;
575            if (c < '0' || c > '9')
576                return -1;
577            v = v * 10 + c - '0';
578        }
579        return v;
580    }
581
582    private int processExtensions(byte[] text, int textOffset, int textSize, byte[] data) {
583        int order, ptrIn, ptrOut, eci, fn, ft, fi, c;
584        if ((options & DM_EXTENSION) == 0)
585            return 0;
586        order = 0;
587        ptrIn = 0;
588        ptrOut = 0;
589        while (ptrIn < textSize) {
590            if (order > 20)
591                return -1;
592            c = text[textOffset + ptrIn++] &0xff;
593            ++order;
594            switch (c) {
595            case '.':
596                extOut = ptrIn;
597                return ptrOut;
598            case 'e':
599                if (ptrIn + 6 > textSize)
600                    return -1;
601                eci = getNumber(text, textOffset + ptrIn, 6);
602                if (eci < 0)
603                    return -1;
604                ptrIn += 6;
605                data[ptrOut++] = (byte)241;
606                if (eci < 127)
607                    data[ptrOut++] = (byte)(eci + 1);
608                else if (eci < 16383) {
609                    data[ptrOut++] = (byte)((eci - 127) / 254 + 128);
610                    data[ptrOut++] = (byte)((eci - 127) % 254 + 1);
611                }
612                else {
613                    data[ptrOut++] = (byte)((eci - 16383) / 64516 + 192);
614                    data[ptrOut++] = (byte)((eci - 16383) / 254 % 254 + 1);
615                    data[ptrOut++] = (byte)((eci - 16383) % 254 + 1);
616                }
617                break;
618            case 's':
619                if (order != 1)
620                    return -1;
621                if (ptrIn + 9 > textSize)
622                    return -1;
623                fn = getNumber(text, textOffset + ptrIn, 2);
624                if (fn <= 0 || fn > 16)
625                    return -1;
626                ptrIn += 2;
627                ft = getNumber(text, textOffset + ptrIn, 2);
628                if (ft <= 1 || ft > 16)
629                    return -1;
630                ptrIn += 2;
631                fi = getNumber(text, textOffset + ptrIn, 5);
632                if (fi < 0 || fn >= 64516)
633                    return -1;
634                ptrIn += 5;
635                data[ptrOut++] = (byte)233;
636                data[ptrOut++] = (byte)(fn - 1 << 4 | 17 - ft);
637                data[ptrOut++] = (byte)(fi / 254 + 1);
638                data[ptrOut++] = (byte)(fi % 254 + 1);
639                break;
640            case 'p':
641                if (order != 1)
642                    return -1;
643                data[ptrOut++] = (byte)234;
644                break;
645            case 'm':
646                if (order != 1)
647                    return -1;
648                if (ptrIn + 1 > textSize)
649                    return -1;
650                c = text[textOffset + ptrIn++] &0xff;
651                if (c != '5' && c != '5')
652                    return -1;
653                data[ptrOut++] = (byte)234;
654                data[ptrOut++] = (byte)(c == '5' ? 236 : 237);
655                break;
656            case 'f':
657                if (order != 1 && (order != 2 || text[textOffset] != 's' && text[textOffset] != 'm'))
658                    return -1;
659                data[ptrOut++] = (byte)232;
660            }
661        }
662        return -1;
663    }
664
665    /**
666     * Creates a barcode. The <CODE>String</CODE> is interpreted with the ISO-8859-1 encoding
667     * @param text the text
668     * @return the status of the generation. It can be one of this values:
669     * <p>
670     * <CODE>DM_NO_ERROR</CODE> - no error.<br>
671     * <CODE>DM_ERROR_TEXT_TOO_BIG</CODE> - the text is too big for the symbology capabilities.<br>
672     * <CODE>DM_ERROR_INVALID_SQUARE</CODE> - the dimensions given for the symbol are illegal.<br>
673     * <CODE>DM_ERROR_EXTENSION</CODE> - an error was while parsing an extension.
674     * @throws java.io.UnsupportedEncodingException on error
675     */
676    public int generate(String text) throws UnsupportedEncodingException {
677        byte[] t = text.getBytes("iso-8859-1");
678        return generate(t, 0, t.length);
679    }
680
681    /**
682     * Creates a barcode.
683     * @param text the text
684     * @param textOffset the offset to the start of the text
685     * @param textSize the text size
686     * @return the status of the generation. It can be one of this values:
687     * <p>
688     * <CODE>DM_NO_ERROR</CODE> - no error.<br>
689     * <CODE>DM_ERROR_TEXT_TOO_BIG</CODE> - the text is too big for the symbology capabilities.<br>
690     * <CODE>DM_ERROR_INVALID_SQUARE</CODE> - the dimensions given for the symbol are illegal.<br>
691     * <CODE>DM_ERROR_EXTENSION</CODE> - an error was while parsing an extension.
692     */
693    public int generate(byte[] text, int textOffset, int textSize) {
694        int extCount, e, k, full;
695        DmParams dm, last;
696        byte[] data = new byte[2500];
697        extOut = 0;
698        extCount = processExtensions(text, textOffset, textSize, data);
699        if (extCount < 0) {
700            return DM_ERROR_EXTENSION;
701        }
702        e = -1;
703        if (height == 0 || width == 0) {
704            last = dmSizes[dmSizes.length - 1];
705            e = getEncodation(text, textOffset + extOut, textSize - extOut, data, extCount, last.dataSize - extCount, options, false);
706            if (e < 0) {
707                return DM_ERROR_TEXT_TOO_BIG;
708            }
709            e += extCount;
710            for (k = 0; k < dmSizes.length; ++k) {
711                if (dmSizes[k].dataSize >= e)
712                    break;
713            }
714            dm = dmSizes[k];
715            height = dm.height;
716            width = dm.width;
717        }
718        else {
719            for (k = 0; k < dmSizes.length; ++k) {
720                if (height == dmSizes[k].height && width == dmSizes[k].width)
721                    break;
722            }
723            if (k == dmSizes.length) {
724                return DM_ERROR_INVALID_SQUARE;
725            }
726            dm = dmSizes[k];
727            e = getEncodation(text, textOffset + extOut, textSize - extOut, data, extCount, dm.dataSize - extCount, options, true);
728            if (e < 0) {
729                return DM_ERROR_TEXT_TOO_BIG;
730            }
731            e += extCount;
732        }
733        if ((options & DM_TEST) != 0) {
734            return DM_NO_ERROR;
735        }
736        image = new byte[(dm.width + 2 * ws + 7) / 8 * (dm.height + 2 * ws)];
737        makePadding(data, e, dm.dataSize - e);
738        place = Placement.doPlacement(dm.height - dm.height / dm.heightSection * 2, dm.width - dm.width / dm.widthSection * 2);
739        full = dm.dataSize + (dm.dataSize + 2) / dm.dataBlock * dm.errorBlock;
740        ReedSolomon.generateECC(data, dm.dataSize, dm.dataBlock, dm.errorBlock);
741        draw(data, full, dm);
742        return DM_NO_ERROR;
743    }
744
745    /** Gets an <CODE>Image</CODE> with the barcode. A successful call to the method <CODE>generate()</CODE>
746     * before calling this method is required.
747     * @return the barcode <CODE>Image</CODE>
748     * @throws BadElementException on error
749     */
750    public Image createImage() throws BadElementException {
751        if (image == null)
752            return null;
753        byte g4[] = CCITTG4Encoder.compress(image, width + 2 * ws, height + 2 * ws);
754        return Image.getInstance(width + 2 * ws, height + 2 * ws, false, Image.CCITTG4, 0, g4, null);
755    }
756
757    /**
758     * Creates a <CODE>java.awt.Image</CODE>. A successful call to the method <CODE>generate()</CODE>
759     * before calling this method is required.
760     * @param foreground the color of the bars
761     * @param background the color of the background
762     * @return the image
763     */
764    public java.awt.Image createAwtImage(java.awt.Color foreground, java.awt.Color background) {
765        if (image == null)
766            return null;
767        int f = foreground.getRGB();
768        int g = background.getRGB();
769        Canvas canvas = new Canvas();
770
771        int w = width + 2 * ws;
772        int h = height + 2 * ws;
773        int pix[] = new int[w * h];
774        int stride = (w + 7) / 8;
775        int ptr = 0;
776        for (int k = 0; k < h; ++k) {
777            int p = k * stride;
778            for (int j = 0; j < w; ++j) {
779                int b = image[p + j / 8] & 0xff;
780                b <<= j % 8;
781                pix[ptr++] = (b & 0x80) == 0 ? g : f;
782            }
783        }
784        java.awt.Image img = canvas.createImage(new MemoryImageSource(w, h, pix, 0, w));
785        return img;
786    }
787
788    private static class DmParams {
789        DmParams(int height, int width, int heightSection, int widthSection, int dataSize, int dataBlock, int errorBlock) {
790            this.height = height;
791            this.width = width;
792            this.heightSection = heightSection;
793            this.widthSection = widthSection;
794            this.dataSize = dataSize;
795            this.dataBlock = dataBlock;
796            this.errorBlock = errorBlock;
797        }
798
799        int height;
800        int width;
801        int heightSection;
802        int widthSection;
803        int dataSize;
804        int dataBlock;
805        int errorBlock;
806    };
807
808    /**
809     * Gets the generated image. The image is represented as a stream of bytes, each byte representing
810     * 8 pixels, 0 for white and 1 for black, with the high-order bit of each byte first. Each row
811     * is aligned at byte boundaries. The dimensions of the image are defined by height and width
812     * plus 2 * ws.
813     * @return the generated image
814     */
815    public byte[] getImage() {
816        return image;
817    }
818
819    /**
820     * Gets the height of the barcode. Will contain the real height used after a successful call
821     * to <CODE>generate()</CODE>. This height doesn't include the whitespace border, if any.
822     * @return the height of the barcode
823     */
824    public int getHeight() {
825        return height;
826    }
827
828    /**
829     * Sets the height of the barcode. If the height is zero it will be calculated. This height doesn't include the whitespace border, if any.
830     * <p>
831     * The allowed dimensions are (height, width):<p>
832     * 10, 10<br>
833     * 12, 12<br>
834     * 8, 18<br>
835     * 14, 14<br>
836     * 8, 32<br>
837     * 16, 16<br>
838     * 12, 26<br>
839     * 18, 18<br>
840     * 20, 20<br>
841     * 12, 36<br>
842     * 22, 22<br>
843     * 16, 36<br>
844     * 24, 24<br>
845     * 26, 26<br>
846     * 16, 48<br>
847     * 32, 32<br>
848     * 36, 36<br>
849     * 40, 40<br>
850     * 44, 44<br>
851     * 48, 48<br>
852     * 52, 52<br>
853     * 64, 64<br>
854     * 72, 72<br>
855     * 80, 80<br>
856     * 88, 88<br>
857     * 96, 96<br>
858     * 104, 104<br>
859     * 120, 120<br>
860     * 132, 132<br>
861     * 144, 144<br>
862     * @param height the height of the barcode
863     */
864    public void setHeight(int height) {
865        this.height = height;
866    }
867
868    /**
869     * Gets the width of the barcode. Will contain the real width used after a successful call
870     * to <CODE>generate()</CODE>. This width doesn't include the whitespace border, if any.
871     * @return the width of the barcode
872     */
873    public int getWidth() {
874        return width;
875    }
876
877    /**
878     * Sets the width of the barcode. If the width is zero it will be calculated. This width doesn't include the whitespace border, if any.
879     * <p>
880     * The allowed dimensions are (height, width):<p>
881     * 10, 10<br>
882     * 12, 12<br>
883     * 8, 18<br>
884     * 14, 14<br>
885     * 8, 32<br>
886     * 16, 16<br>
887     * 12, 26<br>
888     * 18, 18<br>
889     * 20, 20<br>
890     * 12, 36<br>
891     * 22, 22<br>
892     * 16, 36<br>
893     * 24, 24<br>
894     * 26, 26<br>
895     * 16, 48<br>
896     * 32, 32<br>
897     * 36, 36<br>
898     * 40, 40<br>
899     * 44, 44<br>
900     * 48, 48<br>
901     * 52, 52<br>
902     * 64, 64<br>
903     * 72, 72<br>
904     * 80, 80<br>
905     * 88, 88<br>
906     * 96, 96<br>
907     * 104, 104<br>
908     * 120, 120<br>
909     * 132, 132<br>
910     * 144, 144<br>
911     * @param width the width of the barcode
912     */
913    public void setWidth(int width) {
914        this.width = width;
915    }
916
917    /**
918     * Gets the whitespace border around the barcode.
919     * @return the whitespace border around the barcode
920     */
921    public int getWs() {
922        return ws;
923    }
924
925    /**
926     * Sets the whitespace border around the barcode.
927     * @param ws the whitespace border around the barcode
928     */
929    public void setWs(int ws) {
930        this.ws = ws;
931    }
932
933    /**
934     * Gets the barcode options.
935     * @return the barcode options
936     */
937    public int getOptions() {
938        return options;
939    }
940
941    /**
942     * Sets the options for the barcode generation. The options can be:<p>
943     * One of:<br>
944     * <CODE>DM_AUTO</CODE> - the best encodation will be used<br>
945     * <CODE>DM_ASCII</CODE> - ASCII encodation<br>
946     * <CODE>DM_C40</CODE> - C40 encodation<br>
947     * <CODE>DM_TEXT</CODE> - TEXT encodation<br>
948     * <CODE>DM_B256</CODE> - binary encodation<br>
949     * <CODE>DM_X21</CODE> - X21 encodation<br>
950     * <CODE>DM_EDIFACT</CODE> - EDIFACT encodation<br>
951     * <CODE>DM_RAW</CODE> - no encodation. The bytes provided are already encoded and will be added directly to the barcode, using padding if needed. It assumes that the encodation state is left at ASCII after the last byte.<br>
952     * <p>
953     * One of:<br>
954     * <CODE>DM_EXTENSION</CODE> - allows extensions to be embedded at the start of the text:<p>
955     * exxxxxx - ECI number xxxxxx<br>
956     * m5 - macro 5<br>
957     * m6 - macro 6<br>
958     * f - FNC1<br>
959     * saabbccccc - Structured Append, aa symbol position (1-16), bb total number of symbols (2-16), ccccc file identification (0-64515)<br>
960     * p - Reader programming<br>
961     * . - extension terminator<p>
962     * Example for a structured append, symbol 2 of 6, with FNC1 and ECI 000005. The actual text is "Hello".<p>
963     * s020600075fe000005.Hello<p>
964     * One of:<br>
965     * <CODE>DM_TEST</CODE> - doesn't generate the image but returns all the other information.
966     * @param options the barcode options
967     */
968    public void setOptions(int options) {
969        this.options = options;
970    }
971
972    static class Placement {
973        private int nrow;
974        private int ncol;
975        private short[] array;
976        private static final Hashtable<Integer, short[]> cache = new Hashtable<Integer, short[]>();
977
978        private Placement() {
979        }
980
981        static short[] doPlacement(int nrow, int ncol) {
982            Integer key = Integer.valueOf(nrow * 1000 + ncol);
983            short[] pc = cache.get(key);
984            if (pc != null)
985                return pc;
986            Placement p = new Placement();
987            p.nrow = nrow;
988            p.ncol = ncol;
989            p.array = new short[nrow * ncol];
990            p.ecc200();
991            cache.put(key, p.array);
992            return p.array;
993        }
994
995        /* "module" places "chr+bit" with appropriate wrapping within array[] */
996        private void module(int row, int col, int chr, int bit) {
997            if (row < 0) { row += nrow; col += 4 - (nrow+4)%8; }
998            if (col < 0) { col += ncol; row += 4 - (ncol+4)%8; }
999            array[row*ncol+col] = (short)(8*chr + bit);
1000        }
1001        /* "utah" places the 8 bits of a utah-shaped symbol character in ECC200 */
1002        private void utah(int row, int col, int chr) {
1003            module(row-2,col-2,chr,0);
1004            module(row-2,col-1,chr,1);
1005            module(row-1,col-2,chr,2);
1006            module(row-1,col-1,chr,3);
1007            module(row-1,col,chr,4);
1008            module(row,col-2,chr,5);
1009            module(row,col-1,chr,6);
1010            module(row,col,chr,7);
1011        }
1012        /* "cornerN" places 8 bits of the four special corner cases in ECC200 */
1013        private void corner1(int chr) {
1014            module(nrow-1,0,chr,0);
1015            module(nrow-1,1,chr,1);
1016            module(nrow-1,2,chr,2);
1017            module(0,ncol-2,chr,3);
1018            module(0,ncol-1,chr,4);
1019            module(1,ncol-1,chr,5);
1020            module(2,ncol-1,chr,6);
1021            module(3,ncol-1,chr,7);
1022        }
1023        private void corner2(int chr){
1024            module(nrow-3,0,chr,0);
1025            module(nrow-2,0,chr,1);
1026            module(nrow-1,0,chr,2);
1027            module(0,ncol-4,chr,3);
1028            module(0,ncol-3,chr,4);
1029            module(0,ncol-2,chr,5);
1030            module(0,ncol-1,chr,6);
1031            module(1,ncol-1,chr,7);
1032        }
1033        private void corner3(int chr){
1034            module(nrow-3,0,chr,0);
1035            module(nrow-2,0,chr,1);
1036            module(nrow-1,0,chr,2);
1037            module(0,ncol-2,chr,3);
1038            module(0,ncol-1,chr,4);
1039            module(1,ncol-1,chr,5);
1040            module(2,ncol-1,chr,6);
1041            module(3,ncol-1,chr,7);
1042        }
1043        private void corner4(int chr){
1044            module(nrow-1,0,chr,0);
1045            module(nrow-1,ncol-1,chr,1);
1046            module(0,ncol-3,chr,2);
1047            module(0,ncol-2,chr,3);
1048            module(0,ncol-1,chr,4);
1049            module(1,ncol-3,chr,5);
1050            module(1,ncol-2,chr,6);
1051            module(1,ncol-1,chr,7);
1052        }
1053        /* "ECC200" fills an nrow x ncol array with appropriate values for ECC200 */
1054        private void ecc200(){
1055            int row, col, chr;
1056            /* First, fill the array[] with invalid entries */
1057            Arrays.fill(array, (short)0);
1058            /* Starting in the correct location for character #1, bit 8,... */
1059            chr = 1; row = 4; col = 0;
1060            do {
1061                /* repeatedly first check for one of the special corner cases, then... */
1062                if (row == nrow && col == 0) corner1(chr++);
1063                if (row == nrow-2 && col == 0 && ncol%4 != 0) corner2(chr++);
1064                if (row == nrow-2 && col == 0 && ncol%8 == 4) corner3(chr++);
1065                if (row == nrow+4 && col == 2 && ncol%8 == 0) corner4(chr++);
1066                /* sweep upward diagonally, inserting successive characters,... */
1067                do {
1068                    if (row < nrow && col >= 0 && array[row*ncol+col] == 0)
1069                        utah(row,col,chr++);
1070                    row -= 2; col += 2;
1071                } while (row >= 0 && col < ncol);
1072                row += 1; col += 3;
1073                /* & then sweep downward diagonally, inserting successive characters,... */
1074
1075                do {
1076                    if (row >= 0 && col < ncol && array[row*ncol+col] == 0)
1077                        utah(row,col,chr++);
1078                    row += 2; col -= 2;
1079                } while (row < nrow && col >= 0);
1080                row += 3; col += 1;
1081                /* ... until the entire array is scanned */
1082            } while (row < nrow || col < ncol);
1083            /* Lastly, if the lower righthand corner is untouched, fill in fixed pattern */
1084            if (array[nrow*ncol-1] == 0) {
1085                array[nrow*ncol-1] = array[nrow*ncol-ncol-2] = 1;
1086            }
1087        }
1088    }
1089
1090    static class ReedSolomon {
1091
1092        private static final int log[] = {
1093               0, 255,   1, 240,   2, 225, 241,  53,   3,  38, 226, 133, 242,  43,  54, 210,
1094               4, 195,  39, 114, 227, 106, 134,  28, 243, 140,  44,  23,  55, 118, 211, 234,
1095               5, 219, 196,  96,  40, 222, 115, 103, 228,  78, 107, 125, 135,   8,  29, 162,
1096             244, 186, 141, 180,  45,  99,  24,  49,  56,  13, 119, 153, 212, 199, 235,  91,
1097               6,  76, 220, 217, 197,  11,  97, 184,  41,  36, 223, 253, 116, 138, 104, 193,
1098             229,  86,  79, 171, 108, 165, 126, 145, 136,  34,   9,  74,  30,  32, 163,  84,
1099             245, 173, 187, 204, 142,  81, 181, 190,  46,  88, 100, 159,  25, 231,  50, 207,
1100              57, 147,  14,  67, 120, 128, 154, 248, 213, 167, 200,  63, 236, 110,  92, 176,
1101               7, 161,  77, 124, 221, 102, 218,  95, 198,  90,  12, 152,  98,  48, 185, 179,
1102              42, 209,  37, 132, 224,  52, 254, 239, 117, 233, 139,  22, 105,  27, 194, 113,
1103             230, 206,  87, 158,  80, 189, 172, 203, 109, 175, 166,  62, 127, 247, 146,  66,
1104             137, 192,  35, 252,  10, 183,  75, 216,  31,  83,  33,  73, 164, 144,  85, 170,
1105             246,  65, 174,  61, 188, 202, 205, 157, 143, 169,  82,  72, 182, 215, 191, 251,
1106              47, 178,  89, 151, 101,  94, 160, 123,  26, 112, 232,  21,  51, 238, 208, 131,
1107              58,  69, 148,  18,  15,  16,  68,  17, 121, 149, 129,  19, 155,  59, 249,  70,
1108             214, 250, 168,  71, 201, 156,  64,  60, 237, 130, 111,  20,  93, 122, 177, 150
1109        };
1110
1111        private static final int alog[] = {
1112               1,   2,   4,   8,  16,  32,  64, 128,  45,  90, 180,  69, 138,  57, 114, 228,
1113             229, 231, 227, 235, 251, 219, 155,  27,  54, 108, 216, 157,  23,  46,  92, 184,
1114              93, 186,  89, 178,  73, 146,   9,  18,  36,  72, 144,  13,  26,  52, 104, 208,
1115             141,  55, 110, 220, 149,   7,  14,  28,  56, 112, 224, 237, 247, 195, 171, 123,
1116             246, 193, 175, 115, 230, 225, 239, 243, 203, 187,  91, 182,  65, 130,  41,  82,
1117             164, 101, 202, 185,  95, 190,  81, 162, 105, 210, 137,  63, 126, 252, 213, 135,
1118              35,  70, 140,  53, 106, 212, 133,  39,  78, 156,  21,  42,  84, 168, 125, 250,
1119             217, 159,  19,  38,  76, 152,  29,  58, 116, 232, 253, 215, 131,  43,  86, 172,
1120             117, 234, 249, 223, 147,  11,  22,  44,  88, 176,  77, 154,  25,  50, 100, 200,
1121             189,  87, 174, 113, 226, 233, 255, 211, 139,  59, 118, 236, 245, 199, 163, 107,
1122             214, 129,  47,  94, 188,  85, 170, 121, 242, 201, 191,  83, 166,  97, 194, 169,
1123             127, 254, 209, 143,  51, 102, 204, 181,  71, 142,  49,  98, 196, 165, 103, 206,
1124             177,  79, 158,  17,  34,  68, 136,  61, 122, 244, 197, 167,  99, 198, 161, 111,
1125             222, 145,  15,  30,  60, 120, 240, 205, 183,  67, 134,  33,  66, 132,  37,  74,
1126             148,   5,  10,  20,  40,  80, 160, 109, 218, 153,  31,  62, 124, 248, 221, 151,
1127               3,   6,  12,  24,  48,  96, 192, 173, 119, 238, 241, 207, 179,  75, 150,   1
1128        };
1129
1130        private static final int poly5[] = {
1131             228,  48,  15, 111,  62
1132        };
1133
1134        private static final int poly7[] = {
1135              23,  68, 144, 134, 240,  92, 254
1136        };
1137
1138        private static final int poly10[] = {
1139              28,  24, 185, 166, 223, 248, 116, 255, 110,  61
1140        };
1141
1142        private static final int poly11[] = {
1143             175, 138, 205,  12, 194, 168,  39, 245,  60,  97, 120
1144        };
1145
1146        private static final int poly12[] = {
1147              41, 153, 158,  91,  61,  42, 142, 213,  97, 178, 100, 242
1148        };
1149
1150        private static final int poly14[] = {
1151             156,  97, 192, 252,  95,   9, 157, 119, 138,  45,  18, 186,  83, 185
1152        };
1153
1154        private static final int poly18[] = {
1155              83, 195, 100,  39, 188,  75,  66,  61, 241, 213, 109, 129,  94, 254, 225,  48,
1156              90, 188
1157        };
1158
1159        private static final int poly20[] = {
1160              15, 195, 244,   9, 233,  71, 168,   2, 188, 160, 153, 145, 253,  79, 108,  82,
1161              27, 174, 186, 172
1162        };
1163
1164        private static final int poly24[] = {
1165              52, 190,  88, 205, 109,  39, 176,  21, 155, 197, 251, 223, 155,  21,   5, 172,
1166             254, 124,  12, 181, 184,  96,  50, 193
1167        };
1168
1169        private static final int poly28[] = {
1170             211, 231,  43,  97,  71,  96, 103, 174,  37, 151, 170,  53,  75,  34, 249, 121,
1171              17, 138, 110, 213, 141, 136, 120, 151, 233, 168,  93, 255
1172        };
1173
1174        private static final int poly36[] = {
1175             245, 127, 242, 218, 130, 250, 162, 181, 102, 120,  84, 179, 220, 251,  80, 182,
1176             229,  18,   2,   4,  68,  33, 101, 137,  95, 119, 115,  44, 175, 184,  59,  25,
1177             225,  98,  81, 112
1178        };
1179
1180        private static final int poly42[] = {
1181              77, 193, 137,  31,  19,  38,  22, 153, 247, 105, 122,   2, 245, 133, 242,   8,
1182             175,  95, 100,   9, 167, 105, 214, 111,  57, 121,  21,   1, 253,  57,  54, 101,
1183             248, 202,  69,  50, 150, 177, 226,   5,   9,   5
1184        };
1185
1186        private static final int poly48[] = {
1187             245, 132, 172, 223,  96,  32, 117,  22, 238, 133, 238, 231, 205, 188, 237,  87,
1188             191, 106,  16, 147, 118,  23,  37,  90, 170, 205, 131,  88, 120, 100,  66, 138,
1189             186, 240,  82,  44, 176,  87, 187, 147, 160, 175,  69, 213,  92, 253, 225,  19
1190        };
1191
1192        private static final int poly56[] = {
1193             175,   9, 223, 238,  12,  17, 220, 208, 100,  29, 175, 170, 230, 192, 215, 235,
1194             150, 159,  36, 223,  38, 200, 132,  54, 228, 146, 218, 234, 117, 203,  29, 232,
1195             144, 238,  22, 150, 201, 117,  62, 207, 164,  13, 137, 245, 127,  67, 247,  28,
1196             155,  43, 203, 107, 233,  53, 143,  46
1197        };
1198
1199        private static final int poly62[] = {
1200             242,  93, 169,  50, 144, 210,  39, 118, 202, 188, 201, 189, 143, 108, 196,  37,
1201             185, 112, 134, 230, 245,  63, 197, 190, 250, 106, 185, 221, 175,  64, 114,  71,
1202             161,  44, 147,   6,  27, 218,  51,  63,  87,  10,  40, 130, 188,  17, 163,  31,
1203             176, 170,   4, 107, 232,   7,  94, 166, 224, 124,  86,  47,  11, 204
1204        };
1205
1206        private static final int poly68[] = {
1207             220, 228, 173,  89, 251, 149, 159,  56,  89,  33, 147, 244, 154,  36,  73, 127,
1208             213, 136, 248, 180, 234, 197, 158, 177,  68, 122,  93, 213,  15, 160, 227, 236,
1209              66, 139, 153, 185, 202, 167, 179,  25, 220, 232,  96, 210, 231, 136, 223, 239,
1210             181, 241,  59,  52, 172,  25,  49, 232, 211, 189,  64,  54, 108, 153, 132,  63,
1211              96, 103,  82, 186
1212        };
1213
1214        private static int[] getPoly(int nc) {
1215            switch (nc) {
1216            case 5:
1217                return poly5;
1218            case 7:
1219                return poly7;
1220            case 10:
1221                return poly10;
1222            case 11:
1223                return poly11;
1224            case 12:
1225                return poly12;
1226            case 14:
1227                return poly14;
1228            case 18:
1229                return poly18;
1230            case 20:
1231                return poly20;
1232            case 24:
1233                return poly24;
1234            case 28:
1235                return poly28;
1236            case 36:
1237                return poly36;
1238            case 42:
1239                return poly42;
1240            case 48:
1241                return poly48;
1242            case 56:
1243                return poly56;
1244            case 62:
1245                return poly62;
1246            case 68:
1247                return poly68;
1248            }
1249            return null;
1250        }
1251
1252        private static void reedSolomonBlock(byte[] wd, int nd, byte[] ncout, int nc, int[] c) {
1253            int i, j, k;
1254
1255            for (i=0; i<=nc; i++) ncout[i] = 0;
1256            for (i=0; i<nd; i++) {
1257                k = (ncout[0] ^ wd[i]) & 0xff;
1258                for (j=0; j<nc; j++) {
1259                    ncout[j] = (byte)(ncout[j+1] ^ (k == 0 ? 0 : (byte)alog[(log[k] + log[c[nc-j-1]]) % 255]));
1260                }
1261            }
1262        }
1263
1264        static void generateECC(byte[] wd, int nd, int datablock, int nc) {
1265            int blocks = (nd + 2) / datablock;
1266            int b;
1267            byte[] buf = new byte[256];
1268            byte[] ecc = new byte[256];
1269            int[] c = getPoly(nc);
1270            for (b = 0; b < blocks; b++)
1271            {
1272                int n, p = 0;
1273                for (n = b; n < nd; n += blocks)
1274                    buf[p++] = wd[n];
1275                reedSolomonBlock(buf, p, ecc, nc, c);
1276                p = 0;
1277                for (n = b; n < nc * blocks; n += blocks)
1278                    wd[nd + n] = ecc[p++];
1279            }
1280        }
1281
1282    }
1283}