0
0
mirror of https://github.com/thunderbird/thunderbird-android.git synced 2024-09-20 12:12:15 +02:00

Replaced local version of jutf7 with a homebuilt jar from:

URL: https://jutf7.svn.sourceforge.net/svnroot/jutf7/trunk
Repository Root: https://jutf7.svn.sourceforge.net/svnroot/jutf7
Repository UUID: 1064e9db-3825-0410-a553-84549dc1c2c0
Revision: 20
Last Changed Author: jtbeetstra
Last Changed Rev: 20
Last Changed Date: 2010-04-22 11:31:16 -0400 (Thu, 22 Apr 2010)
This commit is contained in:
Jesse Vincent 2011-01-31 18:25:52 +00:00
parent 2ce5b9ed03
commit 4cc114c568
9 changed files with 1 additions and 868 deletions

View File

@ -6,6 +6,7 @@
<classpathentry exported="true" kind="lib" path="libs/apache-mime4j-core-0.7-SNAPSHOT.jar"/>
<classpathentry exported="true" kind="lib" path="libs/apache-mime4j-dom-0.7-SNAPSHOT.jar"/>
<classpathentry kind="lib" path="libs/commons-io-2.0.1.jar"/>
<classpathentry kind="lib" path="libs/jutf7-1.0.1-SNAPSHOT.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/compile-only-libs"/>
<classpathentry kind="output" path="bin"/>
</classpath>

Binary file not shown.

View File

@ -1,117 +0,0 @@
/* ====================================================================
* Copyright (c) 2006 J.T. Beetstra
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================================
*/
package com.beetstra.jutf7;
import java.util.Arrays;
/**
* <p>
* Represent a base 64 mapping. The 64 characters used in the encoding can be
* specified, since modified-UTF-7 uses other characters than UTF-7 (',' instead
* of '/').
* </p>
* <p>
* The exact type of the arguments and result values is adapted to the needs of
* the encoder and decoder, as opposed to following a strict interpretation of
* base 64.
* </p>
* <p>
* Base 64, as specified in RFC 2045, is an encoding used to encode bytes as
* characters. In (modified-)UTF-7 however, it is used to encode characters as
* bytes, using some intermediate steps:
* </p>
* <ol>
* <li>Encode all characters as a 16-bit (UTF-16) integer value</li>
* <li>Write this as stream of bytes (most-significant first)</li>
* <li>Encode these bytes using (modified) base 64 encoding</li>
* <li>Write the thus formed stream of characters as a stream of bytes, using
* ASCII encoding</li>
* </ol>
*
* @author Jaap Beetstra
*/
class Base64Util {
private static final int ALPHABET_LENGTH = 64;
private final char[] alphabet;
private final int[] inverseAlphabet;
/**
* Initializes the class with the specified encoding/decoding alphabet.
*
* @param alphabet
* @throws IllegalArgumentException if alphabet is not 64 characters long or
* contains characters which are not 7-bit ASCII
*/
Base64Util(final String alphabet) {
this.alphabet = alphabet.toCharArray();
if (alphabet.length() != ALPHABET_LENGTH)
throw new IllegalArgumentException("alphabet has incorrect length (should be 64, not "
+ alphabet.length() + ")");
inverseAlphabet = new int[128];
Arrays.fill(inverseAlphabet, -1);
for (int i = 0; i < this.alphabet.length; i++) {
final char ch = this.alphabet[i];
if (ch >= 128)
throw new IllegalArgumentException("invalid character in alphabet: " + ch);
inverseAlphabet[ch] = i;
}
}
/**
* Returns the integer value of the six bits represented by the specified
* character.
*
* @param ch The character, as a ASCII encoded byte
* @return The six bits, as an integer value, or -1 if the byte is not in
* the alphabet
*/
int getSextet(final byte ch) {
if (ch >= 128)
return -1;
return inverseAlphabet[ch];
}
/**
* Tells whether the alphabet contains the specified character.
*
* @param ch The character
* @return true if the alphabet contains <code>ch</code>, false otherwise
*/
boolean contains(final char ch) {
if (ch >= 128)
return false;
return inverseAlphabet[ch] >= 0;
}
/**
* Encodes the six bit group as a character.
*
* @param sextet The six bit group to be encoded
* @return The ASCII value of the character
*/
byte getChar(final int sextet) {
return (byte)alphabet[sextet];
}
}

View File

