2001-08-31 00:30:17 +00:00
|
|
|
/**
|
|
|
|
*******************************************************************************
|
|
|
|
* Copyright (C) 1996-2001, International Business Machines Corporation and *
|
|
|
|
* others. All Rights Reserved. *
|
|
|
|
*******************************************************************************
|
|
|
|
*
|
|
|
|
* $Source: /xsrl/Nsvn/icu/unicodetools/com/ibm/text/UCD/MLStreamWriter.java,v $
|
2001-12-13 23:36:29 +00:00
|
|
|
* $Date: 2001/12/13 23:35:57 $
|
|
|
|
* $Revision: 1.3 $
|
2001-08-31 00:30:17 +00:00
|
|
|
*
|
|
|
|
*******************************************************************************
|
|
|
|
*/
|
|
|
|
|
2001-08-30 20:50:18 +00:00
|
|
|
package com.ibm.text.utility;
|
|
|
|
|
|
|
|
import java.io.*;
|
|
|
|
import java.util.*;
|
|
|
|
import com.ibm.text.UCD.*;
|
|
|
|
|
|
|
|
public class MLStreamWriter extends Writer {
|
|
|
|
public static final String copyright =
|
|
|
|
"Copyright (C) 2000, IBM Corp. and others. All Rights Reserved.";
|
|
|
|
|
|
|
|
public MLStreamWriter (PrintWriter output, boolean HTML) {
|
|
|
|
out = output;
|
|
|
|
isHTML = HTML;
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter (PrintWriter output) {
|
|
|
|
this(output,true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter el(String elementName) {
|
|
|
|
closeIfOpen();
|
|
|
|
print('<', AFTER);
|
|
|
|
print(elementName, elementName.equals("!--") ? AFTER+FORCE : AFTER);
|
|
|
|
stack.add(elementName);
|
|
|
|
inElement = true;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private MLStreamWriter closeIfOpen() {
|
|
|
|
if (inElement && !"!--".equals(stack.get(stack.size()-1))) {
|
|
|
|
print('>',BEFORE+FORCE);
|
|
|
|
}
|
|
|
|
inElement = false;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter cel(String elementName) {
|
|
|
|
return cl().tx(elementName);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter at(String attributeName, String attributeValue) {
|
|
|
|
if (!inElement) {
|
|
|
|
throw new IllegalArgumentException("attribute \"" + attributeName + "\" not in element");
|
|
|
|
}
|
|
|
|
print(' ', BOTH);
|
|
|
|
print(attributeName, AFTER);
|
|
|
|
print('=', AFTER);
|
|
|
|
print('"');
|
|
|
|
print(quoted(attributeValue));
|
|
|
|
print('"', AFTER);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter at(String attributeName, int value) {
|
|
|
|
return at(attributeName, String.valueOf(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter CR() {
|
|
|
|
closeIfOpen();
|
|
|
|
out.println();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*public MLStreamWriter comment() {
|
|
|
|
closeIfOpen();
|
|
|
|
print("<!--");
|
|
|
|
CR();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter endComment() {
|
|
|
|
print("-->");
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
public MLStreamWriter tx(String text) {
|
|
|
|
closeIfOpen();
|
|
|
|
print(quoted(text));
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter tx(char text) {
|
|
|
|
return tx(String.valueOf(text));
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter tx(int text) {
|
|
|
|
return tx(String.valueOf(text));
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter tx16(String text) {
|
|
|
|
return tx(hex(text));
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter tx16(char text) {
|
|
|
|
return tx(hex(text));
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter tx16(int text) {
|
|
|
|
return tx(hex(text));
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter cl(String closingElement) {
|
|
|
|
closeIfOpen();
|
|
|
|
String lastElement = (String)stack.remove(stack.size()-1);
|
|
|
|
if (closingElement != null && !closingElement.equals(lastElement)) {
|
|
|
|
throw new IllegalArgumentException("mismatch when closing \"" + closingElement
|
|
|
|
+ "\", current active element is \"" + lastElement + "\"");
|
|
|
|
}
|
|
|
|
if (lastElement.equals("!--")) {// hack for XML/HTML
|
|
|
|
print("-->",BEFORE+FORCE);
|
|
|
|
} else {
|
|
|
|
print("</");
|
|
|
|
print(lastElement);
|
|
|
|
print('>',BEFORE);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter cl() {
|
|
|
|
return cl(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public MLStreamWriter closeAllElements() {
|
|
|
|
for (int i = stack.size()-1; i >= 0; --i) {
|
|
|
|
cl(null);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// stream stuff
|
|
|
|
|
|
|
|
public void write(char[] source, int start, int len) {
|
|
|
|
closeIfOpen();
|
|
|
|
// later make more efficient!!
|
|
|
|
out.print(quoted(new String(source, start, len)));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void close() {
|
|
|
|
closeAllElements();
|
|
|
|
out.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void flush() {
|
|
|
|
out.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Utility methods
|
|
|
|
|
|
|
|
final public MLStreamWriter cell(String ch, String type, String codepoint, String cat) {
|
|
|
|
if (codepoint == null) codepoint = ch;
|
|
|
|
int dotpos = type.indexOf('.');
|
|
|
|
if (dotpos == -1) el(type);
|
|
|
|
else {
|
|
|
|
el(type.substring(0,dotpos));
|
|
|
|
at("class",type.substring(dotpos+1));
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
if (color == -1) {
|
|
|
|
el("th");
|
|
|
|
} else {
|
|
|
|
el("td");
|
|
|
|
if (color != 0xFFFFFF) {
|
|
|
|
at("bgcolor","#"+hex(color,6));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
tx(ch).el("br").el("tt").tx16(codepoint);
|
|
|
|
if (cat != null) tx(" ").tx(cat);
|
|
|
|
cl().cl().cl();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter cell(String ch) {
|
|
|
|
return cell(ch,"td",null,null);
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter cell(String ch, String type) {
|
|
|
|
return cell(ch,type,null,null);
|
|
|
|
}
|
|
|
|
|
|
|
|
final public MLStreamWriter cell(String ch, String type, String codepoint) {
|
|
|
|
return cell(ch,type,codepoint,null);
|
|
|
|
}
|
|
|
|
|
|
|
|
static public String hex(int i, int width) {
|
|
|
|
String result = Long.toString(i & 0xFFFFFFFFL, 16).toUpperCase();
|
|
|
|
return "00000000".substring(result.length(),width) + result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Supplies a zero-padded hex representation of an integer (without 0x)
|
|
|
|
*/
|
|
|
|
static public String hex(int i) {
|
|
|
|
return hex(i,8);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Supplies a zero-padded hex representation of a Unicode character (without 0x, \\u)
|
|
|
|
*/
|
|
|
|
static public String hex(char i) {
|
|
|
|
return hex(i,4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Supplies a zero-padded hex representation of a Unicode String (without 0x, \\u)
|
|
|
|
*@param sep can be used to give a sequence, e.g. hex("ab", ",") gives "0061,0062"
|
|
|
|
*/
|
|
|
|
static public String hex(String s, String sep) {
|
|
|
|
StringBuffer result = new StringBuffer();
|
|
|
|
for (int i = 0; i < s.length(); ++i) {
|
|
|
|
if (i != 0) result.append(sep);
|
|
|
|
result.append(hex(s.charAt(i)));
|
|
|
|
}
|
|
|
|
return result.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
static public String hex(String s) {
|
|
|
|
return hex(s," ");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void author(String name, String url) {
|
|
|
|
el("font").at("size","-3").tx("[").el("a").at("href",url).tx(name).cl("a").el("script").el("!--");
|
|
|
|
tx("document.write(', ', document.lastModified);");
|
|
|
|
cl("!--").cl("script").tx("]").cl("font");
|
|
|
|
}
|
|
|
|
|
|
|
|
// ================== PRIVATES =================
|
|
|
|
|
|
|
|
PrintWriter out;
|
|
|
|
boolean isHTML;
|
|
|
|
ArrayList stack = new ArrayList();
|
|
|
|
boolean inElement = false;
|
2001-12-13 23:36:29 +00:00
|
|
|
Normalizer formC = new Normalizer(Normalizer.NFC, "");
|
2001-08-30 20:50:18 +00:00
|
|
|
int len;
|
|
|
|
int maxLineLength = 60;
|
|
|
|
// later, add better line end management, indenting
|
|
|
|
|
|
|
|
static final int NONE=0, BEFORE=1, AFTER=2, BOTH=3, FORCE = 4; // chosen for bits!!
|
|
|
|
|
|
|
|
final void print(String s) {
|
|
|
|
print(s,NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
final void print(char c) {
|
|
|
|
print(c,NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
final void print(String s, int doesBreak) {
|
|
|
|
if ((doesBreak & BEFORE) != 0) tryBreak(s.length(), doesBreak);
|
|
|
|
len += s.length();
|
|
|
|
out.print(s);
|
|
|
|
if ((doesBreak & AFTER) != 0) tryBreak(0, doesBreak);
|
|
|
|
}
|
|
|
|
|
|
|
|
final void print(char c, int doesBreak) {
|
|
|
|
if ((doesBreak & BEFORE) != 0) tryBreak(1, doesBreak);
|
|
|
|
++len;
|
|
|
|
out.print(c);
|
|
|
|
if ((doesBreak & AFTER) != 0) tryBreak(0, doesBreak);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tryBreak(int toAdd, int doesBreak) {
|
|
|
|
if ((doesBreak & FORCE) != 0 || (len + toAdd) > maxLineLength) {
|
|
|
|
out.println();
|
|
|
|
len = stack.size();
|
|
|
|
for (int i = 0; i < len; ++i) out.print(' ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public String quoted(String source) {
|
|
|
|
source = formC.normalize(source);
|
|
|
|
StringBuffer result = new StringBuffer();
|
|
|
|
for (int i = 0; i < source.length(); ++i) {
|
|
|
|
char ch = source.charAt(i);
|
|
|
|
switch(ch) {
|
|
|
|
case '\'':
|
|
|
|
if (!isHTML) {
|
|
|
|
result.append("'");
|
|
|
|
} else {
|
|
|
|
result.append(ch);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '\"':
|
|
|
|
result.append(""");
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
result.append("<");
|
|
|
|
break;
|
|
|
|
case '&':
|
|
|
|
result.append("&");
|
|
|
|
break;
|
|
|
|
case '>':
|
|
|
|
result.append(">");
|
|
|
|
break;
|
|
|
|
case '\n': case '\r': case '\t':
|
|
|
|
result.append(ch);
|
|
|
|
break;
|
|
|
|
default: if (ch < ' ' // do surrogates later
|
|
|
|
|| ch >= '\u007F' && ch <= '\u009F'
|
|
|
|
|| ch >= '\uD800' && ch <= '\uDFFF'
|
|
|
|
|| ch >= '\uFFFE') {
|
|
|
|
result.append('\uFFFD');
|
|
|
|
} else {
|
|
|
|
result.append(ch);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|