@@ -221,16 +221,16 @@ def reply_elements( self, attribute, data, context ):
221221 # data will be trimmed elsewhere, according to the actual byte offset requested in the Read
222222 # Tag Fragmented request.
223223 begadvance = off // siz # Rounds down to the start of the element at offset
224+ offremains = off - begadvance * siz # off is how many bytes into beg element?
224225 log .info ( "index: {index!r} beg: {beg}, cnt: {cnt}, elm: {elm}; endactual: {endactual}, begadvance: {begadvance}" .format (
225226 index = index , beg = beg , cnt = cnt , elm = elm , endactual = endactual , begadvance = begadvance ))
226227 beg += begadvance
227228 if data .service in (self .RD_TAG_RPY , self .RD_FRG_RPY ):
228- # Return at least enough elements to satisfy max_size, beginning at offset 'off' We have
229- # a 'beg' Element that contains the first byte at offset 'off'; compute the endmax that
230- # contains the last byte at offset off+max_siz-1. The data may specify the (remaining)
231- # .max_size payload available.
232- off_rem = off - begadvance * siz # off is how many bytes into beg element?
233- endadvance = max (( off_rem + max_size + siz - 1 ) // siz , 1 ) # rounds up
229+ # Return at least enough elements to satisfy max_size, beginning at offset 'off'. We
230+ # have a 'beg' Element that contains the first byte at offset 'off'; compute the endmax
231+ # that contains the last byte at offset off+max_siz-1. The data may specify the
232+ # (remaining) .max_size payload available.
233+ endadvance = max (( offremains + max_size + siz - 1 ) // siz , 1 ) # rounds up
234234 endmax = beg + endadvance
235235 else :
236236 endadvance = len ( data [context ].data )
@@ -239,13 +239,13 @@ def reply_elements( self, attribute, data, context ):
239239 "Attribute %s capacity exceeded; writing %d elements beginning at index %d" % (
240240 attribute , len ( data [context ].data ), beg )
241241 end = min ( endactual , endmax )
242- log .debug ( "offset: {off:6d} siz: {siz:3d}, beg: {beg:3d}, end: {end:3d}, endmax: {endmax:3d}" .format (
243- off = off , siz = siz , beg = beg , end = end , endmax = endmax ))
242+ log .info ( "offset: {off:6d} siz: {siz:3d}, beg: {beg:3d}, end: {end:3d}, endmax: {endmax:3d}, offremains: {offremains }" .format (
243+ off = off , siz = siz , beg = beg , end = end , endmax = endmax , offremains = offremains ))
244244 assert 0 <= beg < cnt , \
245245 "Attribute %r initial element invalid: %r" % ( attribute , (beg , end ) )
246246 assert beg < end , \
247247 "Attribute %r ending element before beginning: %r" % ( attribute , (beg , end ) )
248- return (beg ,end ,endactual )
248+ return (beg ,end ,endactual , offremains , max_size )
249249
250250 def request ( self , data , addr = None ):
251251 """Any exception should result in a reply being generated with a non-zero status."""
@@ -396,14 +396,14 @@ def request( self, data, addr=None ):
396396 # endactual. If a .offset (and optionally .max_size) is provided, these must be used to
397397 # constrain the actual payload bytes returned; the [beg,end) should index elements
398398 # containing the first byte to return (at .offset), up tothe last byte
399- # (.offset+.max_size-1).
400- beg ,end ,endactual = self .reply_elements ( attribute , data , context )
399+ # (.offset+.max_size-1). Since we might have advances 'beg', we get back the adjusted
400+ # 'offremains', as well the target 'max_size'.
401+ beg ,end ,endactual ,offremains ,max_size \
402+ = self .reply_elements ( attribute , data , context )
401403 log .debug ( "Replying w/ elements [%3d-%-3d/%3d] for %r" , beg , end , endactual , data )
402404 if data .service in (self .RD_TAG_RPY , self .RD_FRG_RPY ):
403405 # Read Tag [Fragmented]
404406 recs = attribute [beg :end ]
405- off = data [context ].get ( 'offset' ) or 0 # nonexistent/None/0 --> 0
406- max_size = data [context ].get ( 'max_size' ) or self .MAX_BYTES
407407 if attribute .parser .tag_type == STRUCT .tag_type :
408408 # Render the STRUCT UDTs to binary. Assume that each record has its data.input
409409 # representation.
@@ -413,19 +413,24 @@ def request( self, data, addr=None ):
413413 # For STRUCTs *only*, we support arbitrary .offset and max_size; trim it
414414 # here. (For other basic data types, we'll simply return the designated
415415 # elements, which may be less than, or slightly more than the .max_size /
416- # self.MAX_BYTES by some portion of one element size) Trim it here.
417- recs = dict ( input = input [off :off + max_size ] )
416+ # self.MAX_BYTES by some portion of one element size) Trim it here. If we've
417+ # returned the end element of the request, and all of its bytes, we're complete.
418+ trimmed = input [offremains :offremains + max_size ]
419+ recs = dict ( input = trimmed )
420+ completed = end == endactual and offremains + max_size >= len ( input )
418421 else :
419422 # We don't presently support a non-zero .offset for indeterminately sized types
420423 # (eg. STRING/SSTRING, etc.), or a sub-element offset for basic data types.
421424 assert off == 0 or (
422425 attribute .parser .tag_type < STRING .tag_type
423426 and off % attribute .parser .struct_calcsize == 0 )
427+ completed = end == endactual
424428 data [context ].data = recs
425- log .detail ( "%s Reading %3d elements %3d-%3d from %s: %r" ,
426- self , end - beg , beg , end - 1 , attribute , data [context ].data )
429+ log .detail ( "%s Reading %3d elements %3d-%3d %s from %s: %r" ,
430+ self , end - beg , beg , end - 1 , "(done)" if completed else "(more)" ,
431+ attribute , data [context ].data )
427432 # Final .status is 0x00 if all requested elements were shipped; 0x06 if not
428- data .status = 0x00 if end == endactual else 0x06
433+ data .status = 0x00 if completed else 0x06
429434 data .pop ( 'status_ext' ) # non-empty dotdict level; use pop instead of del
430435 else :
431436 # Write Tag [Fragmented]. We know the type is right.
0 commit comments