package jxl.biff; import common.Logger; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.Format; import java.text.NumberFormat; import java.text.SimpleDateFormat; import jxl.WorkbookSettings; import jxl.format.Format; import jxl.read.biff.Record; public class FormatRecord extends WritableRecordData implements DisplayFormat, Format { public static Logger logger = Logger.getLogger(FormatRecord.class); private boolean initialized; private byte[] data; private int indexCode; private String formatString; private boolean date; private boolean number; private Format format; private WorkbookSettings settings; private static String[] dateStrings = new String[] { "dd", "mm", "yy", "hh", "ss", "m/", "/d" }; private static class BiffType { private BiffType() {} } public static final BiffType biff8 = new BiffType(); public static final BiffType biff7 = new BiffType(); FormatRecord(String fmt, int refno) { super(Type.FORMAT); this.formatString = fmt; this.indexCode = refno; this.initialized = true; } protected FormatRecord() { super(Type.FORMAT); this.initialized = false; } protected FormatRecord(FormatRecord fr) { super(Type.FORMAT); this.initialized = false; this.formatString = fr.formatString; this.date = fr.date; this.number = fr.number; } public FormatRecord(Record t, WorkbookSettings ws, BiffType biffType) { super(t); byte[] data = getRecord().getData(); this.indexCode = IntegerHelper.getInt(data[0], data[1]); this.initialized = true; if (biffType == biff8) { int numchars = IntegerHelper.getInt(data[2], data[3]); if (data[4] == 0) { this.formatString = StringHelper.getString(data, numchars, 5, ws); } else { this.formatString = StringHelper.getUnicodeString(data, numchars, 5); } } else { int numchars = data[2]; byte[] chars = new byte[numchars]; System.arraycopy(data, 3, chars, 0, chars.length); this.formatString = new String(chars); } this.date = false; this.number = false; for (int i = 0; i < dateStrings.length; i++) { String dateString = dateStrings[i]; if (this.formatString.indexOf(dateString) != -1 || this.formatString.indexOf(dateString.toUpperCase()) != -1) { this.date = true; break; } } if (!this.date) if (this.formatString.indexOf('#') != -1 || this.formatString.indexOf('0') != -1) this.number = true; } public byte[] getData() { this.data = new byte[this.formatString.length() * 2 + 3 + 2]; IntegerHelper.getTwoBytes(this.indexCode, this.data, 0); IntegerHelper.getTwoBytes(this.formatString.length(), this.data, 2); this.data[4] = 1; StringHelper.getUnicodeBytes(this.formatString, this.data, 5); return this.data; } public int getFormatIndex() { return this.indexCode; } public boolean isInitialized() { return this.initialized; } public void initialize(int pos) { this.indexCode = pos; this.initialized = true; } protected final String replace(String input, String search, String replace) { String fmtstr = input; int pos = fmtstr.indexOf(search); while (pos != -1) { StringBuffer tmp = new StringBuffer(fmtstr.substring(0, pos)); tmp.append(replace); tmp.append(fmtstr.substring(pos + search.length())); fmtstr = tmp.toString(); pos = fmtstr.indexOf(search); } return fmtstr; } protected final void setFormatString(String s) { this.formatString = s; } public final boolean isDate() { return this.date; } public final boolean isNumber() { return this.number; } public final NumberFormat getNumberFormat() { if (this.format != null && this.format instanceof NumberFormat) return (NumberFormat)this.format; try { String fs = this.formatString; fs = replace(fs, "E+", "E"); fs = replace(fs, "_)", ""); fs = replace(fs, "_", ""); fs = replace(fs, "[Red]", ""); fs = replace(fs, "\\", ""); this.format = new DecimalFormat(fs); } catch (IllegalArgumentException e) { this.format = new DecimalFormat("#.###"); } return (NumberFormat)this.format; } public final DateFormat getDateFormat() { if (this.format != null && this.format instanceof DateFormat) return (DateFormat)this.format; String fmt = this.formatString; int pos = fmt.indexOf("AM/PM"); while (pos != -1) { StringBuffer stringBuffer = new StringBuffer(fmt.substring(0, pos)); stringBuffer.append('a'); stringBuffer.append(fmt.substring(pos + 5)); fmt = stringBuffer.toString(); pos = fmt.indexOf("AM/PM"); } pos = fmt.indexOf("ss.0"); while (pos != -1) { StringBuffer stringBuffer = new StringBuffer(fmt.substring(0, pos)); stringBuffer.append("ss.SSS"); pos += 4; while (pos < fmt.length() && fmt.charAt(pos) == '0') pos++; stringBuffer.append(fmt.substring(pos)); fmt = stringBuffer.toString(); pos = fmt.indexOf("ss.0"); } StringBuffer sb = new StringBuffer(); for (int i = 0; i < fmt.length(); i++) { if (fmt.charAt(i) != '\\') sb.append(fmt.charAt(i)); } fmt = sb.toString(); if (fmt.charAt(0) == '[') { int end = fmt.indexOf(']'); if (end != -1) fmt = fmt.substring(end + 1); } fmt = replace(fmt, ";@", ""); char[] formatBytes = fmt.toCharArray(); for (int j = 0; j < formatBytes.length; j++) { if (formatBytes[j] == 'm') if (j > 0 && (formatBytes[j - 1] == 'm' || formatBytes[j - 1] == 'M')) { formatBytes[j] = formatBytes[j - 1]; } else { int minuteDist = Integer.MAX_VALUE; int k; for (k = j - 1; k > 0; k--) { if (formatBytes[k] == 'h') { minuteDist = j - k; break; } } for (k = j + 1; k < formatBytes.length; k++) { if (formatBytes[k] == 'h') { minuteDist = Math.min(minuteDist, k - j); break; } } for (k = j - 1; k > 0; k--) { if (formatBytes[k] == 'H') { minuteDist = j - k; break; } } for (k = j + 1; k < formatBytes.length; k++) { if (formatBytes[k] == 'H') { minuteDist = Math.min(minuteDist, k - j); break; } } for (k = j - 1; k > 0; k--) { if (formatBytes[k] == 's') { minuteDist = Math.min(minuteDist, j - k); break; } } for (k = j + 1; k < formatBytes.length; k++) { if (formatBytes[k] == 's') { minuteDist = Math.min(minuteDist, k - j); break; } } int monthDist = Integer.MAX_VALUE; int m; for (m = j - 1; m > 0; m--) { if (formatBytes[m] == 'd') { monthDist = j - m; break; } } for (m = j + 1; m < formatBytes.length; m++) { if (formatBytes[m] == 'd') { monthDist = Math.min(monthDist, m - j); break; } } for (m = j - 1; m > 0; m--) { if (formatBytes[m] == 'y') { monthDist = Math.min(monthDist, j - m); break; } } for (m = j + 1; m < formatBytes.length; m++) { if (formatBytes[m] == 'y') { monthDist = Math.min(monthDist, m - j); break; } } if (monthDist < minuteDist) { formatBytes[j] = Character.toUpperCase(formatBytes[j]); } else if (monthDist == minuteDist && monthDist != Integer.MAX_VALUE) { char ind = formatBytes[j - monthDist]; if (ind == 'y' || ind == 'd') formatBytes[j] = Character.toUpperCase(formatBytes[j]); } } } try { this.format = new SimpleDateFormat(new String(formatBytes)); } catch (IllegalArgumentException e) { this.format = new SimpleDateFormat("dd MM yyyy hh:mm:ss"); } return (DateFormat)this.format; } public int getIndexCode() { return this.indexCode; } public String getFormatString() { return this.formatString; } public boolean isBuiltIn() { return false; } public int hashCode() { return this.formatString.hashCode(); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof FormatRecord)) return false; FormatRecord fr = (FormatRecord)o; if (this.initialized && fr.initialized) { if (this.date != fr.date || this.number != fr.number) return false; return this.formatString.equals(fr.formatString); } return this.formatString.equals(fr.formatString); } }