KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > krysalis > barcode > impl > Code39LogicImpl


1 /*
2  * $Id: Code39LogicImpl.java,v 1.6 2003/10/31 08:50:56 jmaerki Exp $
3  * ============================================================================
4  * The Krysalis Patchy Software License, Version 1.1_01
5  * Copyright (c) 2002-2003 Nicola Ken Barozzi. All rights reserved.
6  *
7  * This Licence is compatible with the BSD licence as described and
8  * approved by http://www.opensource.org/, and is based on the
9  * Apache Software Licence Version 1.1.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * 2. Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in
20  * the documentation and/or other materials provided with the
21  * distribution.
22  *
23  * 3. The end-user documentation included with the redistribution,
24  * if any, must include the following acknowledgment:
25  * "This product includes software developed for project
26  * Krysalis (http://www.krysalis.org/)."
27  * Alternately, this acknowledgment may appear in the software itself,
28  * if and wherever such third-party acknowledgments normally appear.
29  *
30  * 4. The names "Krysalis" and "Nicola Ken Barozzi" and
31  * "Krysalis Barcode" must not be used to endorse or promote products
32  * derived from this software without prior written permission. For
33  * written permission, please contact nicolaken@krysalis.org.
34  *
35  * 5. Products derived from this software may not be called "Krysalis",
36  * "Krysalis Barcode", nor may "Krysalis" appear in their name,
37  * without prior written permission of Nicola Ken Barozzi.
38  *
39  * 6. This software may contain voluntary contributions made by many
40  * individuals, who decided to donate the code to this project in
41  * respect of this licence, and was originally created by
42  * Jeremias Maerki <jeremias@maerki.org>.
43  *
44  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
45  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
47  * DISCLAIMED. IN NO EVENT SHALL THE KRYSALIS PROJECT OR
48  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
51  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
52  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
53  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
54  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  * ====================================================================
57  */

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 /**
65  * This class is an implementation of the Code39 barcode.
66  *
67  * @author Jeremias Maerki
68  * @todo Add ASCII-7bit encoding table
69  */

