+// Implementation (C) 2004 Fredrik Roubert
+//
+// Changes to work in streaming mode (C) 2008 Vadim Zeitlin
+
+//
+// BASE64 decoding table
+//
+static const unsigned char utf7unb64[] =
+{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen,
+ const char *src, size_t srcLen) const
+{
+ DecoderState stateOrig,
+ *statePtr;
+ if ( srcLen == wxNO_LEN )
+ {
+ // convert the entire string, up to and including the trailing NUL
+ srcLen = strlen(src) + 1;
+
+ // when working on the entire strings we don't update nor use the shift
+ // state from the previous call
+ statePtr = &stateOrig;
+ }
+ else // when working with partial strings we do use the shift state
+ {
+ statePtr = wx_const_cast(DecoderState *, &m_stateDecoder);
+
+ // also save the old state to be able to rollback to it on error
+ stateOrig = m_stateDecoder;
+ }
+
+ // but to simplify the code below we use this variable in both cases
+ DecoderState& state = *statePtr;
+
+
+ // number of characters [which would have been] written to dst [if it were
+ // not NULL]
+ size_t len = 0;
+
+ const char * const srcEnd = src + srcLen;
+
+ while ( (src < srcEnd) && (!dst || (len < dstLen)) )
+ {
+ const unsigned char cc = *src++;
+
+ if ( state.IsShifted() )
+ {
+ const unsigned char dc = utf7unb64[cc];
+ if ( dc == 0xff )
+ {
+ // end of encoded part
+ state.ToDirect();
+
+ // re-parse this character normally below unless it's '-' which
+ // is consumed by the decoder
+ if ( cc == '-' )
+ continue;
+ }
+ else // valid encoded character
+ {
+ // mini base64 decoder: each character is 6 bits
+ state.bit += 6;
+ state.accum <<= 6;
+ state.accum += dc;
+
+ if ( state.bit >= 8 )
+ {
+ // got the full byte, consume it
+ state.bit -= 8;
+ unsigned char b = (state.accum >> state.bit) & 0x00ff;
+
+ if ( state.isLSB )
+ {
+ // we've got the full word, output it
+ if ( dst )
+ *dst++ = (state.msb << 8) | b;
+ len++;
+ state.isLSB = false;
+ }
+ else // MSB
+ {
+ // just store it while we wait for LSB
+ state.msb = b;
+ state.isLSB = true;
+ }
+ }
+ }
+ }
+
+ if ( state.IsDirect() )
+ {
+ // start of an encoded segment?
+ if ( cc == '+' )
+ {
+ if ( src == srcEnd )
+ return wxCONV_FAILED; // can't have '+' at the end
+
+ if ( *src == '-' )
+ {
+ // just the encoded plus sign, don't switch to shifted mode
+ if ( dst )
+ *dst++ = '+';
+ len++;
+ src++;
+ }
+ else
+ {
+ state.ToShifted();
+ }
+ }
+ else // not '+'
+ {
+ // only printable 7 bit ASCII characters (with the exception of
+ // NUL, TAB, CR and LF) can be used directly
+ if ( cc >= 0x7f || (cc < ' ' &&
+ !(cc == '\0' || cc == '\t' || cc == '\r' || cc == '\n')) )
+ return wxCONV_FAILED;
+
+ if ( dst )
+ *dst++ = cc;
+ len++;
+ }
+ }
+ }