readSourceFully function
- PdfByteSource source, {
- void onProgress()?,
- int chunk = 8 << 20,
- PdfCancelToken? cancelToken,
Reads a whole PdfByteSource into one contiguous buffer, reporting progress as it goes.
This is the background "finish the download" half of progressive open: PdfDocument.openSource paints the first page(s) from a sparse buffer of just the bytes it needs (zeros in the free space the parser never reads), then a host reads the rest with this and swaps the full buffer in. Unlike that first-paint buffer, the bytes returned here are the complete file - what the edit session, signing, and the render workers need.
Progress is reported to onProgress after each read as (received, total);
total is the document length when the source knows it, else null. Pass a
cancelToken to abort in flight - a fired token makes this throw
PdfHttpCancelledException between reads (and any read the source itself
aborts propagates). chunk bounds each read (and so the progress
granularity).
A known-length source is read forward in chunk windows until it is
exhausted; an unknown-length one is chunked until a short/empty read signals
the end.
Implementation
Future<Uint8List> readSourceFully(
PdfByteSource source, {
void Function(int received, int? total)? onProgress,
int chunk = 8 << 20,
PdfCancelToken? cancelToken,
}) async {
assert(chunk > 0);
final len = await source.length;
if (len != null && len >= 0) {
final out = Uint8List(len);
var pos = 0;
while (pos < len) {
cancelToken?.throwIfCancelled();
final end = pos + chunk < len ? pos + chunk : len;
final data = await source.readRange(pos, end);
if (data.isEmpty) break;
// Never trust a source to honour the requested length: a misbehaving one
// can answer with more bytes than asked for (a 200-style full body).
// Clamp so setRange can't run past the buffer.
final count = data.length < len - pos ? data.length : len - pos;
out.setRange(pos, pos + count, data);
pos += count;
onProgress?.call(pos, len);
}
return pos == len ? out : Uint8List.sublistView(out, 0, pos);
}
// Unknown length: chunk until a short read signals EOF.
final builder = BytesBuilder(copy: false);
var pos = 0;
while (true) {
cancelToken?.throwIfCancelled();
final data = await source.readRange(pos, pos + chunk);
if (data.isEmpty) break;
builder.add(data);
pos += data.length;
onProgress?.call(pos, null);
if (data.length < chunk) break;
}
return builder.toBytes();
}