org.krysalis.barcode4j.impl.upcean.UPCELogicImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of barcode4j-fop-ext-0.20.5-complete Show documentation
Show all versions of barcode4j-fop-ext-0.20.5-complete Show documentation
Barcode4J is a flexible generator for barcodes written in Java inclusive
extensions to support Apache FOP 0.20.5.
The newest version!
/*
* Copyright 2002-2004 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.krysalis.barcode4j.impl.upcean;
import org.krysalis.barcode4j.BarGroup;
import org.krysalis.barcode4j.ChecksumMode;
import org.krysalis.barcode4j.ClassicBarcodeLogicHandler;
/**
* This class is an implementation of the UPC-E barcode.
*
* @author Jeremias Maerki
* @version $Id: UPCELogicImpl.java,v 1.2 2004/10/24 11:45:53 jmaerki Exp $
*/
public class UPCELogicImpl extends UPCEANLogicImpl {
private static final byte O = ODD_PARITY;
private static final byte E = EVEN_PARITY;
private static final byte[][] NUMBER_SYSTEM_0 =
{{E, E, E, O, O, O},
{E, E, O, E, O, O},
{E, E, O, O, E, O},
{E, E, O, O, O, E},
{E, O, E, E, O, O},
{E, O, O, E, E, O},
{E, O, O, O, E, E},
{E, O, E, O, E, O},
{E, O, E, O, O, E},
{E, O, O, E, O, E}};
/**
* Main constructor
* @param mode the checksum mode
*/
public UPCELogicImpl(ChecksumMode mode) {
super(mode);
}
private static String substring(String s, int idx, int len) {
return s.substring(idx, idx + len);
}
/**
* Compacts an UPC-A message to an UPC-E message if possible.
* @param msg an UPC-A message
* @return String the derived UPC-E message (with checksum),
* null if the message is a valid UPC-A message but no UPC-E representation
* is possible
*/
public static String compactMessage(String msg) {
UPCALogicImpl.validateMessage(msg);
String upca = UPCALogicImpl.handleChecksum(msg, ChecksumMode.CP_AUTO);
final byte numberSystem = extractNumberSystem(upca);
if ((numberSystem != 0) && (numberSystem != 1)) {
return null;
}
final byte check = Byte.parseByte(upca.substring(11, 12));
StringBuffer upce = new StringBuffer();
upce.append(Byte.toString(numberSystem));
try {
String manufacturer = substring(upca, 1, 5);
String product = substring(upca, 6, 5);
String mtemp, ptemp;
//Rule 1
mtemp = substring(manufacturer, 2, 3);
ptemp = substring(product, 0, 2);
if (("000|100|200".indexOf(mtemp) >= 0)
&& ("00".equals(ptemp))) {
upce.append(substring(manufacturer, 0, 2));
upce.append(substring(product, 2, 3));
upce.append(mtemp.charAt(0));
} else {
//Rule 2
ptemp = substring(product, 0, 3);
if (("300|400|500|600|700|800|900".indexOf(mtemp) >= 0)
&& ("000".equals(ptemp))) {
upce.append(substring(manufacturer, 0, 3));
upce.append(substring(product, 3, 2));
upce.append("3");
} else {
//Rule 3
mtemp = substring(manufacturer, 3, 2);
ptemp = substring(product, 0, 4);
if (("10|20|30|40|50|60|70|80|90".indexOf(mtemp) >= 0)
&& ("0000".equals(ptemp))) {
upce.append(substring(manufacturer, 0, 4));
upce.append(substring(product, 4, 1));
upce.append("4");
} else {
//Rule 4
mtemp = substring(manufacturer, 4, 1);
ptemp = substring(product, 4, 1);
if (!"0".equals(mtemp)
&& ("5|6|7|8|9".indexOf(ptemp) >= 0)) {
upce.append(manufacturer);
upce.append(ptemp);
} else {
return null;
}
}
}
}
} catch (NumberFormatException nfe) {
return null;
}
upce.append(Byte.toString(check));
return upce.toString();
}
/**
* Expands an UPC-E message to an UPC-A message.
* @param msg an UPC-E message (7 or 8 characters)
* @return String the expanded UPC-A message (with checksum, 12 characters)
*/
public static String expandMessage(String msg) {
char check = '\u0000';
if (msg.length() == 8) {
check = msg.charAt(7);
}
String upce = substring(msg, 0, 7);
final byte numberSystem = extractNumberSystem(upce);
if ((numberSystem != 0) && (numberSystem != 1)) {
throw new IllegalArgumentException("Invalid UPC-E message: " + msg);
}
StringBuffer upca = new StringBuffer();
upca.append(Byte.toString(numberSystem));
byte mode = Byte.parseByte(substring(upce, 6, 1));
if ((mode >= 0) && (mode <= 2)) {
upca.append(substring(upce, 1, 2));
upca.append(Byte.toString(mode));
upca.append("0000");
upca.append(substring(upce, 3, 3));
} else if (mode == 3) {
upca.append(substring(upce, 1, 3));
upca.append("00000");
upca.append(substring(upce, 4, 2));
} else if (mode == 4) {
upca.append(substring(upce, 1, 4));
upca.append("00000");
upca.append(substring(upce, 5, 1));
} else if ((mode >= 5) && (mode <= 9)) {
upca.append(substring(upce, 1, 5));
upca.append("0000");
upca.append(Byte.toString(mode));
} else {
//Shouldn't happen
throw new RuntimeException("Internal error");
}
String upcaFinished = upca.toString();
char expectedCheck = calcChecksum(upcaFinished);
if ((check != '\u0000') && (check != expectedCheck)) {
throw new IllegalArgumentException("Invalid checksum. Expected "
+ expectedCheck + " but was " + check);
}
return upcaFinished + expectedCheck;
}
private static byte extractNumberSystem(String msg) {
return Byte.parseByte(msg.substring(0, 1));
}
private String convertUPCAtoUPCE(String msg) {
if ((msg.length() == 11) || (msg.length() == 12)) {
final String s = compactMessage(msg);
if (s == null) {
throw new IllegalArgumentException(
"UPC-A message cannot be compacted to UPC-E. Message: " + msg);
}
return s;
}
return msg;
}
/**
* Validates an UPC-E message. The message can also be UPC-A in which case
* the message is compacted to a UPC-E message if possible. If it's not
* possible an IllegalArgumentException is thrown
* @param msg the message to validate
*/
public static void validateMessage(String msg) {
UPCEANLogicImpl.validateMessage(msg);
if ((msg.length() < 7) || (msg.length() > 8)) {
throw new IllegalArgumentException(
"Message must be 7 or 8 characters long. Message: " + msg);
}
byte numberSystem = extractNumberSystem(msg);
if ((numberSystem < 0) || (numberSystem > 1)) {
throw new IllegalArgumentException(
"Valid number systems for UPC-E are 0 or 1. Found: "
+ numberSystem);
}
}
private String handleChecksum(String msg) {
ChecksumMode mode = getChecksumMode();
if (mode == ChecksumMode.CP_AUTO) {
if (msg.length() == 7) {
mode = ChecksumMode.CP_ADD;
} else if (msg.length() == 8) {
mode = ChecksumMode.CP_CHECK;
} else {
//Shouldn't happen because of validateMessage
throw new RuntimeException("Internal error");
}
}
if (mode == ChecksumMode.CP_ADD) {
if (msg.length() != 7) {
throw new IllegalArgumentException(
"Message must be 7 characters long");
}
return msg + expandMessage(msg).charAt(11);
} else if (mode == ChecksumMode.CP_CHECK) {
if (msg.length() != 8) {
throw new IllegalArgumentException(
"Message must be 8 characters long");
}
char check = msg.charAt(7);
char expected = expandMessage(msg).charAt(11);
if (check != expected) {
throw new IllegalArgumentException(
"Checksum is bad (" + check + "). Expected: " + expected);
}
return msg;
} else if (mode == ChecksumMode.CP_IGNORE) {
if (msg.length() != 8) {
throw new IllegalArgumentException(
"Message must be 8 characters long");
}
return msg;
} else {
throw new UnsupportedOperationException(
"Unknown checksum mode: " + mode);
}
}
private byte selectCharset(byte check, byte numberSystem, int position) {
byte charset = NUMBER_SYSTEM_0[check][position];
if (numberSystem == 1) {
//Number System 1 is inversion of Number System 0
if (charset == ODD_PARITY) {
charset = EVEN_PARITY;
} else {
charset = ODD_PARITY;
}
}
return charset;
}
/**
* Generates a UPC-E right guard.
* @param logic the logic handler to receive generated events
*/
protected void drawUPCERightGuard(ClassicBarcodeLogicHandler logic) {
//draw guard bars 010101
logic.startBarGroup(BarGroup.UPC_EAN_GUARD, null);
logic.addBar(false, 1);
logic.addBar(true, 1);
logic.addBar(false, 1);
logic.addBar(true, 1);
logic.addBar(false, 1);
logic.addBar(true, 1);
logic.endBarGroup();
}
/** @see org.krysalis.barcode4j.impl.upcean.UPCEANLogicImpl */
public void generateBarcodeLogic(ClassicBarcodeLogicHandler logic, String msg) {
String supp = retrieveSupplemental(msg);
String s = removeSupplemental(msg);
s = convertUPCAtoUPCE(s);
validateMessage(s);
s = handleChecksum(s);
String canonicalMessage = s;
if (supp != null) {
canonicalMessage = canonicalMessage + "+" + supp;
}
logic.startBarcode(canonicalMessage, canonicalMessage);
//Left guard
drawSideGuard(logic);
//Number system character
final byte numberSystem = extractNumberSystem(msg);
logic.startBarGroup(BarGroup.UPC_EAN_LEAD, Byte.toString(numberSystem));
//No bars, number system is implicitly encoded
logic.endBarGroup();
//Checksum
final byte check = Byte.parseByte(s.substring(7, 8));
logic.startBarGroup(BarGroup.UPC_EAN_GROUP, s.substring(1, 7));
//First five data characters
for (int i = 1; i < 7; i++) {
final byte charset = selectCharset(check, numberSystem, i - 1);
encodeChar(logic, s.charAt(i), charset);
}
logic.endBarGroup();
//Checksum
logic.startBarGroup(BarGroup.UPC_EAN_CHECK, Byte.toString(check));
//No bars, checksum is implicitly encoded
logic.endBarGroup();
//Right guard
drawUPCERightGuard(logic);
//Optional Supplemental
if (supp != null) {
drawSupplemental(logic, supp);
}
logic.endBarcode();
}
}