/// <summary> /// Resets the decoder. /// </summary> /// <remarks> /// Resets the state of the decoder. /// </remarks> public void Reset() { octet = (byte)'\n'; state = initial; escaped = false; eoln = true; crc.Reset(); }
/// <summary> /// Initializes a new instance of the <see cref="MimeKit.Encodings.YDecoder"/> class. /// </summary> /// <remarks> /// Creates a new yEnc decoder. /// </remarks> /// <param name="payloadOnly"> /// If <c>true</c>, decoding begins immediately rather than after finding an =ybegin line. /// </param> public YDecoder(bool payloadOnly) { initial = payloadOnly ? YDecoderState.Payload : YDecoderState.ExpectYBegin; crc = new Crc32(-1); Reset(); }
/// <summary> /// Decodes the specified input into the output buffer. /// </summary> /// <remarks> /// <para>Decodes the specified input into the output buffer.</para> /// <para>The output buffer should be large enough to hold all of the /// decoded input. For estimating the size needed for the output buffer, /// see <see cref="EstimateOutputLength"/>.</para> /// </remarks> /// <returns>The number of bytes written to the output buffer.</returns> /// <param name="input">A pointer to the beginning of the input buffer.</param> /// <param name="length">The length of the input buffer.</param> /// <param name="output">A pointer to the beginning of the output buffer.</param> public unsafe int Decode(byte *input, int length, byte *output) { byte *inend = input + length; byte *outptr = output; byte *inptr = input; if (state < YDecoderState.Payload) { if ((inptr = ScanYBeginMarker(inptr, inend)) == inend) { return(0); } eoln = true; } if (state == YDecoderState.Ended) { return(0); } while (inptr < inend) { octet = *inptr++; if (octet == (byte)'\r') { escaped = false; continue; } if (octet == (byte)'\n') { escaped = false; eoln = true; continue; } if (escaped) { if (eoln && octet == (byte)'y') { // this can only be =yend state = YDecoderState.Ended; break; } escaped = false; eoln = false; octet -= 64; } else if (octet == (byte)'=') { escaped = true; continue; } else { eoln = false; } octet -= 42; crc.Update(octet); *outptr++ = octet; } return((int)(outptr - output)); }
unsafe byte *ScanYBeginMarker(byte *inptr, byte *inend) { while (inptr < inend) { if (state == YDecoderState.ExpectYBegin) { if (octet != (byte)'\n') { while (inptr < inend && *inptr != (byte)'\n') { inptr++; } if (inptr == inend) { octet = *(inptr - 1); break; } octet = *inptr++; if (inptr == inend) { break; } } octet = *inptr++; if (octet != (byte)'=') { continue; } state = YDecoderState.YBeginEqual; if (inptr == inend) { break; } } if (state == YDecoderState.YBeginEqual) { octet = *inptr++; if (octet != (byte)'y') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualY; if (inptr == inend) { break; } } if (state == YDecoderState.YBeginEqualY) { octet = *inptr++; if (octet != (byte)'b') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYB; if (inptr == inend) { break; } } if (state == YDecoderState.YBeginEqualYB) { octet = *inptr++; if (octet != (byte)'e') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBe; if (inptr == inend) { break; } } if (state == YDecoderState.YBeginEqualYBe) { octet = *inptr++; if (octet != (byte)'g') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBeg; if (inptr == inend) { break; } } if (state == YDecoderState.YBeginEqualYBeg) { octet = *inptr++; if (octet != (byte)'i') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBegi; if (inptr == inend) { break; } } if (state == YDecoderState.YBeginEqualYBegi) { octet = *inptr++; if (octet != (byte)'n') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBegin; if (inptr == inend) { break; } } if (state == YDecoderState.YBeginEqualYBegin) { octet = *inptr++; if (octet != (byte)' ') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.ExpectYBeginNewLine; if (inptr == inend) { break; } } if (state == YDecoderState.ExpectYBeginNewLine) { while (inptr < inend && *inptr != (byte)'\n') { inptr++; } if (inptr == inend) { octet = *(inptr - 1); break; } state = YDecoderState.ExpectYPartOrPayload; octet = *inptr++; break; } if (state == YDecoderState.ExpectYPartOrPayload) { if (*inptr != (byte)'=') { state = YDecoderState.Payload; break; } state = YDecoderState.YPartEqual; octet = *inptr++; escaped = true; if (inptr == inend) { break; } } if (state == YDecoderState.YPartEqual) { if (*inptr != (byte)'y') { state = YDecoderState.Payload; return(inptr); } state = YDecoderState.YPartEqualY; octet = *inptr++; if (inptr == inend) { break; } } if (state == YDecoderState.YPartEqualY) { if (*inptr == (byte)'e') { // we got an "=ye" which can only be an "=yend" state = YDecoderState.Ended; return(inptr); } if (*inptr != (byte)'p') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYP; octet = *inptr++; if (inptr == inend) { break; } } if (state == YDecoderState.YPartEqualYP) { if (*inptr != (byte)'a') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYPa; octet = *inptr++; if (inptr == inend) { break; } } if (state == YDecoderState.YPartEqualYPa) { if (*inptr != (byte)'r') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYPar; octet = *inptr++; if (inptr == inend) { break; } } if (state == YDecoderState.YPartEqualYPar) { if (*inptr != (byte)'t') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYPart; octet = *inptr++; if (inptr == inend) { break; } } if (state == YDecoderState.YPartEqualYPart) { if (*inptr != (byte)' ') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.ExpectYPartNewLine; octet = *inptr++; if (inptr == inend) { break; } } if (state == YDecoderState.ExpectYPartNewLine) { while (inptr < inend && *inptr != (byte)'\n') { inptr++; } if (inptr == inend) { octet = *(inptr - 1); break; } state = YDecoderState.Payload; octet = *inptr++; break; } } return(inptr); }
/// <summary> /// Initializes a new instance of the <see cref="MimeKit.Encodings.YDecoder"/> class. /// </summary> /// <remarks> /// Creates a new yEnc decoder. /// </remarks> /// <param name="payloadOnly"> /// If <c>true</c>, decoding begins immediately rather than after finding an =ybegin line. /// </param> public YDecoder (bool payloadOnly) { initial = payloadOnly ? YDecoderState.Payload : YDecoderState.ExpectYBegin; crc = new Crc32 (-1); Reset (); }
/// <summary> /// Resets the decoder. /// </summary> /// <remarks> /// Resets the state of the decoder. /// </remarks> public void Reset () { octet = (byte) '\n'; state = initial; escaped = false; eoln = true; crc.Reset (); }
/// <summary> /// Decodes the specified input into the output buffer. /// </summary> /// <remarks> /// <para>Decodes the specified input into the output buffer.</para> /// <para>The output buffer should be large enough to hold all of the /// decoded input. For estimating the size needed for the output buffer, /// see <see cref="EstimateOutputLength"/>.</para> /// </remarks> /// <returns>The number of bytes written to the output buffer.</returns> /// <param name="input">A pointer to the beginning of the input buffer.</param> /// <param name="length">The length of the input buffer.</param> /// <param name="output">A pointer to the beginning of the output buffer.</param> public unsafe int Decode (byte* input, int length, byte* output) { byte* inend = input + length; byte* outptr = output; byte* inptr = input; if (state < YDecoderState.Payload) { if ((inptr = ScanYBeginMarker (inptr, inend)) == inend) return 0; eoln = true; } if (state == YDecoderState.Ended) return 0; while (inptr < inend) { octet = *inptr++; if (octet == (byte) '\r') { escaped = false; continue; } if (octet == (byte) '\n') { escaped = false; eoln = true; continue; } if (escaped) { if (eoln && octet == (byte) 'y') { // this can only be =yend state = YDecoderState.Ended; break; } escaped = false; eoln = false; octet -= 64; } else if (octet == (byte) '=') { escaped = true; continue; } else { eoln = false; } octet -= 42; crc.Update (octet); *outptr++ = octet; } return (int) (outptr - output); }
unsafe byte* ScanYBeginMarker (byte* inptr, byte* inend) { while (inptr < inend) { if (state == YDecoderState.ExpectYBegin) { if (octet != (byte) '\n') { while (inptr < inend && *inptr != (byte) '\n') inptr++; if (inptr == inend) { octet = *(inptr - 1); break; } octet = *inptr++; if (inptr == inend) break; } octet = *inptr++; if (octet != (byte) '=') continue; state = YDecoderState.YBeginEqual; if (inptr == inend) break; } if (state == YDecoderState.YBeginEqual) { octet = *inptr++; if (octet != (byte) 'y') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualY; if (inptr == inend) break; } if (state == YDecoderState.YBeginEqualY) { octet = *inptr++; if (octet != (byte) 'b') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYB; if (inptr == inend) break; } if (state == YDecoderState.YBeginEqualYB) { octet = *inptr++; if (octet != (byte) 'e') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBe; if (inptr == inend) break; } if (state == YDecoderState.YBeginEqualYBe) { octet = *inptr++; if (octet != (byte) 'g') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBeg; if (inptr == inend) break; } if (state == YDecoderState.YBeginEqualYBeg) { octet = *inptr++; if (octet != (byte) 'i') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBegi; if (inptr == inend) break; } if (state == YDecoderState.YBeginEqualYBegi) { octet = *inptr++; if (octet != (byte) 'n') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.YBeginEqualYBegin; if (inptr == inend) break; } if (state == YDecoderState.YBeginEqualYBegin) { octet = *inptr++; if (octet != (byte) ' ') { state = YDecoderState.ExpectYBegin; continue; } state = YDecoderState.ExpectYBeginNewLine; if (inptr == inend) break; } if (state == YDecoderState.ExpectYBeginNewLine) { while (inptr < inend && *inptr != (byte) '\n') inptr++; if (inptr == inend) { octet = *(inptr - 1); break; } state = YDecoderState.ExpectYPartOrPayload; octet = *inptr++; break; } if (state == YDecoderState.ExpectYPartOrPayload) { if (*inptr != (byte) '=') { state = YDecoderState.Payload; break; } state = YDecoderState.YPartEqual; octet = *inptr++; escaped = true; if (inptr == inend) break; } if (state == YDecoderState.YPartEqual) { if (*inptr != (byte) 'y') { state = YDecoderState.Payload; return inptr; } state = YDecoderState.YPartEqualY; octet = *inptr++; if (inptr == inend) break; } if (state == YDecoderState.YPartEqualY) { if (*inptr == (byte) 'e') { // we got an "=ye" which can only be an "=yend" state = YDecoderState.Ended; return inptr; } if (*inptr != (byte) 'p') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYP; octet = *inptr++; if (inptr == inend) break; } if (state == YDecoderState.YPartEqualYP) { if (*inptr != (byte) 'a') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYPa; octet = *inptr++; if (inptr == inend) break; } if (state == YDecoderState.YPartEqualYPa) { if (*inptr != (byte) 'r') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYPar; octet = *inptr++; if (inptr == inend) break; } if (state == YDecoderState.YPartEqualYPar) { if (*inptr != (byte) 't') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.YPartEqualYPart; octet = *inptr++; if (inptr == inend) break; } if (state == YDecoderState.YPartEqualYPart) { if (*inptr != (byte) ' ') { state = YDecoderState.ExpectYBeginNewLine; continue; } state = YDecoderState.ExpectYPartNewLine; octet = *inptr++; if (inptr == inend) break; } if (state == YDecoderState.ExpectYPartNewLine) { while (inptr < inend && *inptr != (byte) '\n') inptr++; if (inptr == inend) { octet = *(inptr - 1); break; } state = YDecoderState.Payload; octet = *inptr++; break; } } return inptr; }