blob: f660f341ed206c83ecc4162e360d737b589903c0 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library crypto.base64.decoder_sink;
import 'dart:convert';
import 'decoder.dart';
/// A [ChunkedConversionSink] for decoding chunks of Base64 strings to data.
class Base64DecoderSink extends ChunkedConversionSink<String> {
/// The encoder used to decode each chunk.
final Base64Decoder _decoder = new Base64Decoder();
/// The underlying sink to which to emit the decoded strings.
final ChunkedConversionSink<List<int>> _outSink;
/// The as-yet-unconverted text.
///
/// This is used to handle text stopping partway through a four-character
/// 32-bit chunk.
String _unconverted = "";
Base64DecoderSink(this._outSink);
void add(String chunk) {
if (chunk.isEmpty) return;
if (_unconverted.isNotEmpty) chunk = _unconverted + chunk;
chunk = chunk.replaceAll("%3D", "=");
// The decodable length is the length of the initial substring comprising
// full four-character 32-bit chunks. Any leftovers are handled when [add]
// or [close] are next called.
var decodableLength = chunk.length;
if (chunk.length > 3 && chunk.contains("%", chunk.length - 2)) {
decodableLength = chunk.lastIndexOf("%");
}
decodableLength -= decodableLength % 4;
_unconverted = chunk.substring(decodableLength);
if (decodableLength > 0) {
_outSink.add(_decoder.convert(chunk.substring(0, decodableLength)));
}
}
void close() {
if (_unconverted.isNotEmpty) _outSink.add(_decoder.convert(_unconverted));
_outSink.close();
}
}