@@ -30,7 +30,7 @@ namespace Google.Protobuf
3030 /// </remarks>
3131 internal abstract class JsonTokenizer
3232 {
33- private JsonToken bufferedToken ;
33+ protected JsonToken bufferedToken ;
3434
3535 /// <summary>
3636 /// Creates a tokenizer that reads from the given text reader.
@@ -58,6 +58,10 @@ internal static JsonTokenizer FromReplayedTokens(IList<JsonToken> tokens, JsonTo
5858 /// </summary>
5959 internal int RecursionDepth { get ; set ; }
6060
61+ internal abstract void StartRecording ( ) ;
62+ internal abstract void StopRecording ( ) ;
63+ internal abstract JsonTokenizer GetReplayTokenizer ( JsonTokenizer continuation ) ;
64+
6165 /// <summary>
6266 /// Returns the depth of the stack, purely in objects (not collections).
6367 /// Informally, this is the number of remaining unclosed '{' characters we have.
@@ -153,26 +157,62 @@ internal void SkipValue()
153157 /// <summary>
154158 /// Tokenizer which first exhausts a list of tokens, then consults another tokenizer.
155159 /// </summary>
156- private class JsonReplayTokenizer : JsonTokenizer
160+ internal class JsonReplayTokenizer : JsonTokenizer
157161 {
158162 private readonly IList < JsonToken > tokens ;
159163 private readonly JsonTokenizer nextTokenizer ;
160164 private int nextTokenIndex ;
165+ private readonly int endIndex ;
161166
162167 internal JsonReplayTokenizer ( IList < JsonToken > tokens , JsonTokenizer nextTokenizer )
163168 {
164169 this . tokens = tokens ;
165170 this . nextTokenizer = nextTokenizer ;
171+ this . endIndex = - 1 ;
172+ }
173+
174+ internal JsonReplayTokenizer ( IList < JsonToken > tokens , int startIndex , int endIndex , JsonTokenizer nextTokenizer )
175+ {
176+ this . tokens = tokens ;
177+ this . nextTokenIndex = startIndex ;
178+ this . endIndex = endIndex ;
179+ this . nextTokenizer = nextTokenizer ;
180+ }
181+
182+ private int recordStartIndex ;
183+ private int recordCount ;
184+ private bool recording ;
185+
186+ internal override void StartRecording ( )
187+ {
188+ recordStartIndex = bufferedToken != null ? nextTokenIndex - 1 : nextTokenIndex ;
189+ recordCount = 0 ;
190+ recording = true ;
191+ }
192+
193+ internal override void StopRecording ( )
194+ {
195+ recording = false ;
196+ }
197+
198+ internal override JsonTokenizer GetReplayTokenizer ( JsonTokenizer continuation )
199+ {
200+ return new JsonReplayTokenizer ( tokens , recordStartIndex , recordStartIndex + recordCount , continuation ) ;
166201 }
167202
168- // FIXME: Object depth not maintained...
169203 protected override JsonToken NextImpl ( )
170204 {
171- if ( nextTokenIndex >= tokens . Count )
205+ int limit = endIndex < 0 ? tokens . Count : endIndex ;
206+ if ( nextTokenIndex >= limit )
172207 {
173208 return nextTokenizer . Next ( ) ;
174209 }
175- return tokens [ nextTokenIndex ++ ] ;
210+ var token = tokens [ nextTokenIndex ++ ] ;
211+ if ( recording )
212+ {
213+ recordCount ++ ;
214+ }
215+ return token ;
176216 }
177217 }
178218
@@ -187,6 +227,23 @@ private sealed class JsonTextTokenizer : JsonTokenizer
187227 private readonly Stack < ContainerType > containerStack = new Stack < ContainerType > ( ) ;
188228 private readonly PushBackReader reader ;
189229 private State state ;
230+ private List < JsonToken > recordedTokens ;
231+
232+ internal override void StartRecording ( )
233+ {
234+ recordedTokens = new List < JsonToken > ( ) ;
235+ }
236+
237+ internal override void StopRecording ( )
238+ {
239+ }
240+
241+ internal override JsonTokenizer GetReplayTokenizer ( JsonTokenizer continuation )
242+ {
243+ var result = FromReplayedTokens ( recordedTokens , continuation ) ;
244+ recordedTokens = null ;
245+ return result ;
246+ }
190247
191248 internal JsonTextTokenizer ( TextReader reader )
192249 {
@@ -203,6 +260,16 @@ internal JsonTextTokenizer(TextReader reader)
203260 /// of it is the large switch statement, which sometimes returns and sometimes doesn't.
204261 /// </remarks>
205262 protected override JsonToken NextImpl ( )
263+ {
264+ var token = NextImplInner ( ) ;
265+ if ( recordedTokens != null )
266+ {
267+ recordedTokens . Add ( token ) ;
268+ }
269+ return token ;
270+ }
271+
272+ private JsonToken NextImplInner ( )
206273 {
207274 if ( state == State . ReaderExhausted )
208275 {
0 commit comments