@@ -14,11 +14,13 @@ internal sealed class NbtBinaryReader : BinaryReader {
1414 const int SeekBufferSize = 8 * 1024 ;
1515 readonly bool swapNeeded ;
1616 readonly byte [ ] stringConversionBuffer = new byte [ 64 ] ;
17+ readonly bool varInt ;
1718
1819
19- public NbtBinaryReader ( [ NotNull ] Stream input , bool bigEndian )
20+ public NbtBinaryReader ( [ NotNull ] Stream input , bool bigEndian , bool varInt )
2021 : base ( input ) {
2122 swapNeeded = ( BitConverter . IsLittleEndian == bigEndian ) ;
23+ this . varInt = varInt ;
2224 }
2325
2426
@@ -32,6 +34,20 @@ public NbtTagType ReadTagType() {
3234 return ( NbtTagType ) type ;
3335 }
3436
37+ public int ReadVarInt ( )
38+ {
39+ return VarInt . ReadSInt32 ( BaseStream ) ;
40+ }
41+
42+ public long ReadVarLong ( )
43+ {
44+ return VarInt . ReadSInt64 ( BaseStream ) ;
45+ }
46+
47+ public int ReadLength ( )
48+ {
49+ return ( int ) VarInt . ReadUInt32 ( BaseStream ) ;
50+ }
3551
3652 public override short ReadInt16 ( ) {
3753 if ( swapNeeded ) {
@@ -43,6 +59,8 @@ public override short ReadInt16() {
4359
4460
4561 public override int ReadInt32 ( ) {
62+ if ( varInt )
63+ return ReadVarInt ( ) ;
4664 if ( swapNeeded ) {
4765 return Swap ( base . ReadInt32 ( ) ) ;
4866 } else {
@@ -52,6 +70,8 @@ public override int ReadInt32() {
5270
5371
5472 public override long ReadInt64 ( ) {
73+ if ( varInt )
74+ return ReadVarLong ( ) ;
5575 if ( swapNeeded ) {
5676 return Swap ( base . ReadInt64 ( ) ) ;
5777 } else {
@@ -82,7 +102,7 @@ public override double ReadDouble() {
82102
83103
84104 public override string ReadString ( ) {
85- short length = ReadInt16 ( ) ;
105+ int length = varInt ? ReadVarInt ( ) : ReadInt16 ( ) ;
86106 if ( length < 0 ) {
87107 throw new NbtFormatException ( "Negative string length given!" ) ;
88108 }
@@ -138,7 +158,7 @@ public void Skip(int bytesToSkip) {
138158
139159
140160 public void SkipString ( ) {
141- short length = ReadInt16 ( ) ;
161+ int length = varInt ? ReadVarInt ( ) : ReadInt16 ( ) ;
142162 if ( length < 0 ) {
143163 throw new NbtFormatException ( "Negative string length given!" ) ;
144164 }
@@ -179,4 +199,137 @@ static long Swap(long v) {
179199 [ CanBeNull ]
180200 public TagSelector Selector { get ; set ; }
181201 }
202+
203+ internal static class VarInt
204+ {
205+ private static uint ReadRawVarInt32 ( Stream buf , int maxSize )
206+ {
207+ uint result = 0 ;
208+ int j = 0 ;
209+ int b0 ;
210+
211+ do
212+ {
213+ b0 = buf . ReadByte ( ) ; // -1 if EOS
214+ if ( b0 < 0 ) throw new EndOfStreamException ( "Not enough bytes for VarInt" ) ;
215+
216+ result |= ( uint ) ( b0 & 0x7f ) << j ++ * 7 ;
217+
218+ if ( j > maxSize )
219+ {
220+ throw new OverflowException ( "VarInt too big" ) ;
221+ }
222+ } while ( ( b0 & 0x80 ) == 0x80 ) ;
223+
224+ return result ;
225+ }
226+
227+ private static ulong ReadRawVarInt64 ( Stream buf , int maxSize )
228+ {
229+ ulong result = 0 ;
230+ int j = 0 ;
231+ int b0 ;
232+
233+ do
234+ {
235+ b0 = buf . ReadByte ( ) ; // -1 if EOS
236+ if ( b0 < 0 ) throw new EndOfStreamException ( "Not enough bytes for VarInt" ) ;
237+
238+ result |= ( ulong ) ( b0 & 0x7f ) << j ++ * 7 ;
239+
240+ if ( j > maxSize )
241+ {
242+ throw new OverflowException ( "VarInt too big" ) ;
243+ }
244+ } while ( ( b0 & 0x80 ) == 0x80 ) ;
245+
246+ return result ;
247+ }
248+
249+ private static void WriteRawVarInt32 ( Stream buf , uint value )
250+ {
251+ while ( ( value & - 128 ) != 0 )
252+ {
253+ buf . WriteByte ( ( byte ) ( ( value & 0x7F ) | 0x80 ) ) ;
254+ value >>= 7 ;
255+ }
256+
257+ buf . WriteByte ( ( byte ) value ) ;
258+ }
259+
260+ private static void WriteRawVarInt64 ( Stream buf , ulong value )
261+ {
262+ while ( ( value & 0xFFFFFFFFFFFFFF80 ) != 0 )
263+ {
264+ buf . WriteByte ( ( byte ) ( ( value & 0x7F ) | 0x80 ) ) ;
265+ value >>= 7 ;
266+ }
267+
268+ buf . WriteByte ( ( byte ) value ) ;
269+ }
270+
271+ // Int
272+
273+ public static void WriteInt32 ( Stream stream , int value )
274+ {
275+ WriteRawVarInt32 ( stream , ( uint ) value ) ;
276+ }
277+
278+ public static int ReadInt32 ( Stream stream )
279+ {
280+ return ( int ) ReadRawVarInt32 ( stream , 5 ) ;
281+ }
282+
283+ public static void WriteSInt32 ( Stream stream , int value )
284+ {
285+ WriteRawVarInt32 ( stream , ( uint ) value ) ;
286+ }
287+
288+ public static int ReadSInt32 ( Stream stream )
289+ {
290+ return ( int ) ReadRawVarInt32 ( stream , 5 ) ;
291+ }
292+
293+ public static void WriteUInt32 ( Stream stream , uint value )
294+ {
295+ WriteRawVarInt32 ( stream , value ) ;
296+ }
297+
298+ public static uint ReadUInt32 ( Stream stream )
299+ {
300+ return ReadRawVarInt32 ( stream , 5 ) ;
301+ }
302+
303+ // Long
304+
305+ public static void WriteInt64 ( Stream stream , long value )
306+ {
307+ WriteRawVarInt64 ( stream , ( ulong ) value ) ;
308+ }
309+
310+ public static long ReadInt64 ( Stream stream )
311+ {
312+ return ( long ) ReadRawVarInt64 ( stream , 10 ) ;
313+ }
314+
315+ public static void WriteSInt64 ( Stream stream , long value )
316+ {
317+ WriteRawVarInt64 ( stream , ( ulong ) value ) ;
318+ }
319+
320+ public static long ReadSInt64 ( Stream stream )
321+ {
322+ return ( long ) ReadRawVarInt64 ( stream , 10 ) ;
323+ }
324+
325+ public static void WriteUInt64 ( Stream stream , ulong value )
326+ {
327+ WriteRawVarInt64 ( stream , value ) ;
328+ }
329+
330+ public static ulong ReadUInt64 ( Stream stream )
331+ {
332+ return ReadRawVarInt64 ( stream , 10 ) ;
333+ }
334+ }
182335}
0 commit comments