-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-//
-// 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.
-//
/*
* UTF7Encoding.cs - Implementation of the
* "System.Text.UTF7Encoding" class.
*
* Copyright (c) 2002 Southern Storm Software, Pty Ltd
- * Copyright (c) 2003, Novell, Inc.
+ * Copyright (c) 2003, 2004, Novell, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
// a rolling state between calls.
private static int InternalGetByteCount
(char[] chars, int index, int count, bool flush,
- int leftOver, bool allowOptionals)
+ int leftOver, bool isInShifted, bool allowOptionals)
{
// Validate the parameters.
if (chars == null) {
switch (rule) {
case 0:
// Handle characters that must be fully encoded.
- if (leftOverSize == 0) {
+ if ( !isInShifted ) {
++length;
+ leftOverSize = 0;
+ isInShifted = true;
}
leftOverSize += 16;
while (leftOverSize >= 6) {
break;
case 1:
// The character is encoded as itself.
- if (leftOverSize != 0) {
- // Flush the previous encoded sequence.
- length += 2;
- leftOverSize = 0;
+ if (isInShifted) {
+ if (leftOverSize != 0) {
+ // Flush the previous encoded sequence.
+ ++length;
+ leftOverSize = 0;
+ }
+ // Count the "-" (sequence terminator)
+ ++length;
+ isInShifted = false;
}
++length;
break;
// Not reached.
case 3:
// Encode the plus sign as "+-".
- if (leftOverSize != 0) {
- // Flush the previous encoded sequence.
- length += 2;
- leftOverSize = 0;
+ if (isInShifted) {
+ if (leftOverSize != 0) {
+ // Flush the previous encoded sequence.
+ ++length;
+ leftOverSize = 0;
+ }
+ // Count the "-" (sequence terminator)
+ ++length;
+ isInShifted = false;
}
length += 2;
break;
}
}
- if (leftOverSize != 0 && flush) {
- length += 2;
+ if (isInShifted && flush) {
+ if (leftOverSize != 0)
+ {
+ // Flush the previous encoded sequence.
+ ++length;
+ }
+ // Count the "-" (sequence terminator)
+ ++length;
}
// Return the length to the caller.
// Get the number of bytes needed to encode a character buffer.
public override int GetByteCount (char[] chars, int index, int count)
{
- return InternalGetByteCount (chars, index, count, true, 0, allowOptionals);
+ return InternalGetByteCount (chars, index, count, true, 0, false, allowOptionals);
}
// Internal version of "GetBytes" that can handle a
private static int InternalGetBytes
(char[] chars, int charIndex, int charCount,
byte[] bytes, int byteIndex, bool flush,
- ref int leftOver, bool allowOptionals)
+ ref int leftOver, ref bool isInShifted, bool allowOptionals)
{
// Validate the parameters.
if (chars == null) {
switch (rule) {
case 0:
// Handle characters that must be fully encoded.
- if (leftOverSize == 0) {
+ if (!isInShifted) {
if (posn >= byteLength) {
throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
}
+ // Start the sequence
bytes[posn++] = (byte)'+';
+ isInShifted = true;
+ leftOverSize = 0;
}
leftOverBits = ((leftOverBits << 16) | ch);
leftOverSize += 16;
break;
case 1:
// The character is encoded as itself.
- if (leftOverSize != 0) {
- // Flush the previous encoded sequence.
- if ((posn + 2) > byteLength) {
+ if (isInShifted) {
+ if (leftOverSize != 0) {
+ // Flush the previous encoded sequence.
+ if ((posn + 1) > byteLength) {
+ throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
+ }
+ bytes[posn++] = (byte)(base64 [leftOverBits << (6 - leftOverSize)]);
+ }
+ if ((posn + 1) > byteLength) {
throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
}
- bytes[posn++] = (byte)(base64 [leftOverBits << (6 - leftOverSize)]);
+ // Terminate the sequence
bytes[posn++] = (byte)'-';
+ isInShifted = false;
leftOverSize = 0;
leftOverBits = 0;
}
// Not reached.
case 3:
// Encode the plus sign as "+-".
- if (leftOverSize != 0) {
- // Flush the previous encoded sequence.
- if ((posn + 2) > byteLength) {
+ if (isInShifted) {
+ if (leftOverSize != 0) {
+ // Flush the previous encoded sequence.
+ if ((posn + 1) > byteLength) {
+ throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
+ }
+ bytes[posn++] = (byte)(base64 [leftOverBits << (6 - leftOverSize)]);
+ }
+ if ((posn + 1) > byteLength) {
throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
}
- bytes[posn++] = (byte)(base64 [leftOverBits << (6 - leftOverSize)]);
+ // Terminate the sequence
bytes[posn++] = (byte)'-';
+ isInShifted = false;
leftOverSize = 0;
leftOverBits = 0;
}
break;
}
}
- if (leftOverSize != 0 && flush) {
- if ((posn + 2) > byteLength) {
- throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
+ if (isInShifted && flush) {
+ // Flush the previous encoded sequence.
+ if (leftOverSize != 0) {
+ if ((posn + 1) > byteLength) {
+ throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
+ }
+ bytes[posn++] = (byte)(base64 [leftOverBits << (6 - leftOverSize)]);
}
- bytes[posn++] = (byte)(base64 [leftOverBits << (6 - leftOverSize)]);
+ // Terminate the sequence
bytes[posn++] = (byte)'-';
leftOverSize = 0;
leftOverBits = 0;
+ isInShifted = false;
}
leftOver = ((leftOverSize << 8) | leftOverBits);
byte[] bytes, int byteIndex)
{
int leftOver = 0;
+ bool isInShifted = false;
return InternalGetBytes (chars, charIndex, charCount, bytes, byteIndex, true,
- ref leftOver, allowOptionals);
+ ref leftOver, ref isInShifted, allowOptionals);
}
// Internal version of "GetCharCount" that can handle
// Determine the length of the result.
int length = 0;
- int byteval, b64value;
+ int byteval;
bool normal = ((leftOver & 0x01000000) == 0);
bool prevIsPlus = ((leftOver & 0x02000000) != 0);
int leftOverSize = ((leftOver >> 16) & 0xFF);
leftOverSize = 0;
}
normal = true;
- } else if ((b64value = base64[byteval]) != -1) {
+ } else if (base64 [byteval] != -1) {
// Extra character in a base64 sequence.
leftOverSize += 6;
if (leftOverSize >= 16) {
leftOverSize -= 16;
}
} else {
- // Normal character terminating a base64 sequence.
- if (leftOverSize > 0) {
- ++length;
- leftOverSize = 0;
- }
++length;
normal = true;
+ leftOverSize = 0;
}
prevIsPlus = false;
}
int byteval, b64value;
bool normal = ((leftOver & 0x01000000) == 0);
bool prevIsPlus = ((leftOver & 0x02000000) != 0);
+ bool afterHighSurrogate = ((leftOver & 0x04000000) != 0);
int leftOverSize = ((leftOver >> 16) & 0xFF);
int leftOverBits = (leftOver & 0xFFFF);
sbyte[] base64 = base64Values;
if (posn >= charLength) {
throw new ArgumentException (_("Arg_InsufficientSpace"), "chars");
}
+ if (afterHighSurrogate) {
+ throw new ArgumentException (_("Arg_InvalidUTF7"), "chars");
+ }
chars[posn++] = (char)byteval;
} else {
// Start of a base64-encoded character.
if (posn >= charLength) {
throw new ArgumentException (_("Arg_InsufficientSpace"), "chars");
}
+ if (afterHighSurrogate) {
+ throw new ArgumentException (_("Arg_InvalidUTF7"), "chars");
+ }
chars[posn++] = '+';
}
// RFC1642 Rule #2
// When decoding, any bits at the end of the Modified Base64 sequence that
// do not constitute a complete 16-bit Unicode character are discarded.
// If such discarded bits are non-zero the sequence is ill-formed.
- if (leftOverBits != 0)
- throw new FormatException ("unused bits not zero");
normal = true;
- } else if ((b64value = base64[byteval]) != -1) {
+ leftOverSize = 0;
+ leftOverBits = 0;
+ }
+ else if ((b64value = base64[byteval]) != -1)
+ {
// Extra character in a base64 sequence.
leftOverBits = (leftOverBits << 6) | b64value;
leftOverSize += 6;
throw new ArgumentException (_("Arg_InsufficientSpace"), "chars");
}
leftOverSize -= 16;
- chars[posn++] = (char)(leftOverBits >> leftOverSize);
+ char nextChar = (char)(leftOverBits >> leftOverSize);
+ if ((nextChar & 0xFC00) == 0xD800) {
+ afterHighSurrogate = true;
+ }
+ else if ((nextChar & 0xFC00) == 0xDC00) {
+ if (!afterHighSurrogate) {
+ throw new ArgumentException (_("Arg_InvalidUTF7"), "chars");
+ }
+ afterHighSurrogate = false;
+ }
+ chars[posn++] = nextChar;
leftOverBits &= ((1 << leftOverSize) - 1);
}
} else {
- // Normal character terminating a base64 sequence.
- if (leftOverSize > 0) {
- if (posn >= charLength) {
- throw new ArgumentException (_("Arg_InsufficientSpace"), "chars");
- }
- chars[posn++] = (char)(leftOverBits << (16 - leftOverSize));
- leftOverSize = 0;
- leftOverBits = 0;
- }
if (posn >= charLength) {
throw new ArgumentException (_("Arg_InsufficientSpace"), "chars");
}
+ if (afterHighSurrogate) {
+ throw new ArgumentException (_("Arg_InvalidUTF7"), "chars");
+ }
chars[posn++] = (char)byteval;
normal = true;
+ leftOverSize = 0;
+ leftOverBits = 0;
}
prevIsPlus = false;
}
}
leftOver = (leftOverBits | (leftOverSize << 16) |
(normal ? 0 : 0x01000000) |
- (prevIsPlus ? 0x02000000 : 0));
+ (prevIsPlus ? 0x02000000 : 0) |
+ (afterHighSurrogate ? 0x04000000 : 0));
// Return the final length to the caller.
return posn - charIndex;
char[] chars, int charIndex)
{
int leftOver = 0;
- return InternalGetChars (bytes, byteIndex, byteCount, chars, charIndex, ref leftOver);
+ int amount = InternalGetChars (bytes, byteIndex, byteCount, chars, charIndex, ref leftOver);
+ if ((leftOver & 0x04000000) != 0) {
+ throw new ArgumentException (_("Arg_InvalidUTF7"), "chars");
+ }
+ return amount;
}
// Get the maximum number of bytes needed to encode a
private sealed class UTF7Encoder : Encoder
{
private bool allowOptionals;
- private int leftOver;
+ private int leftOver = 0;
+ private bool isInShifted = false;
// Constructor.
public UTF7Encoder (bool allowOptionals)
{
this.allowOptionals = allowOptionals;
- this.leftOver = 0;
}
// Override inherited methods.
int count, bool flush)
{
return InternalGetByteCount
- (chars, index, count, flush, leftOver, allowOptionals);
+ (chars, index, count, flush, leftOver, isInShifted, allowOptionals);
}
public override int GetBytes (char[] chars, int charIndex,
int charCount, byte[] bytes,
{
return InternalGetBytes (chars, charIndex, charCount,
bytes, byteIndex, flush,
- ref leftOver, allowOptionals);
+ ref leftOver, ref isInShifted, allowOptionals);
}
} // class UTF7Encoder