blob: 469e65ae1eb69c2ec551ee5090c0bb76edc5338d [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2002-2004, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.tool.localeconverter;
import java.io.*;
import java.util.*;
import com.ibm.icu.impl.UCharacterProperty;
/**
* A LocaleWriter takes locale data in standard form and
* writes it to standard output in a form suitable for
* loading programatically.
*/
public abstract class LocaleWriter {
private static final String INDENT_CHARS =
" "+
" "+
" ";
private static final char EOL_CHARS[] = {'\r', '\n', '\u2028', '\u2029'};
private static final int INDENT_SIZE = 4;
private static final int MAX_LINE_LENGTH = 80;
private int indentLevel;
private String indentString;
private boolean needsIndent;
protected StringBuffer lineBuffer = new StringBuffer();
private int lineLength;
protected PrintStream out;
protected PrintStream err;
//final File outFile = new File( "cnvLoc.txt");
//FileOutputStream outFileStream;
//BufferedWriter outBufWrite;
//PrintWriter myOut;
public LocaleWriter(PrintStream out) {
this.out = out;
this.err = out;
/* try{
outFile.canWrite();
outFileStream = new FileOutputStream(outFile);
outBufWrite = new BufferedWriter(new OutputStreamWriter(outFileStream,"UTF8"));
}
catch(java.io.IOException e){
System.out.println("Encoding unsupported");
return;
}
*/
}
public LocaleWriter(PrintStream out, PrintStream err) {
this.out = out;
this.err = err;
/*
try{
outFile.canWrite();
outFileStream = new FileOutputStream(outFile);
outBufWrite = new BufferedWriter(new OutputStreamWriter(outFileStream,"UTF8"));
}
catch(java.io.IOException e){
System.out.println("Encoding unsupported");
return;
}
*/
}
public void write(Locale locale, Hashtable localeData) {
open(locale);
//sort the key so the tags are in order in the resource file
SortedVector order = new SortedVector(localeData.keys(), new SortedVector.StringComparator());
Enumeration e = order.elements();
while (e.hasMoreElements()) {
final String key = (String)e.nextElement();
final Object data = localeData.get(key);
if (isDuplicateOfInheritedValue(locale, key, data)) {
println("///* Discarding duplicate data for tag: "+key+" */");
} else {
write(key, data);
}
}
close();
}
/*
public void closeFileHandle(){
try{
outBufWrite.close();
}
catch(java.io.IOException excp){
out.println("could not close the output file");
}
}
*/
protected void write(String tag, Object o) {
if (o instanceof String) {
write(tag, (String)o);
} else if (o instanceof String[]) {
write(tag, (String[]) o);
} else if (o instanceof String[][]) {
write(tag, (String[][])o);
} else if (o instanceof Object[]) {
Object[] data = (Object[])o;
String[] temp = new String[data.length];
for (int i = 0; i < data.length; i++) {
temp[i] = data[i].toString();
}
write(tag, temp);
} else if (o instanceof Object[][]) {
Object[][] data = (Object[][])o;
String[][] temp = new String[data.length][];
for (int i = 0; i < data.length; i++) {
temp[i] = new String[data[i].length];
for (int j = 0; j < temp[i].length; j++) {
temp[i][j] = data[i][j].toString();
}
}
write(tag, temp);
} else {
write(tag, o.toString());
}
}
protected final void write(String tag, String[][] value) {
if (value.length > 0) {
if (value[0].length > 2) {
write2D(tag, value);
} else {
writeTagged(tag, value);
}
} else {
writeTagged(tag, value);
}
}
protected abstract void open(Locale locale);
protected abstract void write(String tag, String value);
protected abstract void write(String tag, String[] value);
protected abstract void write2D(String tag, String[][] value);
protected abstract void writeTagged(String tag, String[][] value);
protected abstract void close();
protected abstract String getStringJoiningCharacter();
protected void tabTo(int pos) {
if (pos > lineLength) {
for (int i = lineLength; i < pos; i++) {
print(" ");
}
}
}
/*
protected void writeToFile(String str){
try{
outBufWrite.write(prependEsc(str));
}
catch(java.io.IOException e){
out.println("Could not write to file");
}
}
*/
protected void print(String val) {
if (needsIndent) {
out.print(indentString);
//writeToFile(indentString);
lineLength += indentString.length();
needsIndent = false;
}
String tval = PosixCollationBuilder.unescape(val);
if(tval.length() < val.length()){
tval=prependEsc(tval);
}
if (tval != null) {
out.print(prependEsc(tval));
//writeToFile(tval);
int len = 0;
for (int i = 0; i < EOL_CHARS.length; i++) {
len = Math.max(len, tval.lastIndexOf(EOL_CHARS[i]));
}
if (len == 0) {
lineLength += tval.length();
} else {
lineLength = tval.length() - len;
}
}
}
protected String prependEsc(String str){
StringBuffer myStr = new StringBuffer();
for(int i=0;i<str.length();i++){
char ch = str.charAt(i);
if(ch > 0x007f || ch < 0x0020){
if(ch!=0x0009){
myStr.append("\\u");
myStr.append(toHexString(ch,16,4));
}else{
myStr.append(ch);
}
}
else{
myStr.append(ch);
}
}
return myStr.toString();
}
protected String toHexString(char ch, int radix, int pad){
final int MAX_DIGITS = 10;
int length = 0;
char buffer[] = new char[10];
int num = 0;
int digit;
int j;
char temp;
int i = (int)ch;
do{
digit = (int)(i % radix);
buffer[length++]=(char)(digit<=9?(0x0030+digit):(0x0030+digit+7));
i=(i/radix);
}while(i>0);
while (length < pad){
buffer[length++] = 0x0030;/*zero padding */
}
/* null terminate the buffer */
if(length<MAX_DIGITS){
buffer[length] = 0x0000;
}
num= (pad>=length) ? pad :length;
/* Reverses the string */
for (j = 0; j < (num / 2); j++){
temp = buffer[(length-1) - j];
buffer[(length-1) - j] = buffer[j];
buffer[j] = temp;
}
return new String(buffer,0,length);
}
protected void println(String val) {
print(val);
out.println();
//writeToFile("\n");
lineLength = 0;
needsIndent = true;
}
protected void printString(String val) {
if (val != null) {
indent();
lineBuffer.setLength(0);
lineBuffer.append("\"");
final int size = val.length();
for (int i = 0; i < size; i++) {
append(val.charAt(i));
/*if (!append(val.charAt(i))) {
lineBuffer.append("\"");
lineBuffer.append(getStringJoiningCharacter());
println(lineBuffer.toString());
lineBuffer.setLength(0);
lineBuffer.append("\"");
}*/
}
lineBuffer.append("\"");
print(lineBuffer.toString());
outdent();
} else {
print("\"\"");
}
}
private boolean isSpecialChar(char ch){
if(((((ch) <= 0x002F) && ((ch) >= 0x0020)) ||
(((ch) <= 0x003F) && ((ch) >= 0x003A)) ||
(((ch) <= 0x0060) && ((ch) >= 0x005B)) ||
(((ch) <= 0x007E) && ((ch) >= 0x007D)) ||
(ch) == 0x007B)){
return true;
}
return false;
}
protected void printRuleString(String src){
String val = PosixCollationBuilder.unescape(src);
if (val != null) {
indent();
lineBuffer.setLength(0);
lineBuffer.append("\"");
final int size = val.length();
for (int i = 0; i < size; i++) {
char ch = val.charAt(i);
if(ch=='\\'){ //escape char
if(((i+1) < val.length())){
char c2 = val.charAt(i+1);
if(isSpecialChar(c2)){
// escape the escape and escape the
// special char
append('\\');
append('\\');
append('\\');
append(c2);
}else{
// write the sequence
append('\\');
append(c2);
}
}else{
// double escape the escape sequence
append('\\');
append('\\');
}
i++;
}else{
if(UCharacterProperty.isRuleWhiteSpace(ch)){
append('\\');
}
append(ch);
}
}
lineBuffer.append("\"");
print(lineBuffer.toString());
outdent();
} else {
print("\"\"");
}
}
protected void printUnquotedString(String val) {
if (val != null) {
indent();
lineBuffer.setLength(0);
//lineBuffer.append("\"");
final int size = val.length();
for (int i = 0; i < size; i++) {
append(val.charAt(i));
/*if (!append(val.charAt(i))) {
lineBuffer.append("\"");
lineBuffer.append(getStringJoiningCharacter());
println(lineBuffer.toString());
lineBuffer.setLength(0);
lineBuffer.append("\"");
}*/
}
//lineBuffer.append("\"");
print(lineBuffer.toString());
outdent();
} else {
print("");
}
}
protected boolean append(final char c) {
boolean escape = isEscapeChar(c);
if (escape) {
appendEscapedChar(c, lineBuffer);
} else {
lineBuffer.append(c);
}
return (lineLength + lineBuffer.length() < MAX_LINE_LENGTH);
}
protected boolean isEscapeChar(final char c) {
switch (c) {
case '"':
case '\\':
case '\n':
case '\r':
case '\u2028':
case '\u2029':
return true;
default:
return (c < ' ') || (c > 0x07F);
}
}
protected void appendEscapedChar(char c, StringBuffer buffer) {
if(c>=0x20 && c < 0x7f){
buffer.append(c);
}else{
buffer.append(getEscapeChar());
int value = ((int)c) & 0xFFFF;
buffer.append(HEX_DIGIT[(value & 0xF000) >> 12]);
buffer.append(HEX_DIGIT[(value & 0x0F00) >> 8]);
buffer.append(HEX_DIGIT[(value & 0x00F0) >> 4]);
buffer.append(HEX_DIGIT[(value & 0x000F)]);
}
}
protected String getEscapeChar() {
return "\\u";
}
protected final void indent() {
indent(1);
}
protected void indent(int amount) {
indentLevel += amount;
indentString = INDENT_CHARS.substring(0, indentLevel*INDENT_SIZE);
}
protected final void outdent() {
outdent(1);
}
protected void outdent(int amount) {
indentLevel -= amount;
indentString = INDENT_CHARS.substring(0, indentLevel*INDENT_SIZE);
}
static final char[] HEX_DIGIT = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'};
/** Return true if the value for the specified tag is the same
* as the value inherited from the parent for that tag */
private boolean isDuplicateOfInheritedValue(final Locale loc, String tag, Object value) {
if (value == null) return true;
try {
final ResourceBundle parentBundle = getParentBundle(loc);
if (parentBundle == null) return false;
Object parentValue = parentBundle.getObject(tag);
if (!objectsAreEqual(value, parentValue)) {
return false;
} else {
return true;
}
} catch (java.util.MissingResourceException e) {
return false;
}
}
private boolean objectsAreEqual(final Object item, final Object parentItem) {
if (item instanceof Object[] && parentItem instanceof Object[]) {
return arraysAreEqual((Object[])item, (Object[])parentItem);
} else {
return item.equals(parentItem);
}
}
private boolean arraysAreEqual(final Object[] item, final Object[] parentItem) {
boolean matches = item.length == parentItem.length;
for (int i = 0; i < item.length && matches; i++) {
matches = objectsAreEqual(item[i], parentItem[i]);
}
return matches;
}
private ResourceBundle getParentBundle(final Locale loc) {
try {
final String x = loc.toString();
final int ndx = x.lastIndexOf('_');
if (ndx < 0) {
return null;
} else {
final String parentLocName = x.substring(0, ndx);
final Locale parentLoc = localeFromString(parentLocName);
return ResourceBundle.getBundle("com.ibm.icu.dev.tool.localeconverter.myLocaleElements", parentLoc);
}
} catch (MissingResourceException e) {
return null;
}
}
private String replace(String source, String target, String replacement) {
if (target.equals(replacement)) {
return source;
} else {
StringBuffer result = new StringBuffer();
int lastNdx = 0;
int ndx = source.indexOf(target);
while (ndx >= 0) {
result.append(source.substring(lastNdx, ndx));
result.append(replacement);
ndx += target.length();
lastNdx = ndx;
ndx = source.indexOf(target, ndx);
}
result.append(source.substring(lastNdx));
return result.toString();
}
}
public Locale localeFromString(final String localeName) {
String language = localeName;
String country = "";
String variant = "";
int ndx = language.indexOf('_');
if (ndx >= 0) {
country = language.substring(ndx+1);
language = language.substring(0, ndx);
}
ndx = country.indexOf('_');
if (ndx >= 0) {
variant = country.substring(ndx);
country = country.substring(0, ndx);
}
return new Locale(language, country, variant);
}
}