@@ -494,21 +494,24 @@ function Base.write(stream::TranscodingStream)
494
494
return 0
495
495
end
496
496
497
- function Base. write (stream:: TranscodingStream , b:: UInt8 )
497
+ function Base. write (stream:: TranscodingStream , b:: UInt8 ):: Int
498
498
changemode! (stream, :write )
499
- if marginsize (stream . buffer1) == 0 && flushbuffer ( stream) == 0
500
- return 0
501
- end
502
- return writebyte! (stream . buffer1, b)
499
+ buffer1 = stream. buffer1
500
+ marginsize (buffer1) > 0 || flush_buffer1 (stream)
501
+ writebyte! (buffer1, b)
502
+ return 1
503
503
end
504
504
505
505
function Base. unsafe_write (stream:: TranscodingStream , input:: Ptr{UInt8} , nbytes:: UInt )
506
506
changemode! (stream, :write )
507
- state = stream . state
507
+ Int (nbytes) # Error if nbytes > typemax Int
508
508
buffer1 = stream. buffer1
509
509
p = input
510
510
p_end = p + nbytes
511
- while p < p_end && (marginsize (buffer1) > 0 || flushbuffer (stream) > 0 )
511
+ while p < p_end
512
+ if marginsize (buffer1) ≤ 0
513
+ flush_buffer1 (stream)
514
+ end
512
515
m = min (marginsize (buffer1), p_end - p)
513
516
copydata! (buffer1, p, m)
514
517
p += m
@@ -535,16 +538,16 @@ const TOKEN_END = EndToken()
535
538
536
539
function Base. write (stream:: TranscodingStream , :: EndToken )
537
540
changemode! (stream, :write )
538
- flushbufferall (stream)
541
+ flush_buffer1 (stream)
539
542
flushuntilend (stream)
540
543
return 0
541
544
end
542
545
543
546
function Base. flush (stream:: TranscodingStream )
544
547
checkmode (stream)
545
548
if stream. state. mode == :write
546
- flushbufferall (stream)
547
- writedata! (stream. stream, stream . buffer2 )
549
+ flush_buffer1 (stream)
550
+ flush_buffer2 (stream)
548
551
end
549
552
flush (stream. stream)
550
553
end
@@ -600,9 +603,12 @@ function stats(stream::TranscodingStream)
600
603
out = transcoded_out - buffersize (buffer1)
601
604
elseif mode === :write
602
605
transcoded_in = buffer1. transcoded
603
- transcoded_out = buffer2. transcoded
606
+ out = state. bytes_written_out
607
+ transcoded_out = out
608
+ if ! has_sharedbuf (stream)
609
+ transcoded_out += buffersize (buffer2)
610
+ end
604
611
in = transcoded_in + buffersize (buffer1)
605
- out = transcoded_out - buffersize (buffer2)
606
612
else
607
613
throw_invalid_mode (mode)
608
614
end
@@ -633,38 +639,37 @@ function fillbuffer(stream::TranscodingStream; eager::Bool = false)
633
639
return nfilled
634
640
end
635
641
636
- function flushbuffer (stream:: TranscodingStream , all:: Bool = false )
637
- changemode! (stream, :write )
642
+ # Empty buffer1 by writing out data.
643
+ # `stream` must be in :write mode.
644
+ # Ensure there is margin available in buffer1 for at least one byte.
645
+ function flush_buffer1 (stream:: TranscodingStream ):: Nothing
638
646
state = stream. state
639
647
buffer1 = stream. buffer1
640
648
buffer2 = stream. buffer2
641
- nflushed:: Int = 0
642
- while (all ? buffersize (buffer1) != 0 : makemargin! (buffer1, 0 ) == 0 )
649
+ while buffersize (buffer1) > 0
643
650
if state. code == :end
644
651
callstartproc (stream, :write )
645
652
end
646
- writedata! (stream. stream, buffer2)
647
- Δin, _ = callprocess (stream, buffer1, buffer2)
648
- nflushed += Δin
653
+ flush_buffer2 (stream)
654
+ callprocess (stream, buffer1, buffer2)
649
655
end
650
- return nflushed
651
- end
652
-
653
- function flushbufferall (stream:: TranscodingStream )
654
- return flushbuffer (stream, true )
656
+ # move positions to the start of the buffer
657
+ @assert ! iszero (makemargin! (buffer1, 0 ))
658
+ return
655
659
end
656
660
661
+ # This is always called after `flush_buffer1(stream)`
657
662
function flushuntilend (stream:: TranscodingStream )
658
- changemode! (stream, :write )
659
663
state = stream. state
660
664
buffer1 = stream. buffer1
661
665
buffer2 = stream. buffer2
666
+ @assert buffersize (buffer1) == 0
667
+ @assert stream. state. mode === :write
662
668
while state. code != :end
663
- writedata! (stream. stream, buffer2 )
669
+ flush_buffer2 (stream)
664
670
callprocess (stream, buffer1, buffer2)
665
671
end
666
- writedata! (stream. stream, buffer2)
667
- @assert buffersize (buffer1) == 0
672
+ flush_buffer2 (stream)
668
673
return
669
674
end
670
675
@@ -687,7 +692,7 @@ function callprocess(stream::TranscodingStream, inbuf::Buffer, outbuf::Buffer)
687
692
state = stream. state
688
693
input = buffermem (inbuf)
689
694
GC. @preserve inbuf makemargin! (outbuf, minoutsize (stream. codec, input))
690
- Δin, Δout, state. code = GC. @preserve inbuf outbuf process (stream. codec, input, marginmem (outbuf), state. error)
695
+ Δin:: Int , Δout:: Int , state. code = GC. @preserve inbuf outbuf process (stream. codec, input, marginmem (outbuf), state. error)
691
696
@debug (
692
697
" called process()" ,
693
698
code = state. code,
@@ -698,6 +703,12 @@ function callprocess(stream::TranscodingStream, inbuf::Buffer, outbuf::Buffer)
698
703
)
699
704
consumed! (inbuf, Δin, transcode = true )
700
705
supplied! (outbuf, Δout, transcode = true )
706
+ if has_sharedbuf (stream)
707
+ if stream. state. mode === :write
708
+ # this must be updated before throwing any error if outbuf is shared.
709
+ stream. state. bytes_written_out += Δout
710
+ end
711
+ end
701
712
if state. code == :error
702
713
changemode! (stream, :panic )
703
714
elseif state. code == :ok && Δin == Δout == 0
@@ -745,20 +756,28 @@ function readdata!(input::IO, output::Buffer)::Int
745
756
end
746
757
747
758
# Write all data to `output` from the buffer of `input`.
748
- function writedata! (output:: IO , input:: Buffer )
749
- if output isa TranscodingStream && output. buffer1 === input
759
+ function flush_buffer2 (stream:: TranscodingStream ):: Nothing
760
+ output = stream. stream
761
+ buffer2 = stream. buffer2
762
+ state = stream. state
763
+ @assert state. mode === :write
764
+ if has_sharedbuf (stream)
750
765
# Delegate the operation to the underlying stream for shared buffers.
751
- return flushbufferall (output)
752
- end
753
- nwritten:: Int = 0
754
- while buffersize (input) > 0
755
- n = GC. @preserve input Base. unsafe_write (output, bufferptr (input), buffersize (input))
756
- consumed! (input, n)
757
- nwritten += n
766
+ changemode! (output, :write )
767
+ flush_buffer1 (output)
768
+ else
769
+ while buffersize (buffer2) > 0
770
+ n:: Int = GC. @preserve buffer2 Base. unsafe_write (output, bufferptr (buffer2), buffersize (buffer2))
771
+ n ≤ 0 && error (" short write" )
772
+ consumed! (buffer2, n)
773
+ state. bytes_written_out += n
774
+ GC. safepoint ()
775
+ end
776
+ # move positions to the start of the buffer
777
+ @assert ! iszero (makemargin! (buffer2, 0 ))
758
778
GC. safepoint ()
759
779
end
760
- GC. safepoint ()
761
- return nwritten
780
+ nothing
762
781
end
763
782
764
783
@@ -800,7 +819,7 @@ function changemode!(stream::TranscodingStream, newmode::Symbol)
800
819
end
801
820
elseif mode == :write
802
821
if newmode == :close
803
- flushbufferall (stream)
822
+ flush_buffer1 (stream)
804
823
flushuntilend (stream)
805
824
state. mode = newmode
806
825
finalize_codec (stream. codec, state. error)
0 commit comments