mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 05:25:00 +00:00
Merge branch 'opencode/curious-river' into adam/bzip2-async
This commit is contained in:
@@ -281,6 +281,39 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
return retChar;
|
||||
}
|
||||
|
||||
public async Task<int> ReadByteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (streamEnd)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
var retChar = currentChar;
|
||||
switch (currentState)
|
||||
{
|
||||
case START_BLOCK_STATE:
|
||||
break;
|
||||
case RAND_PART_A_STATE:
|
||||
break;
|
||||
case RAND_PART_B_STATE:
|
||||
SetupRandPartB();
|
||||
break;
|
||||
case RAND_PART_C_STATE:
|
||||
SetupRandPartC();
|
||||
break;
|
||||
case NO_RAND_PART_A_STATE:
|
||||
break;
|
||||
case NO_RAND_PART_B_STATE:
|
||||
SetupNoRandPartB();
|
||||
break;
|
||||
case NO_RAND_PART_C_STATE:
|
||||
SetupNoRandPartC();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return retChar;
|
||||
}
|
||||
|
||||
private bool Initialize(bool isFirstStream)
|
||||
{
|
||||
var magic0 = bsStream.ReadByte();
|
||||
@@ -308,6 +341,49 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<bool> InitializeAsync(
|
||||
bool isFirstStream,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var singleByte = new byte[1];
|
||||
var read0 = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var magic0 = read0 == 0 ? -1 : singleByte[0];
|
||||
var read1 = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var magic1 = read1 == 0 ? -1 : singleByte[0];
|
||||
var read2 = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var magic2 = read2 == 0 ? -1 : singleByte[0];
|
||||
if (magic0 == -1 && !isFirstStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h')
|
||||
{
|
||||
throw new IOException("Not a BZIP2 marked stream");
|
||||
}
|
||||
var read3 = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
var magic3 = read3 == 0 ? -1 : singleByte[0];
|
||||
if (magic3 < '1' || magic3 > '9')
|
||||
{
|
||||
BsFinishedWithStream();
|
||||
streamEnd = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SetDecompressStructureSizes(magic3 - '0');
|
||||
bsLive = 0;
|
||||
computedCombinedCRC = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void InitBlock()
|
||||
{
|
||||
char magic1,
|
||||
@@ -375,6 +451,73 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
currentState = START_BLOCK_STATE;
|
||||
}
|
||||
|
||||
private async Task InitBlockAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
char magic1,
|
||||
magic2,
|
||||
magic3,
|
||||
magic4;
|
||||
char magic5,
|
||||
magic6;
|
||||
|
||||
while (true)
|
||||
{
|
||||
magic1 = await BsGetUCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
magic2 = await BsGetUCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
magic3 = await BsGetUCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
magic4 = await BsGetUCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
magic5 = await BsGetUCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
magic6 = await BsGetUCharAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (
|
||||
magic1 != 0x17
|
||||
|| magic2 != 0x72
|
||||
|| magic3 != 0x45
|
||||
|| magic4 != 0x38
|
||||
|| magic5 != 0x50
|
||||
|| magic6 != 0x90
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (await CompleteAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
magic1 != 0x31
|
||||
|| magic2 != 0x41
|
||||
|| magic3 != 0x59
|
||||
|| magic4 != 0x26
|
||||
|| magic5 != 0x53
|
||||
|| magic6 != 0x59
|
||||
)
|
||||
{
|
||||
BadBlockHeader();
|
||||
streamEnd = true;
|
||||
return;
|
||||
}
|
||||
|
||||
storedBlockCRC = await BsGetInt32Async(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (await BsRAsync(1, cancellationToken).ConfigureAwait(false) == 1)
|
||||
{
|
||||
blockRandomised = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockRandomised = false;
|
||||
}
|
||||
|
||||
// currBlockNo++;
|
||||
await GetAndMoveToFrontDecodeAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
mCrc.InitialiseCRC();
|
||||
currentState = START_BLOCK_STATE;
|
||||
}
|
||||
|
||||
private void EndBlock()
|
||||
{
|
||||
computedBlockCRC = mCrc.GetFinalCRC();
|
||||
@@ -408,6 +551,28 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
return complete;
|
||||
}
|
||||
|
||||
private async Task<bool> CompleteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
storedCombinedCRC = await BsGetInt32Async(cancellationToken).ConfigureAwait(false);
|
||||
if (storedCombinedCRC != computedCombinedCRC)
|
||||
{
|
||||
CrcError();
|
||||
}
|
||||
|
||||
var complete =
|
||||
!decompressConcatenated
|
||||
|| !(await InitializeAsync(false, cancellationToken).ConfigureAwait(false));
|
||||
if (complete)
|
||||
{
|
||||
BsFinishedWithStream();
|
||||
streamEnd = true;
|
||||
}
|
||||
|
||||
// Look for the next .bz2 stream if decompressing
|
||||
// concatenated files.
|
||||
return complete;
|
||||
}
|
||||
|
||||
private static void BlockOverrun() => Cadvise();
|
||||
|
||||
private static void BadBlockHeader() => Cadvise();
|
||||
@@ -456,8 +621,44 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
return v;
|
||||
}
|
||||
|
||||
private async Task<int> BsRAsync(int n, CancellationToken cancellationToken)
|
||||
{
|
||||
var singleByte = new byte[1];
|
||||
int v;
|
||||
while (bsLive < n)
|
||||
{
|
||||
int zzi;
|
||||
int thech = '\0';
|
||||
try
|
||||
{
|
||||
var readCount = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
thech = readCount == 0 ? '\uffff' : singleByte[0];
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
CompressedStreamEOF();
|
||||
}
|
||||
if (thech == '\uffff')
|
||||
{
|
||||
CompressedStreamEOF();
|
||||
}
|
||||
zzi = thech;
|
||||
bsBuff = (bsBuff << 8) | (zzi & 0xff);
|
||||
bsLive += 8;
|
||||
}
|
||||
|
||||
v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
|
||||
bsLive -= n;
|
||||
return v;
|
||||
}
|
||||
|
||||
private char BsGetUChar() => (char)BsR(8);
|
||||
|
||||
private async Task<char> BsGetUCharAsync(CancellationToken cancellationToken) =>
|
||||
(char)(await BsRAsync(8, cancellationToken).ConfigureAwait(false));
|
||||
|
||||
private int BsGetint()
|
||||
{
|
||||
var u = 0;
|
||||
@@ -468,10 +669,26 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
return u;
|
||||
}
|
||||
|
||||
private async Task<int> BsGetintAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var u = 0;
|
||||
u = (u << 8) | (await BsRAsync(8, cancellationToken).ConfigureAwait(false));
|
||||
u = (u << 8) | (await BsRAsync(8, cancellationToken).ConfigureAwait(false));
|
||||
u = (u << 8) | (await BsRAsync(8, cancellationToken).ConfigureAwait(false));
|
||||
u = (u << 8) | (await BsRAsync(8, cancellationToken).ConfigureAwait(false));
|
||||
return u;
|
||||
}
|
||||
|
||||
private int BsGetIntVS(int numBits) => BsR(numBits);
|
||||
|
||||
private Task<int> BsGetIntVSAsync(int numBits, CancellationToken cancellationToken) =>
|
||||
BsRAsync(numBits, cancellationToken);
|
||||
|
||||
private int BsGetInt32() => BsGetint();
|
||||
|
||||
private Task<int> BsGetInt32Async(CancellationToken cancellationToken) =>
|
||||
BsGetintAsync(cancellationToken);
|
||||
|
||||
private void HbCreateDecodeTables(
|
||||
int[] limit,
|
||||
int[] basev,
|
||||
@@ -664,6 +881,138 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RecvDecodingTablesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
|
||||
int i,
|
||||
j,
|
||||
t,
|
||||
nGroups,
|
||||
nSelectors,
|
||||
alphaSize;
|
||||
int minLen,
|
||||
maxLen;
|
||||
var inUse16 = new bool[16];
|
||||
|
||||
/* Receive the mapping table */
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (await BsRAsync(1, cancellationToken).ConfigureAwait(false) == 1)
|
||||
{
|
||||
inUse16[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
inUse16[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
inUse[i] = false;
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (inUse16[i])
|
||||
{
|
||||
for (j = 0; j < 16; j++)
|
||||
{
|
||||
if (await BsRAsync(1, cancellationToken).ConfigureAwait(false) == 1)
|
||||
{
|
||||
inUse[(i * 16) + j] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MakeMaps();
|
||||
alphaSize = nInUse + 2;
|
||||
|
||||
/* Now the selectors */
|
||||
nGroups = await BsRAsync(3, cancellationToken).ConfigureAwait(false);
|
||||
nSelectors = await BsRAsync(15, cancellationToken).ConfigureAwait(false);
|
||||
for (i = 0; i < nSelectors; i++)
|
||||
{
|
||||
j = 0;
|
||||
while (await BsRAsync(1, cancellationToken).ConfigureAwait(false) == 1)
|
||||
{
|
||||
j++;
|
||||
}
|
||||
if (i < BZip2Constants.MAX_SELECTORS)
|
||||
{
|
||||
selectorMtf[i] = (char)j;
|
||||
}
|
||||
}
|
||||
|
||||
nSelectors = Math.Min(nSelectors, BZip2Constants.MAX_SELECTORS);
|
||||
|
||||
/* Undo the MTF values for the selectors. */
|
||||
{
|
||||
var pos = new char[BZip2Constants.N_GROUPS];
|
||||
char tmp,
|
||||
v;
|
||||
for (v = '\0'; v < nGroups; v++)
|
||||
{
|
||||
pos[v] = v;
|
||||
}
|
||||
|
||||
for (i = 0; i < nSelectors; i++)
|
||||
{
|
||||
v = selectorMtf[i];
|
||||
tmp = pos[v];
|
||||
while (v > 0)
|
||||
{
|
||||
pos[v] = pos[v - 1];
|
||||
v--;
|
||||
}
|
||||
pos[0] = tmp;
|
||||
selector[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the coding tables */
|
||||
for (t = 0; t < nGroups; t++)
|
||||
{
|
||||
var curr = await BsRAsync(5, cancellationToken).ConfigureAwait(false);
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
{
|
||||
while (await BsRAsync(1, cancellationToken).ConfigureAwait(false) == 1)
|
||||
{
|
||||
if (await BsRAsync(1, cancellationToken).ConfigureAwait(false) == 0)
|
||||
{
|
||||
curr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr--;
|
||||
}
|
||||
}
|
||||
len[t][i] = (char)curr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the Huffman decoding tables */
|
||||
for (t = 0; t < nGroups; t++)
|
||||
{
|
||||
minLen = 32;
|
||||
maxLen = 0;
|
||||
for (i = 0; i < alphaSize; i++)
|
||||
{
|
||||
if (len[t][i] > maxLen)
|
||||
{
|
||||
maxLen = len[t][i];
|
||||
}
|
||||
if (len[t][i] < minLen)
|
||||
{
|
||||
minLen = len[t][i];
|
||||
}
|
||||
}
|
||||
HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen, maxLen, alphaSize);
|
||||
minLens[t] = minLen;
|
||||
}
|
||||
}
|
||||
|
||||
private void GetAndMoveToFrontDecode()
|
||||
{
|
||||
var yy = new char[256];
|
||||
@@ -918,6 +1267,270 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetAndMoveToFrontDecodeAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var yy = new char[256];
|
||||
int i,
|
||||
j,
|
||||
nextSym,
|
||||
limitLast;
|
||||
int EOB,
|
||||
groupNo,
|
||||
groupPos;
|
||||
var singleByte = new byte[1];
|
||||
|
||||
limitLast = BZip2Constants.baseBlockSize * blockSize100k;
|
||||
origPtr = await BsGetIntVSAsync(24, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await RecvDecodingTablesAsync(cancellationToken).ConfigureAwait(false);
|
||||
EOB = nInUse + 1;
|
||||
groupNo = -1;
|
||||
groupPos = 0;
|
||||
|
||||
/*
|
||||
Setting up the unzftab entries here is not strictly
|
||||
necessary, but it does save having to do it later
|
||||
in a separate pass, and so saves a block's worth of
|
||||
cache misses.
|
||||
*/
|
||||
for (i = 0; i <= 255; i++)
|
||||
{
|
||||
unzftab[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i <= 255; i++)
|
||||
{
|
||||
yy[i] = (char)i;
|
||||
}
|
||||
|
||||
last = -1;
|
||||
|
||||
{
|
||||
int zt,
|
||||
zn,
|
||||
zvec,
|
||||
zj;
|
||||
if (groupPos == 0)
|
||||
{
|
||||
groupNo++;
|
||||
groupPos = BZip2Constants.G_SIZE;
|
||||
}
|
||||
groupPos--;
|
||||
zt = selector[groupNo];
|
||||
zn = minLens[zt];
|
||||
zvec = await BsRAsync(zn, cancellationToken).ConfigureAwait(false);
|
||||
while (zvec > limit[zt][zn])
|
||||
{
|
||||
zn++;
|
||||
{
|
||||
{
|
||||
while (bsLive < 1)
|
||||
{
|
||||
int zzi;
|
||||
int thech = '\0';
|
||||
try
|
||||
{
|
||||
var readCount = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
thech = readCount == 0 ? '\uffff' : singleByte[0];
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
CompressedStreamEOF();
|
||||
}
|
||||
if (thech == '\uffff')
|
||||
{
|
||||
CompressedStreamEOF();
|
||||
}
|
||||
zzi = thech;
|
||||
bsBuff = (bsBuff << 8) | (zzi & 0xff);
|
||||
bsLive += 8;
|
||||
}
|
||||
}
|
||||
zj = (bsBuff >> (bsLive - 1)) & 1;
|
||||
bsLive--;
|
||||
}
|
||||
zvec = (zvec << 1) | zj;
|
||||
}
|
||||
nextSym = perm[zt][zvec - basev[zt][zn]];
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (nextSym == EOB)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB)
|
||||
{
|
||||
char ch;
|
||||
var s = -1;
|
||||
var N = 1;
|
||||
do
|
||||
{
|
||||
if (nextSym == BZip2Constants.RUNA)
|
||||
{
|
||||
s += (0 + 1) * N;
|
||||
}
|
||||
else if (nextSym == BZip2Constants.RUNB)
|
||||
{
|
||||
s += (1 + 1) * N;
|
||||
}
|
||||
N *= 2;
|
||||
{
|
||||
int zt,
|
||||
zn,
|
||||
zvec,
|
||||
zj;
|
||||
if (groupPos == 0)
|
||||
{
|
||||
groupNo++;
|
||||
groupPos = BZip2Constants.G_SIZE;
|
||||
}
|
||||
groupPos--;
|
||||
zt = selector[groupNo];
|
||||
zn = minLens[zt];
|
||||
zvec = await BsRAsync(zn, cancellationToken).ConfigureAwait(false);
|
||||
while (zvec > limit[zt][zn])
|
||||
{
|
||||
zn++;
|
||||
{
|
||||
{
|
||||
while (bsLive < 1)
|
||||
{
|
||||
int zzi;
|
||||
int thech = '\0';
|
||||
try
|
||||
{
|
||||
var readCount = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
thech = readCount == 0 ? '\uffff' : singleByte[0];
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
CompressedStreamEOF();
|
||||
}
|
||||
if (thech == '\uffff')
|
||||
{
|
||||
CompressedStreamEOF();
|
||||
}
|
||||
zzi = thech;
|
||||
bsBuff = (bsBuff << 8) | (zzi & 0xff);
|
||||
bsLive += 8;
|
||||
}
|
||||
}
|
||||
zj = (bsBuff >> (bsLive - 1)) & 1;
|
||||
bsLive--;
|
||||
}
|
||||
zvec = (zvec << 1) | zj;
|
||||
}
|
||||
nextSym = perm[zt][zvec - basev[zt][zn]];
|
||||
}
|
||||
} while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);
|
||||
|
||||
s++;
|
||||
ch = seqToUnseq[yy[0]];
|
||||
unzftab[ch] += s;
|
||||
|
||||
while (s > 0)
|
||||
{
|
||||
last++;
|
||||
ll8[last] = ch;
|
||||
s--;
|
||||
}
|
||||
|
||||
if (last >= limitLast)
|
||||
{
|
||||
BlockOverrun();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char tmp;
|
||||
last++;
|
||||
if (last >= limitLast)
|
||||
{
|
||||
BlockOverrun();
|
||||
}
|
||||
|
||||
tmp = yy[nextSym - 1];
|
||||
unzftab[seqToUnseq[tmp]]++;
|
||||
ll8[last] = seqToUnseq[tmp];
|
||||
|
||||
/*
|
||||
This loop is hammered during decompression,
|
||||
hence the unrolling.
|
||||
|
||||
for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1];
|
||||
*/
|
||||
|
||||
j = nextSym - 1;
|
||||
for (; j > 3; j -= 4)
|
||||
{
|
||||
yy[j] = yy[j - 1];
|
||||
yy[j - 1] = yy[j - 2];
|
||||
yy[j - 2] = yy[j - 3];
|
||||
yy[j - 3] = yy[j - 4];
|
||||
}
|
||||
for (; j > 0; j--)
|
||||
{
|
||||
yy[j] = yy[j - 1];
|
||||
}
|
||||
|
||||
yy[0] = tmp;
|
||||
{
|
||||
int zt,
|
||||
zn,
|
||||
zvec,
|
||||
zj;
|
||||
if (groupPos == 0)
|
||||
{
|
||||
groupNo++;
|
||||
groupPos = BZip2Constants.G_SIZE;
|
||||
}
|
||||
groupPos--;
|
||||
zt = selector[groupNo];
|
||||
zn = minLens[zt];
|
||||
zvec = await BsRAsync(zn, cancellationToken).ConfigureAwait(false);
|
||||
while (zvec > limit[zt][zn])
|
||||
{
|
||||
zn++;
|
||||
{
|
||||
{
|
||||
while (bsLive < 1)
|
||||
{
|
||||
int zzi;
|
||||
int thech = '\0';
|
||||
try
|
||||
{
|
||||
var readCount = await bsStream
|
||||
.ReadAsync(singleByte, 0, 1, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
thech = readCount == 0 ? '\uffff' : singleByte[0];
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
CompressedStreamEOF();
|
||||
}
|
||||
zzi = thech;
|
||||
bsBuff = (bsBuff << 8) | (zzi & 0xff);
|
||||
bsLive += 8;
|
||||
}
|
||||
}
|
||||
zj = (bsBuff >> (bsLive - 1)) & 1;
|
||||
bsLive--;
|
||||
}
|
||||
zvec = (zvec << 1) | zj;
|
||||
}
|
||||
nextSym = perm[zt][zvec - basev[zt][zn]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupBlock()
|
||||
{
|
||||
Span<int> cftab = stackalloc int[257];
|
||||
@@ -1147,7 +1760,7 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
return k;
|
||||
}
|
||||
|
||||
public override Task<int> ReadAsync(
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int count,
|
||||
@@ -1159,14 +1772,14 @@ internal class CBZip2InputStream : Stream, IStreamStack
|
||||
for (k = 0; k < count; ++k)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
c = ReadByte();
|
||||
c = await ReadByteAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (c == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
buffer[k + offset] = (byte)c;
|
||||
}
|
||||
return Task.FromResult(k);
|
||||
return k;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) => 0;
|
||||
|
||||
Reference in New Issue
Block a user