@ -1,90 +0,0 @@
/* ====================================================================
* Copyright (c) 2006 J.T. Beetstra
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================================
*/
package com.beetstra.jutf7;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* <p>
* Charset service-provider class used for both variants of the UTF-7 charset
* and the modified-UTF-7 charset.
* </p>
*
* @author Jaap Beetstra
*/
public class CharsetProvider extends java.nio.charset.spi.CharsetProvider {
private static final String UTF7_NAME = "UTF-7";
private static final String UTF7_O_NAME = "X-UTF-7-OPTIONAL";
private static final String UTF7_M_NAME = "X-MODIFIED-UTF-7";
private static final String[] UTF7_ALIASES = new String[] {
"UNICODE-1-1-UTF-7", "CSUNICODE11UTF7", "X-RFC2152", "X-RFC-2152"
};
private static final String[] UTF7_O_ALIASES = new String[] {
"X-RFC2152-OPTIONAL", "X-RFC-2152-OPTIONAL"
};
private static final String[] UTF7_M_ALIASES = new String[] {
"X-IMAP-MODIFIED-UTF-7", "X-IMAP4-MODIFIED-UTF7", "X-IMAP4-MODIFIED-UTF-7",
"X-RFC3501", "X-RFC-3501"
};
private Charset utf7charset = new UTF7Charset(UTF7_NAME, UTF7_ALIASES, false);
private Charset utf7oCharset = new UTF7Charset(UTF7_O_NAME, UTF7_O_ALIASES, true);
private Charset imap4charset = new ModifiedUTF7Charset(UTF7_M_NAME, UTF7_M_ALIASES);
private List charsets;
public CharsetProvider() {
charsets = Arrays.asList(new Object[] {
utf7charset, imap4charset, utf7oCharset
});
}
/**
* {@inheritDoc}
*/
public Charset charsetForName(String charsetName) {
charsetName = charsetName.toUpperCase();
for (Iterator iter = charsets.iterator(); iter.hasNext();) {
Charset charset = (Charset)iter.next();
if (charset.name().equals(charsetName))
return charset;
}
for (Iterator iter = charsets.iterator(); iter.hasNext();) {
Charset charset = (Charset)iter.next();
if (charset.aliases().contains(charsetName))
return charset;
}
return null;
}
/**
* {@inheritDoc}
*/
public Iterator charsets() {
return charsets.iterator();
}
}

View File

@ -1,57 +0,0 @@
/* ====================================================================
* Copyright (c) 2006 J.T. Beetstra
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================================
*/
package com.beetstra.jutf7;
/**
* <p>
* The character set specified in RFC 3501 to use for IMAP4rev1 mailbox name
* encoding.
* </p>
*
* @see <a href="http://tools.ietf.org/html/rfc3501">RFC 3501< /a>
* @author Jaap Beetstra
*/
class ModifiedUTF7Charset extends UTF7StyleCharset {
private static final String MODIFIED_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz" + "0123456789+,";
ModifiedUTF7Charset(String name, String[] aliases) {
super(name, aliases, MODIFIED_BASE64_ALPHABET, true);
}
boolean canEncodeDirectly(char ch) {
if (ch == shift())
return false;
return ch >= 0x20 && ch <= 0x7E;
}
byte shift() {
return '&';
}
byte unshift() {
return '-';
}
}

View File

@ -1,75 +0,0 @@
/* ====================================================================
* Copyright (c) 2006 J.T. Beetstra
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================================
*/
package com.beetstra.jutf7;
/**
* <p>
* The character set specified in RFC 2152. Two variants are supported using the
* encodeOptional constructor flag
* </p>
*
* @see <a href="http://tools.ietf.org/html/rfc2152">RFC 2152< /a>
* @author Jaap Beetstra
*/
class UTF7Charset extends UTF7StyleCharset {
private static final String BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz" + "0123456789+/";
private static final String SET_D = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?";
private static final String SET_O = "!\"#$%&*;<=>@[]^_`{|}";
private static final String RULE_3 = " \t\r\n";
final String directlyEncoded;
UTF7Charset(String name, String[] aliases, boolean includeOptional) {
super(name, aliases, BASE64_ALPHABET, false);
if (includeOptional)
this.directlyEncoded = SET_D + SET_O + RULE_3;
else
this.directlyEncoded = SET_D + RULE_3;
}
/*
* (non-Javadoc)
* @see com.beetstra.jutf7.UTF7StyleCharset#canEncodeDirectly(char)
*/
boolean canEncodeDirectly(char ch) {
return directlyEncoded.indexOf(ch) >= 0;
}
/*
* (non-Javadoc)
* @see com.beetstra.jutf7.UTF7StyleCharset#shift()
*/
byte shift() {
return '+';
}
/*
* (non-Javadoc)
* @see com.beetstra.jutf7.UTF7StyleCharset#unshift()
*/
byte unshift() {
return '-';
}
}