70 public class Code39LogicImpl {
71
72     private static final char[] CHARACTERS =
73                         {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
74                          'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
75                          'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
76                          'U', 'V', 'W', 'X', 'Y', 'Z',
77                          '-', '.', ' ', '$', '/', '+', '%', '*'};
78
79     private static final char STARTSTOP = '*'; //Not used as normal character
80

81     private static final byte[][] CHARSET =
82                         {{0, 0, 0, 1, 1, 0, 1, 0, 0}, //0
83
{1, 0, 0, 1, 0, 0, 0, 0, 1}, //1
84
{0, 0, 1, 1, 0, 0, 0, 0, 1}, //2
85
{1, 0, 1, 1, 0, 0, 0, 0, 0}, //3
86
{0, 0, 0, 1, 1, 0, 0, 0, 1}, //4
87
{1, 0, 0, 1, 1, 0, 0, 0, 0}, //5
88
{0, 0, 1, 1, 1, 0, 0, 0, 0}, //6
89
{0, 0, 0, 1, 0, 0, 1, 0, 1}, //7
90
{1, 0, 0, 1, 0, 0, 1, 0, 0}, //8
91
{0, 0, 1, 1, 0, 0, 1, 0, 0}, //9
92
{1, 0, 0, 0, 0, 1, 0, 0, 1}, //A
93
{0, 0, 1, 0, 0, 1, 0, 0, 1}, //B
94
{1, 0, 1, 0, 0, 1, 0, 0, 0}, //C
95
{0, 0, 0, 0, 1, 1, 0, 0, 1}, //D
96
{1, 0, 0, 0, 1, 1, 0, 0, 0}, //E
97
{0, 0, 1, 0, 1, 1, 0, 0, 0}, //F
98
{0, 0, 0, 0, 0, 1, 1, 0, 1}, //G
99
{1, 0, 0, 0, 0, 1, 1, 0, 0}, //H
100
{0, 0, 1, 0, 0, 1, 1, 0, 0}, //I
101
{0, 0, 0, 0, 1, 1, 1, 0, 0}, //J
102
{1, 0, 0, 0, 0, 0, 0, 1, 1}, //K
103
{0, 0, 1, 0, 0, 0, 0, 1, 1}, //L
104
{1, 0, 1, 0, 0, 0, 0, 1, 0}, //M
105
{0, 0, 0, 0, 1, 0, 0, 1, 1}, //N
106
{1, 0, 0, 0, 1, 0, 0, 1, 0}, //O
107
{0, 0, 1, 0, 1, 0, 0, 1, 0}, //P
108
{0, 0, 0, 0, 0, 0, 1, 1, 1}, //Q
109
{1, 0, 0, 0, 0, 0, 1, 1, 0}, //R
110
{0, 0, 1, 0, 0, 0, 1, 1, 0}, //S
111
{0, 0, 0, 0, 1, 0, 1, 1, 0}, //T
112
{1, 1, 0, 0, 0, 0, 0, 0, 1}, //U
113
{0, 1, 1, 0, 0, 0, 0, 0, 1}, //V
114
{1, 1, 1, 0, 0, 0, 0, 0, 0}, //W
115
{0, 1, 0, 0, 1, 0, 0, 0, 1}, //X
116
{1, 1, 0, 0, 1, 0, 0, 0, 0}, //Y
117
{0, 1, 1, 0, 1, 0, 0, 0, 0}, //Z
118
{0, 1, 0, 0, 0, 0, 1, 0, 1}, //-
119
{1, 1, 0, 0, 0, 0, 1, 0, 0}, //.
120
{0, 1, 1, 0, 0, 0, 1, 0, 0}, //SP
121
{0, 1, 0, 1, 0, 1, 0, 0, 0}, //$
122
{0, 1, 0, 1, 0, 0, 0, 1, 0}, //"/"
123
{0, 1, 0, 0, 0, 1, 0, 1, 0}, //+
124
{0, 0, 0, 1, 0, 1, 0, 1, 0}, //%
125
{0, 1, 0, 0, 1, 0, 1, 0, 0}}; //*
126

127     private ChecksumMode checksumMode = ChecksumMode.CP_AUTO;
128     
129
130     /**
131      * Main constructor
132      * @param mode checksum mode
133      */

134     public Code39LogicImpl(ChecksumMode mode) {
135         this.checksumMode = mode;
136     }
137
138     /**
139      * Returns the currently active checksum mode.
140      * @return the checksum mode
141      */

142     public ChecksumMode getChecksumMode() {
143         return this.checksumMode;
144     }
145
146     /**
147      * Calculates the checksum for a message to be encoded as an
148      * Code39 barcode.
149      * @param msg message to calculate the check digit for
150      * @return char the check digit
151      */

152     public static char calcChecksum(String JavaDoc msg) {
153         int checksum = 0;
154         for (int i = 0; i < msg.length(); i++) {
155             final int chidx = getCharIndex(msg.charAt(i));
156             if (chidx >= 0) {
157                 checksum += chidx;
158             } else {
159                 throw new IllegalArgumentException JavaDoc("Invalid character: " + msg.charAt(i));
160             }
161         }
162         return CHARACTERS[checksum % 43];
163     }
164
165
166     /**
167      * Verifies the checksum for a message.
168      * @param msg message (check digit included)
169      * @return boolean True, if the checksum is correct
170      */

171     public static boolean validateChecksum(String JavaDoc msg) {
172         char actual = msg.charAt(msg.length() - 1);
173         char expected = calcChecksum(msg.substring(0, msg.length() - 1));
174         return (actual == expected);
175     }
176
177     private static int getCharIndex(char ch) {
178         final char effch;
179         if ((ch >= 'a') && (ch <= 'z')) {
180             effch = Character.toUpperCase(ch);
181         } else {
182             effch = ch;
183         }
184         for (int i = 0; i < CHARACTERS.length; i++) {
185             if (effch == CHARACTERS[i]) {
186                 return i;
187             }
188         }
189         return -1;
190     }
191
192
193     private static boolean isValidChar(char ch) {
194         if (ch == STARTSTOP) return false;
195         return (getCharIndex(ch) >= 0);
196     }
197
198     private int widthAt(char ch, int index) {
199         final int chidx = getCharIndex(ch);
200         if (chidx >= 0) {
201             int binary = CHARSET[chidx][index];
202             return binary + 1;
203         } else {
204             throw new IllegalArgumentException JavaDoc("Invalid character: " + ch);
205         }
206     }
207
208     /**
209      * Encodes a single character.
210      * @param logic the logic handler to receive generated events
211      * @param c the character to encode
212      */

213     protected void encodeChar(ClassicBarcodeLogicHandler logic, char c) {
214         logic.startBarGroup(BarGroup.MSG_CHARACTER, new Character JavaDoc(c).toString());
215         for (byte i = 0; i < 9; i++) {
216             int width = widthAt(c, i);
217             boolean black = (i % 2 == 0);
218             logic.addBar(black, width);
219         }
220         logic.endBarGroup();
221     }
222
223     private void addIntercharacterGap(ClassicBarcodeLogicHandler logic) {
224         //Add intercharacter gap (currently assumed to be narrow width)
225
logic.addBar(false, -1); //-1 is special
226
}
227         
228     private void handleChecksum(StringBuffer JavaDoc sb) {
229         if (getChecksumMode() == ChecksumMode.CP_ADD) {
230             sb.append(calcChecksum(sb.toString()));
231         } else if (getChecksumMode() == ChecksumMode.CP_CHECK) {
232             if (!validateChecksum(sb.toString())) {
233                 throw new IllegalArgumentException JavaDoc("Message '"
234                     + sb.toString()
235                     + "' has a bad checksum. Expected: "
236                     + calcChecksum(sb.toString()));
237             }
238         } else if (getChecksumMode() == ChecksumMode.CP_IGNORE) {
239             return;
240         } else if (getChecksumMode() == ChecksumMode.CP_AUTO) {
241             return; //equals ignore
242
}
243     }
244
245     /**
246      * Generates the barcode logic
247      * @param logic the logic handler to receive generated events
248      * @param msg the message to encode
249      */

250     public void generateBarcodeLogic(ClassicBarcodeLogicHandler logic, String JavaDoc msg) {
251         logic.startBarcode(msg);
252
253         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(msg);
254         
255         //Checksum handling as requested
256
handleChecksum(sb);
257
258         //Start character
259
logic.startBarGroup(BarGroup.START_CHARACTER, new Character JavaDoc(STARTSTOP).toString());
260         encodeChar(logic, STARTSTOP);
261         logic.endBarGroup();
262
263         for (int i = 0; i < sb.length(); i++) {
264             addIntercharacterGap(logic);
265             
266             final char ch = sb.charAt(i);
267             if (!isValidChar(ch)) throw new IllegalArgumentException JavaDoc("Invalid character: " + ch);
268             encodeChar(logic, ch);
269         }
270
271         addIntercharacterGap(logic);
272
273         //Start character
274
logic.startBarGroup(BarGroup.STOP_CHARACTER, new Character JavaDoc(STARTSTOP).toString());
275         encodeChar(logic, STARTSTOP);
276         logic.endBarGroup();
277
278         logic.endBarcode();
279     }
280
281
282 }
283
Popular Tags