@@ -25,8 +25,8 @@ import array
2525
2626
2727cdef extern from " decoder_basic.c" :
28- void decode_zigzag_ints(const unsigned char ** buffer , const uint64_t count, uint64_t * result);
29- void skip_zigzag_int(const unsigned char ** buffer );
28+ int decode_zigzag_ints(const unsigned char ** buffer , const unsigned char * end , const uint64_t count, uint64_t * result);
29+ int skip_zigzag_int(const unsigned char ** buffer , const unsigned char * end );
3030
3131unsigned_long_long_array_template = cython.declare(array.array, array.array(' Q' , []))
3232
@@ -61,6 +61,14 @@ cdef class CythonBinaryDecoder:
6161 def __dealloc__(self ):
6262 PyMem_Free(self ._data)
6363
64+ cdef inline void _ensure_available(self , uint64_t length):
65+ if length > < uint64_t> (self ._end - self ._current):
66+ raise EOFError (f" EOF: read {length} bytes" )
67+
68+ cdef inline void _decode_zigzag_ints(self , uint64_t count, uint64_t * result):
69+ if not decode_zigzag_ints(& self ._current, self ._end, count, result):
70+ raise EOFError (" EOF: read 1 bytes" )
71+
6472 cpdef unsigned int tell(self ):
6573 """ Return the current stream position."""
6674 return self ._current - self ._data
@@ -69,16 +77,19 @@ cdef class CythonBinaryDecoder:
6977 """ Read n bytes."""
7078 if n < 0 :
7179 raise ValueError (f" Requested {n} bytes to read, expected positive integer." )
80+ cdef uint64_t length = n
81+ self ._ensure_available(length)
7282 cdef const unsigned char * r = self ._current
73- self ._current += n
74- return r[0 :n ]
83+ self ._current += length
84+ return r[0 :length ]
7585
7686 def read_boolean (self ) -> bool:
7787 """Reads a value from the stream as a boolean.
7888
7989 A boolean is written as a single byte
8090 whose value is either 0 (false ) or 1 (true ).
8191 """
92+ self._ensure_available(1)
8293 self._current += 1;
8394 return self._current[-1] != 0
8495
@@ -88,46 +99,43 @@ cdef class CythonBinaryDecoder:
8899 int/long values are written using variable-length, zigzag coding.
89100 """
90101 cdef uint64_t result;
91- if self ._current >= self ._end:
92- raise EOFError (f" EOF: read 1 bytes" )
93- decode_zigzag_ints(& self ._current, 1 , & result)
102+ self ._decode_zigzag_ints(1 , & result)
94103 return result
95104
96105 def read_ints (self , count: int ) -> array.array[int]:
97106 """Reads a list of integers."""
98107 newarray = array.clone(unsigned_long_long_array_template, count, zero = False )
99- if self._current >= self._end:
100- raise EOFError(f"EOF: read 1 bytes")
101- decode_zigzag_ints(&self._current , count , <uint64_t *>newarray.data.as_ulonglongs )
108+ self._decode_zigzag_ints(count , <uint64_t *>newarray.data.as_ulonglongs )
102109 return newarray
103110
104111 cpdef void read_int_bytes_dict(self , count: int , dest: Dict[int , bytes]):
105112 """ Reads a dictionary of integers for keys and bytes for values into a destination dict."""
106- cdef uint64_t result [2 ];
107- if self ._current >= self ._end:
108- raise EOFError (f " EOF: read 1 bytes " )
113+ cdef uint64_t raw_result [2 ];
114+ cdef int64_t key
115+ cdef int64_t length
109116
110117 for _ in range (count):
111- decode_zigzag_ints(& self ._current, 2 , < uint64_t * > & result)
112- if result[1 ] <= 0 :
113- dest[result[0 ]] = b" "
118+ self ._decode_zigzag_ints(2 , raw_result)
119+ key = < int64_t> raw_result[0 ]
120+ length = < int64_t> raw_result[1 ]
121+ if length <= 0 :
122+ dest[key] = b" "
114123 else :
115- dest[result[0 ]] = self ._current[0 :result[1 ]]
116- self ._current += result[1 ]
124+ self ._ensure_available(< uint64_t> length)
125+ dest[key] = self ._current[0 :length]
126+ self ._current += length
117127
118128 cpdef inline bytes read_bytes(self ):
119129 """ Bytes are encoded as a long followed by that many bytes of data."""
120- cdef uint64_t length;
121- if self ._current >= self ._end:
122- raise EOFError (f" EOF: read 1 bytes" )
123-
124- decode_zigzag_ints(& self ._current, 1 , & length)
130+ cdef uint64_t raw_length;
131+ self ._decode_zigzag_ints(1 , & raw_length)
125132
126- if length <= 0 :
133+ if < int64_t > raw_length <= 0 :
127134 return b" "
135+ self ._ensure_available(raw_length)
128136 cdef const unsigned char * r = self ._current
129- self ._current += length
130- return r[0 :length ]
137+ self ._current += raw_length
138+ return r[0 :raw_length ]
131139
132140 cpdef float read_float(self ):
133141 """ Reads a value from the stream as a float.
@@ -156,25 +164,32 @@ cdef class CythonBinaryDecoder:
156164 return self .read_bytes().decode(" utf-8" )
157165
158166 def skip_int (self ) -> None:
159- skip_zigzag_int(&self._current )
160- return
167+ if not skip_zigzag_int(&self._current , self. _end ):
168+ raise EOFError ( " EOF: read 1 bytes " )
161169
162170 def skip (self , n: int ) -> None:
163- self._current += n
171+ if n < 0:
172+ raise ValueError(f"Requested {n} bytes to skip , expected positive integer.")
173+ cdef uint64_t length = n
174+ self._ensure_available(length )
175+ self._current += length
164176
165177 def skip_boolean(self ) -> None:
166- self._current += 1
178+ self.skip(1)
167179
168180 def skip_float(self ) -> None:
169- self._current += 4
181+ self.skip(4)
170182
171183 def skip_double(self ) -> None:
172- self._current += 8
184+ self.skip(8)
173185
174186 def skip_bytes(self ) -> None:
175- cdef uint64_t result;
176- decode_zigzag_ints(&self._current , 1, &result )
177- self._current += result
187+ cdef uint64_t raw_length;
188+ self._decode_zigzag_ints(1, &raw_length )
189+ if <int64_t>raw_length <= 0:
190+ return
191+ self._ensure_available(raw_length )
192+ self._current += raw_length
178193
179194 def skip_utf8(self ) -> None:
180195 self.skip_bytes()
0 commit comments