View File

@ -1,117 +0,0 @@
/* ====================================================================
* Copyright (c) 2006 J.T. Beetstra
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================================
*/
package com.beetstra.jutf7;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.Arrays;
import java.util.List;
/**
* <p>
* Abstract base class for UTF-7 style encoding and decoding.
* </p>
*
* @author Jaap Beetstra
*/
abstract class UTF7StyleCharset extends Charset {
private static final List CONTAINED = Arrays.asList(new String[] {
"US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16", "UTF-16LE", "UTF-16BE"
});
final boolean strict;
Base64Util base64;
/**
* <p>
* Besides the name and aliases, two additional parameters are required.
* First the base 64 alphabet used; in modified UTF-7 a slightly different
* alphabet is used. Additionally, it should be specified if encoders and
* decoders should be strict about the interpretation of malformed encoded
* sequences. This is used since modified UTF-7 specifically disallows some
* constructs which are allowed (or not specifically disallowed) in UTF-7
* (RFC 2152).
* </p>
*
* @param canonicalName The name as defined in java.nio.charset.Charset
* @param aliases The aliases as defined in java.nio.charset.Charset
* @param alphabet The base 64 alphabet used
* @param strict True if strict handling of sequences is requested
*/
protected UTF7StyleCharset(String canonicalName, String[] aliases, String alphabet,
boolean strict) {
super(canonicalName, aliases);
this.base64 = new Base64Util(alphabet);
this.strict = strict;
}
/*
* (non-Javadoc)
* @see java.nio.charset.Charset#contains(java.nio.charset.Charset)
*/
public boolean contains(final Charset cs) {
return CONTAINED.contains(cs.name());
}
/*
* (non-Javadoc)
* @see java.nio.charset.Charset#newDecoder()
*/
public CharsetDecoder newDecoder() {
return new UTF7StyleCharsetDecoder(this, base64, strict);
}
/*
* (non-Javadoc)
* @see java.nio.charset.Charset#newEncoder()
*/
public CharsetEncoder newEncoder() {
return new UTF7StyleCharsetEncoder(this, base64, strict);
}
/**
* Tells if a character can be encoded using simple (US-ASCII) encoding or
* requires base 64 encoding.
*
* @param ch The character
* @return True if the character can be encoded directly, false otherwise
*/
abstract boolean canEncodeDirectly(char ch);
/**
* Returns character used to switch to base 64 encoding.
*
* @return The shift character
*/
abstract byte shift();
/**
* Returns character used to switch from base 64 encoding to simple
* encoding.
*
* @return The unshift character
*/
abstract byte unshift();
}

View File

