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}