001: /* Checksums.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Thu Feb 5 11:40:21 2004, Created by tomyeh
010: }}IS_NOTE
011:
012: Copyright (C) 2004 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.util;
020:
021: //NOTE: DO NOT modify the algorithm here because i3lb/HostInfo counts on it.
022: //If you really have to modify, you have to reserve old codes and modify
023: //HostInfo to call the old ones.
024:
025: /**
026: * Checksum relevant utilities.
027: *
028: * @author tomyeh
029: */
030: public class Checksums {
031: /** The default skips. */
032: public static final String SKIPS = "DEOX";
033:
034: /** Returns a readable string plus a checksum.
035: *
036: * @param skips specifies a string of characters that shall be skipped.
037: * If null specified, "DEOX" is assumed. To skip nothing, specify "".
038: * You can only specify upper-case leters: A-Z. And, it must be in
039: * alphabetic order.
040: */
041: public static final String toReadable(long val, String skips) {
042: if (skips == null)
043: skips = SKIPS;
044:
045: final int mod = 36 - skips.length();
046:
047: if (val < 0)
048: val = -val;
049: int patch = (int) val; //used to patch for 4 digits
050: if (patch < 0)
051: patch = -patch;
052:
053: final StringBuffer sb = new StringBuffer(32);
054: for (int digits = 0;;) {
055: if (val == 0) { //no more digit
056: if (digits == 4) {
057: digits = 0;
058: sb.append('-');
059: }
060: while (digits++ != 3) { //align to 4 - 1
061: final int v = patch % mod;
062: patch /= mod;
063: sb.append(toReadableChar(v, skips));
064: }
065: sb.append(getChecksum(sb, skips));
066: return sb.toString();
067: }
068:
069: if (digits++ == 4) {
070: digits = 1;
071: sb.append('-');
072: }
073: final int v = (int) (val % mod);
074: val /= mod;
075: sb.append(toReadableChar(v, skips));
076: }
077: }
078:
079: /** Returns the character of the specified val by skiping skips.
080: * Note: the caller must ensure val is in the right range:
081: * 0 - (36 - skips.length()).
082: *
083: * @param skips specifies a string of characters that shall be skipped.
084: * If null specified, "DEOX" is assumed. To skip nothing, specify "".
085: * You can only specify upper-case leters: A-Z. And, it must be in
086: * alphabetic order.
087: */
088: public static final char toReadableChar(int val, String skips) {
089: if (val < 10)
090: return (char) (val + '0');
091:
092: if (skips == null)
093: skips = SKIPS;
094:
095: char cc = (char) (val + ('A' - 10));
096: for (int j = 0, sklen = skips.length(); j < sklen; ++j) {
097: final char sk = skips.charAt(j);
098: if (cc < sk)
099: break;
100: ++cc;
101: }
102: return cc;
103: }
104:
105: /** Returns the checksum character of the specified val.
106: * <p>It use {@link #toReadableChar} to convert the checksum to a character.
107: * <p>Note: it skips '-' and ' '.
108: *
109: * @param skips specifies a string of characters that shall be skipped.
110: * If null specified, "DEOX" is assumed. To skip nothing, specify "".
111: * You can only specify upper-case leters: A-Z. And, it must be in
112: * alphabetic order.
113: */
114: public static final char getChecksum(String val, String skips) {
115: if (skips == null)
116: skips = SKIPS;
117:
118: final int len = val.length();
119: int cksum = 0;
120: for (int j = 0; j < len; ++j) {
121: final char cc = val.charAt(j);
122: if (cc != '-' && cc != ' ')
123: cksum = cksum * 27 + cc;
124: }
125:
126: if (cksum < 0)
127: cksum = -cksum;
128: return toReadableChar(cksum % (36 - skips.length()), skips);
129: }
130:
131: /** Returns the checksum character of the specified val.
132: * <p>It use {@link #toReadableChar} to convert the checksum to a character.
133: * <p>Note: it skips '-' and ' '.
134: *
135: * @param skips specifies a string of characters that shall be skipped.
136: * If null specified, "DEOX" is assumed. To skip nothing, specify "".
137: * You can only specify upper-case leters: A-Z. And, it must be in
138: * alphabetic order.
139: */
140: public static final char getChecksum(StringBuffer val, String skips) {
141: if (skips == null)
142: skips = SKIPS;
143:
144: final int len = val.length();
145: int cksum = 0;
146: for (int j = 0; j < len; ++j) {
147: final char cc = val.charAt(j);
148: if (cc != '-' && cc != ' ')
149: cksum = cksum * 27 + cc;
150: }
151:
152: if (cksum < 0)
153: cksum = -cksum;
154: return toReadableChar(cksum % (36 - skips.length()), skips);
155: }
156: }
|