/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// BEGIN base64 encode code copied and modified from NSPR constunsignedchar* const base =
(unsignedchar*)"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/";
// The Base64 encoder assumes all characters are less than 256; for 16-bit // strings, that means assuming that all characters are within range, and // masking off high bits if necessary. template <typename T>
uint8_t CharTo8Bit(T aChar) { return uint8_t(aChar);
}
EncodeInputStream_State<T>* state = static_cast<EncodeInputStream_State<T>*>(aClosure);
// We consume the whole data always.
*aWriteCount = aCount;
// If we have any data left from last time, encode it now.
uint32_t countRemaining = aCount; constunsignedchar* src = (constunsignedchar*)aFromSegment; if (state->charsOnStack) {
MOZ_ASSERT(state->charsOnStack == 1 || state->charsOnStack == 2);
// Not enough data to compose a triple. if (state->charsOnStack == 1 && countRemaining == 1) {
state->charsOnStack = 2;
state->c[1] = src[0]; return NS_OK;
}
// Nothing is left. if (!countRemaining) { return NS_OK;
}
}
// Encode as many full triplets as possible.
uint32_t encodeLength = countRemaining - countRemaining % 3;
MOZ_ASSERT(encodeLength % 3 == 0, "Should have an exact number of triplets!");
Encode(src, encodeLength, state->buffer);
state->buffer += (encodeLength / 3) * 4;
src += encodeLength;
countRemaining -= encodeLength;
if (countRemaining) { // We should never have a full triplet left at this point.
MOZ_ASSERT(countRemaining < 3, "We should have encoded more!");
state->c[0] = src[0];
state->c[1] = (countRemaining == 2) ? src[1] : '\0';
state->charsOnStack = countRemaining;
}
return NS_OK;
}
mozilla::Result<uint32_t, nsresult> CalculateBase64EncodedLength( const size_t aBinaryLen, const uint32_t aPrefixLen = 0) {
mozilla::CheckedUint32 res = aBinaryLen; // base 64 encoded length is 4/3rds the length of the input data, rounded up
res += 2;
res /= 3;
res *= 4;
res += aPrefixLen; if (!res.isValid()) { return mozilla::Err(NS_ERROR_FAILURE);
} return res.value();
}
if (!aCount) {
rv = aInputStream->Available(&count64); if (NS_WARN_IF(NS_FAILED(rv))) { return rv;
} // if count64 is over 4GB, it will be failed at the below condition, // then will return NS_ERROR_OUT_OF_MEMORY
aCount = (uint32_t)count64;
}
constauto base64LenOrErr = CalculateBase64EncodedLength(count64, aOffset); if (base64LenOrErr.isErr()) { // XXX For some reason, it was NS_ERROR_OUT_OF_MEMORY here instead of // NS_ERROR_FAILURE, so we keep that. return NS_ERROR_OUT_OF_MEMORY;
}
auto handleOrErr = aDest.BulkWrite(base64LenOrErr.inspect(), aOffset, false); if (handleOrErr.isErr()) { return handleOrErr.unwrapErr();
}
rv = aInputStream->ReadSegments(&EncodeInputStream_Encoder<T>,
(void*)&state, aCount, &read); if (NS_FAILED(rv)) { if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
MOZ_CRASH("Not implemented for async streams!");
} if (rv == NS_ERROR_NOT_IMPLEMENTED) {
MOZ_CRASH("Requires a stream that implements ReadSegments!");
} return rv;
}
if (!read) { break;
}
aCount -= read;
}
// Finish encoding if anything is left if (state.charsOnStack) {
Encode(state.c, state.charsOnStack, state.buffer);
state.buffer += 4;
}
// If we encountered EOF before reading aCount bytes, the resulting string // could be shorter than predicted, so determine the length from the state.
size_t trueLength = state.buffer - handle.Elements();
handle.Finish(trueLength, false);
return NS_OK;
}
// Maps an encoded character to a value in the Base64 alphabet, per // RFC 4648, Table 1. Invalid input characters map to UINT8_MAX.
auto handleOrErr = aBinary.BulkWrite(binaryLen, 0, false); if (handleOrErr.isErr()) { // Must not touch the handle if failing here, but we // already truncated the string at the top, so it's // unchanged. return handleOrErr.unwrapErr();
}
auto handle = handleOrErr.unwrap();
nsresult rv = Base64DecodeHelper(aBase64.BeginReading(), aBase64.Length(),
handle.Elements(), &binaryLen); if (NS_FAILED(rv)) { // Retruncate to match old semantics of this method.
handle.Finish(0, true); return rv;
}
// The decoded length may be 1-2 bytes over, depending on the final quantum.
uint32_t binaryLen = (base64Len * 3) / 4;
// Determine whether to check for and ignore trailing padding. bool maybePadded = false; switch (aPaddingPolicy) { case Base64URLDecodePaddingPolicy::Require: if (base64Len % 4) { // Padded input length must be a multiple of 4. return NS_ERROR_INVALID_ARG;
}
maybePadded = true; break;
case Base64URLDecodePaddingPolicy::Ignore: // Check for padding only if the length is a multiple of 4.
maybePadded = !(base64Len % 4); break;
// If we're expecting unpadded input, no need for additional checks. // `=` isn't in the decode table, so padded strings will fail to decode. default:
MOZ_FALLTHROUGH_ASSERT("Invalid decode padding policy"); case Base64URLDecodePaddingPolicy::Reject: break;
} if (maybePadded && base64[base64Len - 1] == '=') { if (base64[base64Len - 2] == '=') {
base64Len -= 2;
} else {
base64Len -= 1;
}
}
// Allocate a buffer large enough to hold the encoded string with padding. constauto base64LenOrErr = CalculateBase64EncodedLength(aBinaryLen); if (base64LenOrErr.isErr()) { return base64LenOrErr.inspectErr();
} const uint32_t base64Len = base64LenOrErr.inspect();
auto handleOrErr = aBase64.BulkWrite(base64Len, 0, false); if (handleOrErr.isErr()) { return handleOrErr.unwrapErr();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.