1 58 package org.krysalis.barcode.impl; 59 60 import org.krysalis.barcode.BarGroup; 61 import org.krysalis.barcode.ChecksumMode; 62 import org.krysalis.barcode.ClassicBarcodeLogicHandler; 63 64 69 public class UPCELogicImpl extends UPCEANLogicImpl { 70 71 private static final byte O = ODD_PARITY; 72 private static final byte E = EVEN_PARITY; 73 74 private static final byte[][] NUMBER_SYSTEM_0 = 75 {{E, E, E, O, O, O}, 76 {E, E, O, E, O, O}, 77 {E, E, O, O, E, O}, 78 {E, E, O, O, O, E}, 79 {E, O, E, E, O, O}, 80 {E, O, O, E, E, O}, 81 {E, O, O, O, E, E}, 82 {E, O, E, O, E, O}, 83 {E, O, E, O, O, E}, 84 {E, O, O, E, O, E}}; 85 86 90 public UPCELogicImpl(ChecksumMode mode) { 91 super(mode); 92 } 93 94 private static final String substring(String s, int idx, int len) { 95 return s.substring(idx, idx + len); 96 } 97 98 105 public static String compactMessage(String msg) { 106 UPCALogicImpl.validateMessage(msg); 107 String upca = UPCALogicImpl.handleChecksum(msg, ChecksumMode.CP_AUTO); 108 final byte numberSystem = extractNumberSystem(upca); 109 if ((numberSystem != 0) && (numberSystem != 1)) { 110 return null; 111 } 112 final byte check = Byte.parseByte(upca.substring(11, 12)); 113 StringBuffer upce = new StringBuffer (); 114 upce.append(Byte.toString(numberSystem)); 115 try { 116 String manufacturer = substring(upca, 1, 5); 117 String product = substring(upca, 6, 5); 118 String mtemp, ptemp; 119 mtemp = substring(manufacturer, 2, 3); 121 ptemp = substring(product, 0, 2); 122 if (("000|100|200".indexOf(mtemp) >= 0) 123 && ("00".equals(ptemp))) { 124 upce.append(substring(manufacturer, 0, 2)); 125 upce.append(substring(product, 2, 3)); 126 upce.append(mtemp.charAt(0)); 127 } else { 128 ptemp = substring(product, 0, 3); 130 if (("300|400|500|600|700|800|900".indexOf(mtemp) >= 0) 131 && ("000".equals(ptemp))) { 132 upce.append(substring(manufacturer, 0, 3)); 133 upce.append(substring(product, 3, 2)); 134 upce.append("3"); 135 } else { 136 mtemp = substring(manufacturer, 3, 2); 138 ptemp = substring(product, 0, 4); 139 if (("10|20|30|40|50|60|70|80|90".indexOf(mtemp) >= 0) 140 && ("0000".equals(ptemp))) { 141 upce.append(substring(manufacturer, 0, 4)); 142 upce.append(substring(product, 4, 1)); 143 upce.append("4"); 144 } else { 145 mtemp = substring(manufacturer, 4, 1); 147 ptemp = substring(product, 4, 1); 148 if (!"0".equals(mtemp) 149 && ("5|6|7|8|9".indexOf(ptemp) >= 0)) { 150 upce.append(manufacturer); 151 upce.append(ptemp); 152 } else { 153 return null; 154 } 155 } 156 } 157 } 158 } catch (NumberFormatException nfe) { 159 return null; 160 } 161 upce.append(Byte.toString(check)); 162 return upce.toString(); 163 } 164 165 170 public static String expandMessage(String msg) { 171 char check = '\u0000'; 172 if (msg.length() == 8) { 173 check = msg.charAt(7); 174 } 175 String upce = substring(msg, 0, 7); 176 final byte numberSystem = extractNumberSystem(upce); 177 if ((numberSystem != 0) && (numberSystem != 1)) { 178 throw new IllegalArgumentException ("Invalid UPC-E message: " + msg); 179 } 180 StringBuffer upca = new StringBuffer (); 181 upca.append(Byte.toString(numberSystem)); 182 byte mode = Byte.parseByte(substring(upce, 6, 1)); 183 if ((mode >= 0) && (mode <= 2)) { 184 upca.append(substring(upce, 1, 2)); 185 upca.append(Byte.toString(mode)); 186 upca.append("0000"); 187 upca.append(substring(upce, 3, 3)); 188 } else if (mode == 3) { 189 upca.append(substring(upce, 1, 3)); 190 upca.append("00000"); 191 upca.append(substring(upce, 4, 2)); 192 } else if (mode == 4) { 193 upca.append(substring(upce, 1, 4)); 194 upca.append("00000"); 195 upca.append(substring(upce, 5, 1)); 196 } else if ((mode >= 5) && (mode <= 9)) { 197 upca.append(substring(upce, 1, 5)); 198 upca.append("0000"); 199 upca.append(Byte.toString(mode)); 200 } else { 201 throw new RuntimeException ("Internal error"); 203 } 204 String upcaFinished = upca.toString(); 205 char expectedCheck = calcChecksum(upcaFinished); 206 if ((check != '\u0000') && (check != expectedCheck)) { 207 throw new IllegalArgumentException ("Invalid checksum. Expected " 208 + expectedCheck + " but was " + check); 209 } 210 return upcaFinished + expectedCheck; 211 } 212 213 private static byte extractNumberSystem(String msg) { 214 return Byte.parseByte(msg.substring(0, 1)); 215 } 216 217 private String convertUPCAtoUPCE(String msg) { 218 if ((msg.length() == 11) || (msg.length() == 12)) { 219 final String s = compactMessage(msg); 220 if (s == null) { 221 throw new IllegalArgumentException ( 222 "UPC-A message cannot be compacted to UPC-E. Message: " + msg); 223 } 224 return s; 225 } 226 return msg; 227 } 228 229 235 public static void validateMessage(String msg) { 236 UPCEANLogicImpl.validateMessage(msg); 237 if ((msg.length() < 7) || (msg.length() > 8)) { 238 throw new IllegalArgumentException ( 239 "Message must be 7 or 8 characters long. Message: " + msg); 240 } 241 byte numberSystem = extractNumberSystem(msg); 242 if ((numberSystem < 0) || (numberSystem > 1)) { 243 throw new IllegalArgumentException ( 244 "Valid number systems for UPC-E are 0 or 1. Found: " 245 + numberSystem); 246 } 247 } 248 249 private String handleChecksum(String msg) { 250 ChecksumMode mode = getChecksumMode(); 251 if (mode == ChecksumMode.CP_AUTO) { 252 if (msg.length() == 7) { 253 mode = ChecksumMode.CP_ADD; 254 } else if (msg.length() == 8) { 255 mode = ChecksumMode.CP_CHECK; 256 } else { 257 throw new RuntimeException ("Internal error"); 259 } 260 } 261 if (mode == ChecksumMode.CP_ADD) { 262 if (msg.length() != 7) { 263 throw new IllegalArgumentException ( 264 "Message must be 7 characters long"); 265 } 266 return msg + expandMessage(msg).charAt(11); 267 } else if (mode == ChecksumMode.CP_CHECK) { 268 if (msg.length() != 8) { 269 throw new IllegalArgumentException ( 270 "Message must be 8 characters long"); 271 } 272 char check = msg.charAt(7); 273 char expected = expandMessage(msg).charAt(11); 274 if (check != expected) { 275 throw new IllegalArgumentException ( 276 "Checksum is bad (" + check + "). Expected: " + expected); 277 } 278 return msg; 279 } else if (mode == ChecksumMode.CP_IGNORE) { 280 if (msg.length() != 8) { 281 throw new IllegalArgumentException ( 282 "Message must be 8 characters long"); 283 } 284 return msg; 285 } else { 286 throw new UnsupportedOperationException ( 287 "Unknown checksum mode: " + mode); 288 } 289 } 290 291 private byte selectCharset(byte check, byte numberSystem, int position) { 292 byte charset = NUMBER_SYSTEM_0[check][position]; 293 if (numberSystem == 1) { 294 if (charset == ODD_PARITY) { 296 charset = EVEN_PARITY; 297 } else { 298 charset = ODD_PARITY; 299 } 300 } 301 return charset; 302 } 303 304 308 protected void drawUPCERightGuard(ClassicBarcodeLogicHandler logic) { 309 logic.startBarGroup(BarGroup.UPC_EAN_GUARD, null); 311 logic.addBar(false, 1); 312 logic.addBar(true, 1); 313 logic.addBar(false, 1); 314 logic.addBar(true, 1); 315 logic.addBar(false, 1); 316 logic.addBar(true, 1); 317 logic.endBarGroup(); 318 } 319 320 321 public void generateBarcodeLogic(ClassicBarcodeLogicHandler logic, String msg) { 322 String supp = retrieveSupplemental(msg); 323 String s = removeSupplemental(msg); 324 s = convertUPCAtoUPCE(s); 325 validateMessage(s); 326 s = handleChecksum(s); 327 328 String canonicalMessage = s; 329 if (supp != null) { 330 canonicalMessage = canonicalMessage + "+" + supp; 331 } 332 logic.startBarcode(canonicalMessage); 333 334 drawSideGuard(logic); 336 337 final byte numberSystem = extractNumberSystem(msg); 339 logic.startBarGroup(BarGroup.UPC_EAN_LEAD, Byte.toString(numberSystem)); 340 logic.endBarGroup(); 342 343 final byte check = Byte.parseByte(s.substring(7, 8)); 345 346 logic.startBarGroup(BarGroup.UPC_EAN_GROUP, s.substring(1, 7)); 347 348 for (int i = 1; i < 7; i++) { 350 final byte charset = selectCharset(check, numberSystem, i - 1); 351 encodeChar(logic, s.charAt(i), charset); 352 } 353 354 logic.endBarGroup(); 355 356 logic.startBarGroup(BarGroup.UPC_EAN_CHECK, Byte.toString(check)); 358 logic.endBarGroup(); 360 361 drawUPCERightGuard(logic); 363 364 if (supp != null) { 366 drawSupplemental(logic, supp); 367 } 368 logic.endBarcode(); 369 } 370 371 } 372 | Popular Tags |