33//
44// Author: Jeffrey Stedfast <jestedfa@microsoft.com>
55//
6- // Copyright (c) 2013-2025 .NET Foundation and Contributors
6+ // Copyright (c) 2013-2026 .NET Foundation and Contributors
77//
88// Permission is hereby granted, free of charge, to any person obtaining a copy
99// of this software and associated documentation files (the "Software"), to deal
@@ -45,10 +45,12 @@ enum QpValidatorState : byte
4545 PassThrough ,
4646 EqualSign ,
4747 SoftBreak ,
48- DecodeByte ,
49- Invalid
48+ DecodeByte
5049 }
5150
51+ readonly MimeReader reader ;
52+ long streamOffset ;
53+ int lineNumber ;
5254 QpValidatorState state ;
5355
5456 /// <summary>
@@ -57,8 +59,14 @@ enum QpValidatorState : byte
5759 /// <remarks>
5860 /// Creates a new quoted-printable validator.
5961 /// </remarks>
60- public QuotedPrintableValidator ( )
62+ /// <param name="reader">The mime reader.</param>
63+ /// <param name="streamOffset">The current stream offset.</param>
64+ /// <param name="lineNumber">The current line number.</param>
65+ public QuotedPrintableValidator ( MimeReader reader , long streamOffset , int lineNumber )
6166 {
67+ this . reader = reader ;
68+ this . streamOffset = streamOffset ;
69+ this . lineNumber = lineNumber ;
6270 }
6371
6472 /// <summary>
@@ -104,6 +112,8 @@ unsafe void Validate (byte* input, int length)
104112 if ( c == '=' ) {
105113 state = QpValidatorState . EqualSign ;
106114 break ;
115+ } else if ( c == '\n ' ) {
116+ lineNumber ++ ;
107117 }
108118 }
109119 break ;
@@ -116,35 +126,39 @@ unsafe void Validate (byte* input, int length)
116126 state = QpValidatorState . SoftBreak ;
117127 } else if ( c == '\n ' ) {
118128 state = QpValidatorState . PassThrough ;
129+ lineNumber ++ ;
119130 } else {
120- // invalid encoded sequence
121- state = QpValidatorState . Invalid ;
122- return ;
131+ reader . OnMimeComplianceViolation ( MimeComplianceViolation . InvalidQuotedPrintableEncoding , streamOffset + ( inptr - input ) , lineNumber ) ;
132+ state = QpValidatorState . PassThrough ;
123133 }
124134 break ;
125135 case QpValidatorState . SoftBreak :
126- state = QpValidatorState . PassThrough ;
127136 c = * inptr ++ ;
128137
129- if ( c ! = '\n ' ) {
130- // invalid encoded sequence
131- state = QpValidatorState . Invalid ;
132- return ;
138+ if ( c = = '\n ' ) {
139+ lineNumber ++ ;
140+ } else {
141+ reader . OnMimeComplianceViolation ( MimeComplianceViolation . InvalidQuotedPrintableSoftBreak , streamOffset + ( inptr - input ) , lineNumber ) ;
133142 }
143+
144+ state = QpValidatorState . PassThrough ;
134145 break ;
135146 case QpValidatorState . DecodeByte :
136147 c = * inptr ++ ;
137148
138149 if ( ! c . IsXDigit ( ) ) {
139- // invalid encoded sequence
140- state = QpValidatorState . Invalid ;
141- return ;
150+ reader . OnMimeComplianceViolation ( MimeComplianceViolation . InvalidQuotedPrintableEncoding , streamOffset + ( inptr - input ) , lineNumber ) ;
151+
152+ if ( c == '\n ' )
153+ lineNumber ++ ;
142154 }
143155
144156 state = QpValidatorState . PassThrough ;
145157 break ;
146158 }
147159 }
160+
161+ streamOffset += length ;
148162 }
149163
150164 /// <summary>
@@ -167,25 +181,24 @@ public unsafe void Write (byte[] buffer, int startIndex, int length)
167181 {
168182 ValidateArguments ( buffer , startIndex , length ) ;
169183
170- if ( state == QpValidatorState . Invalid )
171- return ;
172-
173184 fixed ( byte * inbuf = buffer ) {
174185 Validate ( inbuf + startIndex , length ) ;
175186 }
176187 }
177188
178189 /// <summary>
179- /// Validate the content that was written to the validator.
190+ /// Flush the validator state .
180191 /// </summary>
181192 /// <remarks>
182- /// Validates the content that was written to the validator.
193+ /// Flushes the validator state .
183194 /// </remarks>
184- /// <returns><see langword="true"/> if the content was valid; otherwise, <see langword="false"/>.</returns>
185- public bool Validate ( )
195+ public void Flush ( )
186196 {
187197 // Note: the only valid state to end on is the pass-through state.
188- return state == QpValidatorState . PassThrough ;
198+ if ( state == QpValidatorState . EqualSign || state == QpValidatorState . DecodeByte )
199+ reader . OnMimeComplianceViolation ( MimeComplianceViolation . InvalidQuotedPrintableEncoding , streamOffset , lineNumber ) ;
200+ else if ( state == QpValidatorState . SoftBreak )
201+ reader . OnMimeComplianceViolation ( MimeComplianceViolation . InvalidQuotedPrintableSoftBreak , streamOffset , lineNumber ) ;
189202 }
190203 }
191204}
0 commit comments