static bool GetNextValue(string charset, Encoder encoder, HexEncoder hex, char[] chars, ref int index, ref byte[] bytes, ref byte[] encoded, int maxLength, out string value) { int length = chars.Length - index; if (length < maxLength) { switch (GetEncodeMethod(chars, index, length)) { case EncodeMethod.Quote: value = MimeUtils.Quote(new string (chars, index, length)); index += length; return(false); case EncodeMethod.None: value = new string (chars, index, length); index += length; return(false); } } length = Math.Min(maxLength, length); int ratio, count, n; do { count = encoder.GetByteCount(chars, index, length, true); if (count > maxLength && length > 1) { ratio = (int)Math.Round((double)count / (double)length); length -= Math.Max((count - maxLength) / ratio, 1); continue; } if (bytes.Length < count) { Array.Resize <byte> (ref bytes, count); } count = encoder.GetBytes(chars, index, length, bytes, 0, true); // Note: the first chunk needs to be encoded in order to declare the charset if (index > 0 || charset == "us-ascii") { var method = GetEncodeMethod(bytes, count); if (method == EncodeMethod.Quote) { value = MimeUtils.Quote(Encoding.ASCII.GetString(bytes, 0, count)); index += length; return(false); } if (method == EncodeMethod.None) { value = Encoding.ASCII.GetString(bytes, 0, count); index += length; return(false); } } n = hex.EstimateOutputLength(count); if (encoded.Length < n) { Array.Resize <byte> (ref encoded, n); } // only the first value gets a charset declaration int charsetLength = index == 0 ? charset.Length + 2 : 0; n = hex.Encode(bytes, 0, count, encoded); if (n > 3 && (charsetLength + n) > maxLength) { int x = 0; for (int i = n - 1; i >= 0 && charsetLength + i >= maxLength; i--) { if (encoded[i] == (byte)'%') { x--; } else { x++; } } ratio = (int)Math.Round((double)count / (double)length); length -= Math.Max(x / ratio, 1); continue; } if (index == 0) { value = charset + "''" + Encoding.ASCII.GetString(encoded, 0, n); } else { value = Encoding.ASCII.GetString(encoded, 0, n); } index += length; return(true); } while (true); }