/* Checksums.java
Purpose:
Description:
History:
Thu Feb 5 11:40:21 2004, Created by tomyeh
Copyright (C) 2004 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.util;
//NOTE: DO NOT modify the algorithm here because i3lb/HostInfo counts on it.
//If you really have to modify, you have to reserve old codes and modify
//HostInfo to call the old ones.
/**
* Checksum relevant utilities.
*
* @author tomyeh
*/
public class Checksums {
/** The default skips. */
public static final String SKIPS = "DEOX";
/** Returns a readable string plus a checksum.
*
* @param skips specifies a string of characters that shall be skipped.
* If null specified, "DEOX" is assumed. To skip nothing, specify "".
* You can only specify upper-case letters: A-Z. And, it must be in
* alphabetic order.
*/
public static final String toReadable(long val, String skips) {
if (skips == null) skips = SKIPS;
final int mod = 36 - skips.length();
if (val < 0) val = -val;
int patch = (int)val; //used to patch for 4 digits
if (patch < 0) patch = -patch;
final StringBuffer sb = new StringBuffer(32);
for (int digits = 0;;) {
if (val == 0) { //no more digit
if (digits == 4) {
digits = 0;
sb.append('-');
}
while (digits++ != 3) { //align to 4 - 1
final int v = patch % mod;
patch /= mod;
sb.append(toReadableChar(v, skips));
}
sb.append(getChecksum(sb, skips));
return sb.toString();
}
if (digits++ == 4) {
digits = 1;
sb.append('-');
}
final int v = (int)(val % mod);
val /= mod;
sb.append(toReadableChar(v, skips));
}
}
/** Returns the character of the specified val by skipping skips.
* Note: the caller must ensure val is in the right range:
* 0 - (36 - skips.length()).
*
* @param skips specifies a string of characters that shall be skipped.
* If null specified, "DEOX" is assumed. To skip nothing, specify "".
* You can only specify upper-case letters: A-Z. And, it must be in
* alphabetic order.
*/
public static final char toReadableChar(int val, String skips) {
if (val < 10)
return (char)(val + '0');
if (skips == null) skips = SKIPS;
char cc = (char)(val + ('A' - 10));
for (int j = 0, sklen = skips.length(); j < sklen; ++j) {
final char sk = skips.charAt(j);
if (cc < sk)
break;
++cc;
}
return cc;
}
/** Returns the checksum character of the specified val.
* <p>It use {@link #toReadableChar} to convert the checksum to a character.
* <p>Note: it skips '-' and ' '.
*
* @param skips specifies a string of characters that shall be skipped.
* If null specified, "DEOX" is assumed. To skip nothing, specify "".
* You can only specify upper-case letters: A-Z. And, it must be in
* alphabetic order.
*/
public static final char getChecksum(String val, String skips) {
if (skips == null) skips = SKIPS;
final int len = val.length();
int cksum = 0;
for (int j = 0; j < len; ++j) {
final char cc = val.charAt(j);
if (cc != '-' && cc != ' ')
cksum = cksum * 27 + cc;
}
if (cksum < 0) cksum = -cksum;
return toReadableChar(cksum % (36 - skips.length()), skips);
}
/** Returns the checksum character of the specified val.
* <p>It use {@link #toReadableChar} to convert the checksum to a character.
* <p>Note: it skips '-' and ' '.
*
* @param skips specifies a string of characters that shall be skipped.
* If null specified, "DEOX" is assumed. To skip nothing, specify "".
* You can only specify upper-case letters: A-Z. And, it must be in
* alphabetic order.
*/
public static final char getChecksum(StringBuffer val, String skips) {
if (skips == null) skips = SKIPS;
final int len = val.length();
int cksum = 0;
for (int j = 0; j < len; ++j) {
final char cc = val.charAt(j);
if (cc != '-' && cc != ' ')
cksum = cksum * 27 + cc;
}
if (cksum < 0) cksum = -cksum;
return toReadableChar(cksum % (36 - skips.length()), skips);
}
}