@ -1,195 +0,0 @@
/* ====================================================================
* Copyright (c) 2006 J.T. Beetstra
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================================
*/
package com.beetstra.jutf7;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
/**
* <p>
* The CharsetDecoder used to decode both variants of the UTF-7 charset and the
* modified-UTF-7 charset.
* </p>
*
* @author Jaap Beetstra
*/
class UTF7StyleCharsetDecoder extends CharsetDecoder {
private final Base64Util base64;
private final byte shift;
private final byte unshift;
private final boolean strict;
private boolean base64mode;
private int bitsRead;
private int tempChar;
private boolean justShifted;
private boolean justUnshifted;
UTF7StyleCharsetDecoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) {
super(cs, 0.6f, 1.0f);
this.base64 = base64;
this.strict = strict;
this.shift = cs.shift();
this.unshift = cs.unshift();
}
/*
* (non-Javadoc)
* @see java.nio.charset.CharsetDecoder#decodeLoop(java.nio.ByteBuffer,
* java.nio.CharBuffer)
*/
protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
while (in.hasRemaining()) {
byte b = in.get();
if (base64mode) {
if (b == unshift) {
if (base64bitsWaiting())
return malformed(in);
if (justShifted) {
if (!out.hasRemaining())
return overflow(in);
out.put((char)shift);
} else
justUnshifted = true;
setUnshifted();
} else {
if (!out.hasRemaining())
return overflow(in);
CoderResult result = handleBase64(in, out, b);
if (result != null)
return result;
}
justShifted = false;
} else {
if (b == shift) {
base64mode = true;
if (justUnshifted && strict)
return malformed(in);
justShifted = true;
continue;
}
if (!out.hasRemaining())
return overflow(in);
out.put((char)b);
justUnshifted = false;
}
}
return CoderResult.UNDERFLOW;
}
private CoderResult overflow(ByteBuffer in) {
in.position(in.position() - 1);
return CoderResult.OVERFLOW;
}
/**
* <p>
* Decodes a byte in <i>base 64 mode</i>. Will directly write a character to
* the output buffer if completed.
* </p>
*
* @param in The input buffer
* @param out The output buffer
* @param lastRead Last byte read from the input buffer
* @return CoderResult.malformed if a non-base 64 character was encountered
* in strict mode, null otherwise
*/
private CoderResult handleBase64(ByteBuffer in, CharBuffer out, byte lastRead) {
CoderResult result = null;
int sextet = base64.getSextet(lastRead);
if (sextet >= 0) {
bitsRead += 6;
if (bitsRead < 16) {
tempChar += sextet << (16 - bitsRead);
} else {
bitsRead -= 16;
tempChar += sextet >> (bitsRead);
out.put((char)tempChar);
tempChar = (sextet << (16 - bitsRead)) & 0xFFFF;
}
} else {
if (strict)
return malformed(in);
out.put((char)lastRead);
if (base64bitsWaiting())
result = malformed(in);
setUnshifted();
}
return result;
}
/*
* (non-Javadoc)
* @see java.nio.charset.CharsetDecoder#implFlush(java.nio.CharBuffer)
*/
protected CoderResult implFlush(CharBuffer out) {
if ((base64mode && strict) || base64bitsWaiting())
return CoderResult.malformedForLength(1);
return CoderResult.UNDERFLOW;
}
/*
* (non-Javadoc)
* @see java.nio.charset.CharsetDecoder#implReset()
*/
protected void implReset() {
setUnshifted();
justUnshifted = false;
}
/**
* <p>
* Resets the input buffer position to just before the last byte read, and
* returns a result indicating to skip the last byte.
* </p>
*
* @param in The input buffer
* @return CoderResult.malformedForLength(1);
*/
private CoderResult malformed(ByteBuffer in) {
in.position(in.position() - 1);
return CoderResult.malformedForLength(1);
}
/**
* @return True if there are base64 encoded characters waiting to be written
*/
private boolean base64bitsWaiting() {
return tempChar != 0 || bitsRead >= 6;
}
/**
* <p>
* Updates internal state to reflect the decoder is no longer in <i>base 64
* mode</i>
* </p>
*/
private void setUnshifted() {
base64mode = false;
bitsRead = 0;
tempChar = 0;
}
}

View File

