| ... | @@ -246,18 +246,41 @@ pub fn appendRemaining( | ... | @@ -246,18 +246,41 @@ pub fn appendRemaining( |
| 246 | limit: Limit, | 246 | limit: Limit, |
| 247 | ) LimitedAllocError!void { | 247 | ) LimitedAllocError!void { |
| 248 | assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data. | 248 | assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data. |
| 249 | var remaining = limit; | 249 | const buffer_contents = r.buffer[r.seek..r.end]; |
| 250 | while (remaining.nonzero()) { | 250 | const copy_len = limit.minInt(buffer_contents.len); |
| 251 | try list.ensureUnusedCapacity(gpa, r.bufferedLen() + 1); | 251 | try list.appendSlice(gpa, r.buffer[0..copy_len]); |
| 252 | const dest = remaining.slice(list.unusedCapacitySlice()); | 252 | r.seek += copy_len; |
| 253 | const n = readVecLimit(r, &.{dest}, .unlimited) catch |err| switch (err) { | 253 | if (buffer_contents.len - copy_len != 0) return error.StreamTooLong; |
| 254 | error.EndOfStream => break, | 254 | r.seek = 0; |
| 255 | error.ReadFailed => return error.ReadFailed, | 255 | r.end = 0; |
| 256 | }; | 256 | var remaining = @intFromEnum(limit) - copy_len; |
| 257 | list.items.len += n; | 257 | while (true) { |
| 258 | remaining = remaining.subtract(n).?; | 258 | try list.ensureUnusedCapacity(gpa, 1); |
| | 259 | const cap = list.unusedCapacitySlice(); |
| | 260 | const dest = cap[0..@min(cap.len, remaining)]; |
| | 261 | if (remaining - dest.len == 0) { |
| | 262 | // Additionally provides `buffer` to detect end. |
| | 263 | const new_remaining = readVecInner(r, &.{}, dest, remaining) catch |err| switch (err) { |
| | 264 | error.EndOfStream => { |
| | 265 | if (r.bufferedLen() != 0) return error.StreamTooLong; |
| | 266 | return; |
| | 267 | }, |
| | 268 | error.ReadFailed => return error.ReadFailed, |
| | 269 | }; |
| | 270 | list.items.len += remaining - new_remaining; |
| | 271 | remaining = new_remaining; |
| | 272 | } else { |
| | 273 | // Leave `buffer` empty, appending directly to `list`. |
| | 274 | var dest_w: Writer = .fixed(dest); |
| | 275 | const n = r.vtable.stream(r, &dest_w, .limited(dest.len)) catch |err| switch (err) { |
| | 276 | error.WriteFailed => unreachable, // Prevented by the limit. |
| | 277 | error.EndOfStream => return, |
| | 278 | error.ReadFailed => return error.ReadFailed, |
| | 279 | }; |
| | 280 | list.items.len += n; |
| | 281 | remaining -= n; |
| | 282 | } |
| 259 | } | 283 | } |
| 260 | if (r.bufferedLen() != 0) return error.StreamTooLong; | | |
| 261 | } | 284 | } |
| 262 | | 285 | |
| 263 | /// Writes bytes from the internally tracked stream position to `data`. | 286 | /// Writes bytes from the internally tracked stream position to `data`. |
| ... | @@ -297,60 +320,66 @@ pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize { | ... | @@ -297,60 +320,66 @@ pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize { |
| 297 | // buffer capacity requirements met. | 320 | // buffer capacity requirements met. |
| 298 | r.seek = 0; | 321 | r.seek = 0; |
| 299 | r.end = 0; | 322 | r.end = 0; |
| 300 | const first = buf[copy_len..]; | 323 | remaining = try readVecInner(r, data[i + 1 ..], buf[copy_len..], remaining); |
| 301 | const middle = data[i + 1 ..]; | 324 | break; |
| 302 | var wrapper: Writer.VectorWrapper = .{ | 325 | } |
| 303 | .it = .{ | 326 | return @intFromEnum(limit) - remaining; |
| 304 | .first = first, | 327 | } |
| 305 | .middle = middle, | 328 | |
| 306 | .last = r.buffer, | 329 | fn readVecInner(r: *Reader, middle: []const []u8, first: []u8, remaining: usize) Error!usize { |
| 307 | }, | 330 | var wrapper: Writer.VectorWrapper = .{ |
| 308 | .writer = .{ | 331 | .it = .{ |
| 309 | .buffer = if (first.len >= r.buffer.len) first else r.buffer, | 332 | .first = first, |
| 310 | .vtable = Writer.VectorWrapper.vtable, | 333 | .middle = middle, |
| 311 | }, | 334 | .last = r.buffer, |
| 312 | }; | 335 | }, |
| 313 | var n = r.vtable.stream(r, &wrapper.writer, .limited(remaining)) catch |err| switch (err) { | 336 | .writer = .{ |
| 314 | error.WriteFailed => { | 337 | .buffer = if (first.len >= r.buffer.len) first else r.buffer, |
| 315 | assert(!wrapper.used); | 338 | .vtable = Writer.VectorWrapper.vtable, |
| 316 | if (wrapper.writer.buffer.ptr == first.ptr) { | 339 | }, |
| 317 | remaining -= wrapper.writer.end; | 340 | }; |
| 318 | } else { | 341 | // If the limit may pass beyond user buffer into Reader buffer, use |
| 319 | assert(wrapper.writer.end <= r.buffer.len); | 342 | // unlimited, allowing the Reader buffer to fill. |
| 320 | r.end = wrapper.writer.end; | 343 | const limit: Limit = l: { |
| 321 | } | 344 | var n: usize = first.len; |
| 322 | break; | 345 | for (middle) |m| n += m.len; |
| 323 | }, | 346 | break :l if (remaining >= n) .unlimited else .limited(remaining); |
| 324 | else => |e| return e, | 347 | }; |
| 325 | }; | 348 | var n = r.vtable.stream(r, &wrapper.writer, limit) catch |err| switch (err) { |
| 326 | if (!wrapper.used) { | 349 | error.WriteFailed => { |
| | 350 | assert(!wrapper.used); |
| 327 | if (wrapper.writer.buffer.ptr == first.ptr) { | 351 | if (wrapper.writer.buffer.ptr == first.ptr) { |
| 328 | remaining -= n; | 352 | return remaining - wrapper.writer.end; |
| 329 | } else { | 353 | } else { |
| 330 | assert(n <= r.buffer.len); | 354 | assert(wrapper.writer.end <= r.buffer.len); |
| 331 | r.end = n; | 355 | r.end = wrapper.writer.end; |
| | 356 | return remaining; |
| 332 | } | 357 | } |
| 333 | break; | 358 | }, |
| 334 | } | 359 | else => |e| return e, |
| 335 | if (n < first.len) { | 360 | }; |
| 336 | remaining -= n; | 361 | if (!wrapper.used) { |
| 337 | break; | 362 | if (wrapper.writer.buffer.ptr == first.ptr) { |
| | 363 | return remaining - n; |
| | 364 | } else { |
| | 365 | assert(n <= r.buffer.len); |
| | 366 | r.end = n; |
| | 367 | return remaining; |
| 338 | } | 368 | } |
| 339 | remaining -= first.len; | 369 | } |
| 340 | n -= first.len; | 370 | if (n < first.len) return remaining - n; |
| 341 | for (middle) |mid| { | 371 | var result = remaining - first.len; |
| 342 | if (n < mid.len) { | 372 | n -= first.len; |
| 343 | remaining -= n; | 373 | for (middle) |mid| { |
| 344 | break; | 374 | if (n < mid.len) { |
| 345 | } | 375 | return result - n; |
| 346 | remaining -= mid.len; | | |
| 347 | n -= mid.len; | | |
| 348 | } | 376 | } |
| 349 | assert(n <= r.buffer.len); | 377 | result -= mid.len; |
| 350 | r.end = n; | 378 | n -= mid.len; |
| 351 | break; | | |
| 352 | } | 379 | } |
| 353 | return @intFromEnum(limit) - remaining; | 380 | assert(n <= r.buffer.len); |
| | 381 | r.end = n; |
| | 382 | return result; |
| 354 | } | 383 | } |
| 355 | | 384 | |
| 356 | pub fn buffered(r: *Reader) []u8 { | 385 | pub fn buffered(r: *Reader) []u8 { |