@@ -37,9 +37,30 @@ public final class GenericStreamReader : StreamReader {
37
37
reading up to given delimiters and there is no space left in the buffer. */
38
38
public var bufferSizeIncrement : Int
39
39
40
+ /**
41
+ Whether `EOF` has been reached, either because of `readSizeLimit` constraint,
42
+ or because end of underlying stream has been reached. See doc of
43
+ `readSizeLimit` for a few more info. */
44
+ public private( set) var streamHasReachedEOF = false
45
+ public private( set) var currentStreamReadPosition : Int
40
46
public private( set) var currentReadPosition = 0
41
47
42
- public var readSizeLimit : Int ?
48
+ /**
49
+ The maximum number of bytes that can be returned by the read methods (when
50
+ updating read position), and also the number of bytes that can be read from
51
+ the underlying stream.
52
+
53
+ Changing this to a greater value will force `streamHasReachedEOF` to `false`,
54
+ but next read might reach `EOF` directly regardless.
55
+
56
+ Changing this to a lower value will not change `streamHasReachedEOF` at all. */
57
+ public var readSizeLimit : Int ? {
58
+ didSet {
59
+ if readSizeLimit ?? Int . max > oldValue ?? Int . max {
60
+ streamHasReachedEOF = false
61
+ }
62
+ }
63
+ }
43
64
/**
44
65
The max size to read from the stream with a single read. Set to `nil` for no
45
66
max.
@@ -66,12 +87,15 @@ public final class GenericStreamReader : StreamReader {
66
87
- Parameter readSizeLimit: The maximum number of bytes allowed to be read
67
88
from the stream. Cannot be negative.
68
89
- Parameter underlyingStreamReadSizeLimit: The max size to read from the
69
- stream with a single read. Cannot be negative or 0. */
90
+ stream with a single read. Cannot be negative. If 0, the reader is
91
+ effectively forbidden from reading the underlying stream. If a read operation
92
+ is done that would require reading from the stream (not enough data in the
93
+ buffer), the `streamReadForbidden` error is thrown. */
70
94
public init ( stream: GenericReadStream , bufferSize size: Int , bufferSizeIncrement sizeIncrement: Int , readSizeLimit limit: Int ? = nil , underlyingStreamReadSizeLimit streamReadSizeLimit: Int ? = nil ) {
71
95
assert ( size > 0 )
72
96
assert ( sizeIncrement > 0 )
73
97
assert ( limit == nil || limit! >= 0 )
74
- assert ( streamReadSizeLimit == nil || streamReadSizeLimit! > 0 )
98
+ assert ( streamReadSizeLimit == nil || streamReadSizeLimit! >= 0 )
75
99
76
100
sourceStream = stream
77
101
@@ -83,7 +107,7 @@ public final class GenericStreamReader : StreamReader {
83
107
bufferStartPos = 0
84
108
bufferValidLength = 0
85
109
86
- totalReadBytesCount = 0
110
+ currentStreamReadPosition = 0
87
111
88
112
readSizeLimit = limit
89
113
underlyingStreamReadSizeLimit = streamReadSizeLimit
@@ -94,14 +118,43 @@ public final class GenericStreamReader : StreamReader {
94
118
bufferSize = 0
95
119
}
96
120
121
+ public func clearStreamHasReachedEOF( ) {
122
+ streamHasReachedEOF = false
123
+ }
124
+
125
+ /**
126
+ Reads `size` bytes from the underlying stream into the internal buffer and
127
+ returns the number of bytes read.
128
+
129
+ The `readSizeLimit` and `underlyingStreamReadSizeLimit` variables are
130
+ respected when using this method.
131
+
132
+ - Important: If the buffer is big enough, might read _more_ bytes than asked.
133
+ Can also read less (if the end of the stream is reached, or if only one read
134
+ is allowed and read returned less than asked).
135
+
136
+ - Parameter size: The number of bytes you want the buffer to be filled with
137
+ from the stream.
138
+ - Parameter allowMoreThanOneRead: If `true`, the method will read from the
139
+ stream until the asked size is read or the end of stream is reached.
140
+ - Returns: The number of bytes acutally read from the stream. */
141
+ public func readStreamInBuffer( size: Int , allowMoreThanOneRead: Bool = false ) throws -> Int {
142
+ let previousBufferValidLenth = bufferValidLength
143
+ _ = try readDataNoCurrentPosIncrement ( size: ( bufferValidLength + size) , readContraints: allowMoreThanOneRead ? . readUntilSizeOrStreamEnd : . readFromStreamMaxOnce)
144
+ let ret = ( bufferValidLength - previousBufferValidLenth)
145
+ assert ( ret >= 0 , " INTERNAL LOGIC ERROR " )
146
+ return ret
147
+ }
148
+
97
149
public func readData< T> ( size: Int , allowReadingLess: Bool , updateReadPosition: Bool , _ handler: ( UnsafeRawBufferPointer ) throws -> T ) throws -> T {
98
150
let ret = try readDataNoCurrentPosIncrement ( size: size, readContraints: allowReadingLess ? . readUntilSizeOrStreamEnd : . getExactSize)
151
+ assert ( ret. count <= bufferValidLength, " INTERNAL LOGIC ERROR " )
152
+ assert ( ret. count <= size, " INTERNAL LOGIC ERROR " )
99
153
if updateReadPosition {
100
154
currentReadPosition += ret. count
101
155
bufferValidLength -= ret. count
102
156
bufferStartPos += ret. count
103
157
}
104
- assert ( ret. count <= size, " INTERNAL ERROR " )
105
158
return try handler ( ret)
106
159
}
107
160
@@ -178,9 +231,6 @@ public final class GenericStreamReader : StreamReader {
178
231
private var bufferStartPos : Int
179
232
private var bufferValidLength : Int
180
233
181
- /** The total number of bytes read from the source stream. */
182
- private var totalReadBytesCount = 0
183
-
184
234
private enum ReadContraints {
185
235
case getExactSize
186
236
case readUntilSizeOrStreamEnd
@@ -192,15 +242,26 @@ public final class GenericStreamReader : StreamReader {
192
242
}
193
243
194
244
private func readDataNoCurrentPosIncrement( size: Int , readContraints: ReadContraints ) throws -> UnsafeRawBufferPointer {
245
+ assert ( size >= 0 )
246
+ /* If we want to read 0 bytes, whether we’ve reached EOF or we are allowed
247
+ * to read more bytes, we can return directly an empty buffer. */
248
+ guard size > 0 else { return UnsafeRawBufferPointer ( start: nil , count: 0 ) }
249
+ /* We check reading the given size is allowed. */
195
250
let allowedToBeRead = readSizeLimit. flatMap { $0 - currentReadPosition }
196
251
if let allowedToBeRead = allowedToBeRead, allowedToBeRead < size {
197
252
guard readContraints. allowReadingLess else {
198
253
throw StreamReaderError . notEnoughData ( wouldReachReadSizeLimit: true )
199
254
}
200
255
if allowedToBeRead <= 0 {
201
- return UnsafeRawBufferPointer ( start : nil , count : 0 )
256
+ streamHasReachedEOF = true
202
257
}
203
258
}
259
+ /* If we have reached EOF (not of the stream, the one of the reader), we
260
+ * know there is nothing more to return. */
261
+ guard !hasReachedEOF else {
262
+ if readContraints. allowReadingLess { return UnsafeRawBufferPointer ( start: nil , count: 0 ) }
263
+ else { throw StreamReaderError . notEnoughData ( wouldReachReadSizeLimit: true ) }
264
+ }
204
265
assert ( allowedToBeRead == nil || allowedToBeRead! >= 0 )
205
266
206
267
/* We constrain the size to the maximum allowed to be read. */
@@ -287,20 +348,31 @@ public final class GenericStreamReader : StreamReader {
287
348
288
349
let bufferStart = buffer + bufferStartPos
289
350
if bufferValidLength < size {
290
- /* The buffer does not contain enough: we read from the stream.
291
- * As per the specs of the function, we know there is enough space in
292
- * the buffer to hold the required size, and reading the given size
293
- * won’t break the readSizeLimit contract. */
351
+ /* The buffer does not contain enough: we read from the stream. */
294
352
repeat {
353
+ assert ( size - bufferValidLength > 0 , " INTERNAL LOGIC ERROR " )
354
+ /* We try and read as much bytes as possible from the stream */
355
+ let unconstrainedSizeToRead = bufferSize - ( bufferStartPos + bufferValidLength)
356
+ /* But we have to constrain to the size allowed to be read */
357
+ let sizeAllowedToBeRead : Int
358
+ if let readSizeLimit = readSizeLimit { sizeAllowedToBeRead = min ( readSizeLimit - currentStreamReadPosition, unconstrainedSizeToRead) }
359
+ else { sizeAllowedToBeRead = unconstrainedSizeToRead}
360
+ /* And to the underlying stream read size limit */
295
361
let sizeToRead : Int
296
- if let readLimit = underlyingStreamReadSizeLimit { sizeToRead = min ( readLimit, size - bufferValidLength) }
297
- else { sizeToRead = size - bufferValidLength}
298
- assert ( sizeToRead > 0 , " INTERNAL LOGIC ERROR " )
362
+ if let readLimit = underlyingStreamReadSizeLimit { sizeToRead = min ( readLimit, sizeAllowedToBeRead) }
363
+ else { sizeToRead = sizeAllowedToBeRead}
299
364
assert ( sizeToRead <= bufferSize - ( bufferStartPos + bufferValidLength) , " INTERNAL LOGIC ERROR " )
365
+
366
+ guard sizeToRead > 0 else {
367
+ assert ( underlyingStreamReadSizeLimit! == 0 , " INTERNAL LOGIC ERROR " )
368
+ throw StreamReaderError . streamReadForbidden
369
+ }
370
+
300
371
let sizeRead = try sourceStream. read ( bufferStart + bufferValidLength, maxLength: sizeToRead)
301
372
bufferValidLength += sizeRead
302
- totalReadBytesCount += sizeRead
303
- assert ( readSizeLimit == nil || totalReadBytesCount <= readSizeLimit!)
373
+ currentStreamReadPosition += sizeRead
374
+ if sizeRead == 0 { streamHasReachedEOF = true }
375
+ assert ( readSizeLimit == nil || currentStreamReadPosition <= readSizeLimit!)
304
376
305
377
if readContraints == . readFromStreamMaxOnce { break }
306
378
guard sizeRead > 0 else {
0 commit comments