@ -1,217 +0,0 @@
/* ====================================================================
* Copyright (c) 2006 J.T. Beetstra
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================================
*/
package com.beetstra.jutf7;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
/**
* <p>
* The CharsetEncoder used to encode both variants of the UTF-7 charset and the
* modified-UTF-7 charset.
* </p>
* <p>
* <strong>Please note this class does not behave strictly according to the
* specification in Sun Java VMs before 1.6.</strong> This is done to get around
* a bug in the implementation of
* {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)}. Unfortunately,
* that method cannot be overridden.
* </p>
*
* @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6221056">JDK
* bug 6221056< /a>
* @author Jaap Beetstra
*/
class UTF7StyleCharsetEncoder extends CharsetEncoder {
private static final float AVG_BYTES_PER_CHAR = 1.5f;
private static final float MAX_BYTES_PER_CHAR = 5.0f;
private final UTF7StyleCharset cs;
private final Base64Util base64;
private final byte shift;
private final byte unshift;
private final boolean strict;
private boolean base64mode;
private int bitsToOutput;
private int sextet;
static boolean useUglyHackToForceCallToFlushInJava5;
static {
String version = System.getProperty("java.specification.version");
String vendor = System.getProperty("java.vm.vendor");
useUglyHackToForceCallToFlushInJava5 = "1.4".equals(version) || "1.5".equals(version);
useUglyHackToForceCallToFlushInJava5 &= "Sun Microsystems Inc.".equals(vendor);
}
UTF7StyleCharsetEncoder(UTF7StyleCharset cs, Base64Util base64, boolean strict) {
super(cs, AVG_BYTES_PER_CHAR, MAX_BYTES_PER_CHAR);
this.cs = cs;
this.base64 = base64;
this.strict = strict;
this.shift = cs.shift();
this.unshift = cs.unshift();
}
/*
* (non-Javadoc)
* @see java.nio.charset.CharsetEncoder#implReset()
*/
protected void implReset() {
base64mode = false;
sextet = 0;
bitsToOutput = 0;
}
/**
* {@inheritDoc}
* <p>
* Note that this method might return <code>CoderResult.OVERFLOW</code> (as
* is required by the specification) if insufficient space is available in
* the output buffer. However, calling it again on JDKs before Java 6
* triggers a bug in
* {@link java.nio.charset.CharsetEncoder#flush(ByteBuffer)} causing it to
* throw an IllegalStateException (the buggy method is <code>final</code>,
* thus cannot be overridden).
* </p>
*
* @see <a
* href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6227608">
* JDK bug 6227608< /a>
* @param out The output byte buffer
* @return A coder-result object describing the reason for termination
*/
protected CoderResult implFlush(ByteBuffer out) {
if (base64mode) {
if (out.remaining() < 2)
return CoderResult.OVERFLOW;
if (bitsToOutput != 0)
out.put(base64.getChar(sextet));
out.put(unshift);
}
return CoderResult.UNDERFLOW;
}
/**
* {@inheritDoc}
* <p>
* Note that this method might return <code>CoderResult.OVERFLOW</code>,
* even though there is sufficient space available in the output buffer.
* This is done to force the broken implementation of
* {@link java.nio.charset.CharsetEncoder#encode(CharBuffer)} to call flush
* (the buggy method is <code>final</code>, thus cannot be overridden).
* </p>
* <p>
* However, String.getBytes() fails if CoderResult.OVERFLOW is returned,
* since this assumes it always allocates sufficient bytes (maxBytesPerChar
* * nr_of_chars). Thus, as an extra check, the size of the input buffer is
* compared against the size of the output buffer. A static variable is used
* to indicate if a broken java version is used.
* </p>
* <p>
* It is not possible to directly write the last few bytes, since more bytes
* might be waiting to be encoded then those available in the input buffer.
* </p>
*
* @see <a
* href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6221056">
* JDK bug 6221056< /a>
* @param in The input character buffer
* @param out The output byte buffer
* @return A coder-result object describing the reason for termination
*/
protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
while (in.hasRemaining()) {
if (out.remaining() < 4)
return CoderResult.OVERFLOW;
char ch = in.get();
if (cs.canEncodeDirectly(ch)) {
unshift(out, ch);
out.put((byte)ch);
} else if (!base64mode && ch == shift) {
out.put(shift);
out.put(unshift);
} else
encodeBase64(ch, out);
}
/*
* <HACK type="ugly"> These lines are required to trick JDK 1.5 and
* earlier into flushing when using Charset.encode(String),
* Charset.encode(CharBuffer) or CharsetEncoder.encode(CharBuffer)
* Without them, the last few bytes may be missing.
*/
if (base64mode && useUglyHackToForceCallToFlushInJava5
&& out.limit() != MAX_BYTES_PER_CHAR * in.limit())
return CoderResult.OVERFLOW;
/* </HACK> */
return CoderResult.UNDERFLOW;
}
/**
* <p>
* Writes the bytes necessary to leave <i>base 64 mode</i>. This might
* include an unshift character.
* </p>
*
* @param out
* @param ch
*/
private void unshift(ByteBuffer out, char ch) {
if (!base64mode)
return;
if (bitsToOutput != 0)
out.put(base64.getChar(sextet));
if (base64.contains(ch) || ch == unshift || strict)
out.put(unshift);
base64mode = false;
sextet = 0;
bitsToOutput = 0;
}
/**
* <p>
* Writes the bytes necessary to encode a character in <i>base 64 mode</i>.
* All bytes which are fully determined will be written. The fields
* <code>bitsToOutput</code> and <code>sextet</code> are used to remember
* the bytes not yet fully determined.
* </p>
*
* @param out
* @param ch
*/
private void encodeBase64(char ch, ByteBuffer out) {
if (!base64mode)
out.put(shift);
base64mode = true;
bitsToOutput += 16;
while (bitsToOutput >= 6) {
bitsToOutput -= 6;
sextet += (ch >> bitsToOutput);
sextet &= 0x3F;
out.put(base64.getChar(sextet));
sextet = 0;
}
sextet = (ch << (6 - bitsToOutput)) & 0x3F;
}
}