Initial charset classes

This commit is contained in:
Alexey Andreev 2015-03-18 19:21:16 +04:00
parent e7db80fe2b
commit 59b2d0b21e
11 changed files with 692 additions and 0 deletions

View File

@ -0,0 +1,30 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
import org.teavm.classlib.java.lang.TRuntimeException;
/**
*
* @author Alexey Andreev
*/
public class TBufferOverflowException extends TRuntimeException {
private static final long serialVersionUID = -94154470269902198L;
public TBufferOverflowException() {
super();
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
/**
*
* @author Alexey Andreev
*/
public class TBufferUnderflowException extends RuntimeException {
private static final long serialVersionUID = 1162643612868888150L;
public TBufferUnderflowException() {
super();
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
import java.io.IOException;
/**
*
* @author Alexey Andreev
*/
public class TCharacterCodingException extends IOException {
private static final long serialVersionUID = -2432441010404243409L;
public TCharacterCodingException() {
super();
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author Alexey Andreev
*/
public abstract class TCharset implements Comparable<TCharset> {
private String canonicalName;
private String[] aliases;
private Set<String> aliasSet;
protected TCharset(String canonicalName, String[] aliases) {
this.canonicalName = canonicalName;
this.aliases = aliases.clone();
}
public static TCharset forName(String charsetName) {
return null;
}
public final String name() {
return canonicalName;
}
public final Set<String> aliases() {
if (aliasSet == null) {
aliasSet = new HashSet<>();
for (String alias : aliases) {
aliasSet.add(alias);
}
aliasSet = Collections.unmodifiableSet(aliasSet);
}
return aliasSet;
}
public String displayName() {
return canonicalName;
}
public abstract TCharsetDecoder newDecoder();
public abstract TCharsetEncoder newEncoder();
public boolean canEncode() {
return true;
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
/**
*
* @author Alexey Andreev
*/
public class TCharsetDecoder {
}

View File

@ -0,0 +1,293 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
import org.teavm.classlib.java.nio.TByteBuffer;
import org.teavm.classlib.java.nio.TCharBuffer;
/**
*
* @author Alexey Andreev
*/
public abstract class TCharsetEncoder {
private static final int READY = 0;
private static final int ONGOING = 1;
private static final int END = 2;
private static final int FLUSH = 3;
private static final int INIT = 4;
private TCharset charset;
private byte[] replacement;
private float averageBytesPerChar;
private float maxBytesPerChar;
private TCodingErrorAction malformedAction = TCodingErrorAction.REPORT;
private TCodingErrorAction unmappableAction = TCodingErrorAction.REPORT;
private int status;
private boolean finished;
protected TCharsetEncoder(TCharset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement) {
checkReplacement(replacement);
this.charset = cs;
this.replacement = replacement.clone();
this.averageBytesPerChar = averageBytesPerChar;
this.maxBytesPerChar = maxBytesPerChar;
status = INIT;
}
protected TCharsetEncoder(TCharset cs, float averageBytesPerChar, float maxBytesPerChar) {
this(cs, averageBytesPerChar, maxBytesPerChar, new byte[] { (byte)'?' });
}
public final TCharset charset() {
return charset;
}
public final byte[] replacement() {
return replacement.clone();
}
public final TCharsetEncoder replaceWith(byte[] newReplacement) {
checkReplacement(newReplacement);
this.replacement = newReplacement.clone();
implReplaceWith(newReplacement);
return this;
}
private void checkReplacement(byte[] replacement) {
if (replacement == null || replacement.length == 0 || replacement.length < maxBytesPerChar) {
throw new IllegalArgumentException("Replacement preconditions do not hold");
}
}
protected void implReplaceWith(@SuppressWarnings("unused") byte[] newReplacement) {
}
public TCodingErrorAction malformedInputAction() {
return malformedAction;
}
public final TCharsetEncoder onMalformedInput(TCodingErrorAction newAction) {
if (newAction == null) {
throw new IllegalArgumentException("Action must be non-null");
}
malformedAction = newAction;
implOnMalformedInput(newAction);
return this;
}
protected void implOnMalformedInput(@SuppressWarnings("unused") TCodingErrorAction newAction) {
}
public TCodingErrorAction unmappableCharacterAction() {
return unmappableAction;
}
public final TCharsetEncoder onUnmappableCharacter(TCodingErrorAction newAction) {
if (newAction == null) {
throw new IllegalArgumentException("Action must be non-null");
}
unmappableAction = newAction;
implOnUnmappableCharacter(newAction);
return this;
}
protected void implOnUnmappableCharacter(@SuppressWarnings("unused") TCodingErrorAction newAction) {
}
public final float averageBytesPerChar() {
return averageBytesPerChar;
}
public final float maxBytesPerChar() {
return maxBytesPerChar;
}
public final TCoderResult encode(TCharBuffer in, TByteBuffer out, boolean endOfInput) {
if (status == READY && finished && !endOfInput) {
throw new IllegalStateException();
}
if (status == FLUSH || !endOfInput && status == END) {
throw new IllegalStateException();
}
TCoderResult result;
while (true) {
try {
result = encodeLoop(in, out);
} catch (TBufferOverflowException e) {
throw new TCoderMalfunctionError(e);
} catch (TBufferUnderflowException e) {
throw new TCoderMalfunctionError(e);
}
if (result == TCoderResult.UNDERFLOW) {
status = endOfInput ? END : ONGOING;
if (endOfInput) {
int remaining = in.remaining();
if (remaining > 0) {
result = TCoderResult.malformedForLength(remaining);
} else {
return result;
}
} else {
return result;
}
} else if (result == TCoderResult.OVERFLOW) {
status = endOfInput ? END : ONGOING;
return result;
}
TCodingErrorAction action = malformedAction;
if (result.isUnmappable()) {
action = unmappableAction;
}
if (action == TCodingErrorAction.REPLACE) {
if (out.remaining() < replacement.length) {
return TCoderResult.OVERFLOW;
}
out.put(replacement);
} else {
if (action != TCodingErrorAction.IGNORE) {
return result;
}
}
in.position(in.position() + result.length());
}
}
public final TByteBuffer encode(TCharBuffer in) throws TCharacterCodingException {
if (in.remaining() == 0) {
return TByteBuffer.allocate(0);
}
reset();
int length = (int)(in.remaining() * averageBytesPerChar);
TByteBuffer output = TByteBuffer.allocate(length);
TCoderResult result = null;
while (true) {
result = encode(in, output, false);
if (result == TCoderResult.UNDERFLOW) {
break;
} else if (result == TCoderResult.OVERFLOW) {
output = allocateMore(output);
continue;
}
checkCoderResult(result);
}
result = encode(in, output, true);
checkCoderResult(result);
while (true) {
result = flush(output);
if (result == TCoderResult.UNDERFLOW) {
output.flip();
break;
} else if (result == TCoderResult.OVERFLOW) {
output = allocateMore(output);
continue;
}
checkCoderResult(result);
output.flip();
if (result.isMalformed()) {
throw new TMalformedInputException(result.length());
} else if (result.isUnmappable()) {
throw new TUnmappableCharacterException(result.length());
}
break;
}
status = READY;
finished = true;
return output;
}
protected abstract TCoderResult encodeLoop(TCharBuffer in, TByteBuffer out);
public boolean canEncode(char c) {
return implCanEncode(TCharBuffer.wrap(new char[] { c }));
}
private boolean implCanEncode(TCharBuffer cb) {
if (status == FLUSH || status == INIT) {
status = READY;
}
if (status != READY) {
throw new IllegalStateException();
}
TCodingErrorAction malformBak = malformedAction;
TCodingErrorAction unmapBak = unmappableAction;
onMalformedInput(TCodingErrorAction.REPORT);
onUnmappableCharacter(TCodingErrorAction.REPORT);
boolean result = true;
try {
encode(cb);
} catch (TCharacterCodingException e) {
result = false;
}
onMalformedInput(malformBak);
onUnmappableCharacter(unmapBak);
reset();
return result;
}
public boolean canEncode(CharSequence sequence) {
TCharBuffer cb;
if (sequence instanceof TCharBuffer) {
cb = ((TCharBuffer)sequence).duplicate();
} else {
cb = TCharBuffer.wrap(sequence);
}
return implCanEncode(cb);
}
private void checkCoderResult(TCoderResult result) throws TCharacterCodingException {
if (malformedAction == TCodingErrorAction.REPORT && result.isMalformed()) {
throw new TMalformedInputException(result.length());
} else if (unmappableAction == TCodingErrorAction.REPORT && result.isUnmappable()) {
throw new TUnmappableCharacterException(result.length());
}
}
private TByteBuffer allocateMore(TByteBuffer output) {
if (output.capacity() == 0) {
return TByteBuffer.allocate(1);
}
TByteBuffer result = TByteBuffer.allocate(output.capacity() * 2);
output.flip();
result.put(output);
return result;
}
public final TCoderResult flush(TByteBuffer out) {
if (status != END && status != READY) {
throw new IllegalStateException();
}
TCoderResult result = implFlush(out);
if (result == TCoderResult.UNDERFLOW) {
status = FLUSH;
}
return result;
}
protected TCoderResult implFlush(@SuppressWarnings("unused") TByteBuffer out) {
return TCoderResult.UNDERFLOW;
}
public final TCharsetEncoder reset() {
status = INIT;
implReset();
return this;
}
protected void implReset() {
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
/**
*
* @author Alexey Andreev
*/
public class TCoderMalfunctionError extends Error {
private static final long serialVersionUID = 8030591981317653860L;
public TCoderMalfunctionError(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
/**
*
* @author Alexey Andreev
*/
public class TCoderResult {
public static final TCoderResult UNDERFLOW = new TCoderResult((byte)0, 0);
public static final TCoderResult OVERFLOW = new TCoderResult((byte)1, 0);
private byte kind;
private int length;
TCoderResult(byte kind, int length) {
super();
this.kind = kind;
this.length = length;
}
public boolean isUnderflow() {
return kind == 0;
}
public boolean isOverflow() {
return kind == 1;
}
public boolean isError() {
return isMalformed() || isUnmappable();
}
public boolean isMalformed() {
return kind == 2;
}
public boolean isUnmappable() {
return kind == 3;
}
public int length() {
if (!isError()) {
throw new UnsupportedOperationException();
}
return length;
}
public static TCoderResult malformedForLength(int length) {
return new TCoderResult((byte)2, length);
}
public static TCoderResult unmappableForLength(int length) {
return new TCoderResult((byte)3, length);
}
public void throwException() throws TCharacterCodingException {
switch (kind) {
case 0:
throw new TBufferUnderflowException();
case 1:
throw new TBufferOverflowException();
case 2:
throw new TMalformedInputException(length);
case 3:
throw new TUnmappableCharacterException(length);
}
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
/**
*
* @author Alexey Andreev
*/
public class TCodingErrorAction {
public static final TCodingErrorAction IGNORE = new TCodingErrorAction("IGNORE");
public static final TCodingErrorAction REPLACE = new TCodingErrorAction("REPLACE");
public static final TCodingErrorAction REPORT = new TCodingErrorAction("REPORT");
private String name;
public TCodingErrorAction(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
/**
*
* @author Alexey Andreev
*/
public class TMalformedInputException extends TCharacterCodingException {
private static final long serialVersionUID = -7677315548693161814L;
private int length;
public TMalformedInputException(int length) {
this.length = length;
}
public int getLength() {
return length;
}
@Override
public String getMessage() {
return "Malformed input of length " + length;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2015 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.nio.charset;
/**
*
* @author Alexey Andreev
*/
public class TUnmappableCharacterException extends TCharacterCodingException {
private static final long serialVersionUID = 4225770757749997199L;
private int length;
public TUnmappableCharacterException(int length) {
this.length = length;
}
public int getLength() {
return length;
}
@Override
public String getMessage() {
return "Unmappable characters of length " + length;
}
}