init commit
This commit is contained in:
@@ -0,0 +1,522 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Org.BouncyCastle.Asn1;
|
||||
using Org.BouncyCastle.Asn1.Cms;
|
||||
using Org.BouncyCastle.Asn1.X509;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.IO;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Security;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
using Org.BouncyCastle.Utilities.Collections;
|
||||
using Org.BouncyCastle.Utilities.IO;
|
||||
using Org.BouncyCastle.X509;
|
||||
|
||||
namespace Org.BouncyCastle.Cms;
|
||||
|
||||
public class CmsSignedDataStreamGenerator : CmsSignedGenerator
|
||||
{
|
||||
private class DigestAndSignerInfoGeneratorHolder
|
||||
{
|
||||
internal readonly ISignerInfoGenerator signerInf;
|
||||
|
||||
internal readonly string digestOID;
|
||||
|
||||
internal AlgorithmIdentifier DigestAlgorithm => new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), DerNull.Instance);
|
||||
|
||||
internal DigestAndSignerInfoGeneratorHolder(ISignerInfoGenerator signerInf, string digestOID)
|
||||
{
|
||||
this.signerInf = signerInf;
|
||||
this.digestOID = digestOID;
|
||||
}
|
||||
}
|
||||
|
||||
private class SignerInfoGeneratorImpl : ISignerInfoGenerator
|
||||
{
|
||||
private readonly CmsSignedDataStreamGenerator outer;
|
||||
|
||||
private readonly SignerIdentifier _signerIdentifier;
|
||||
|
||||
private readonly string _digestOID;
|
||||
|
||||
private readonly string _encOID;
|
||||
|
||||
private readonly CmsAttributeTableGenerator _sAttr;
|
||||
|
||||
private readonly CmsAttributeTableGenerator _unsAttr;
|
||||
|
||||
private readonly string _encName;
|
||||
|
||||
private readonly ISigner _sig;
|
||||
|
||||
internal SignerInfoGeneratorImpl(CmsSignedDataStreamGenerator outer, AsymmetricKeyParameter key, SignerIdentifier signerIdentifier, string digestOID, string encOID, CmsAttributeTableGenerator sAttr, CmsAttributeTableGenerator unsAttr)
|
||||
{
|
||||
this.outer = outer;
|
||||
_signerIdentifier = signerIdentifier;
|
||||
_digestOID = digestOID;
|
||||
_encOID = encOID;
|
||||
_sAttr = sAttr;
|
||||
_unsAttr = unsAttr;
|
||||
_encName = Helper.GetEncryptionAlgName(_encOID);
|
||||
string digestAlgName = Helper.GetDigestAlgName(_digestOID);
|
||||
string algorithm = digestAlgName + "with" + _encName;
|
||||
if (_sAttr != null)
|
||||
{
|
||||
_sig = Helper.GetSignatureInstance(algorithm);
|
||||
}
|
||||
else if (_encName.Equals("RSA"))
|
||||
{
|
||||
_sig = Helper.GetSignatureInstance("RSA");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_encName.Equals("DSA"))
|
||||
{
|
||||
throw new SignatureException("algorithm: " + _encName + " not supported in base signatures.");
|
||||
}
|
||||
_sig = Helper.GetSignatureInstance("NONEwithDSA");
|
||||
}
|
||||
_sig.Init(forSigning: true, new ParametersWithRandom(key, outer.rand));
|
||||
}
|
||||
|
||||
public SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm, byte[] calculatedDigest)
|
||||
{
|
||||
try
|
||||
{
|
||||
string digestAlgName = Helper.GetDigestAlgName(_digestOID);
|
||||
string algorithm = digestAlgName + "with" + _encName;
|
||||
byte[] array = calculatedDigest;
|
||||
Asn1Set asn1Set = null;
|
||||
if (_sAttr != null)
|
||||
{
|
||||
IDictionary baseParameters = outer.GetBaseParameters(contentType, digestAlgorithm, calculatedDigest);
|
||||
Org.BouncyCastle.Asn1.Cms.AttributeTable attributeTable = _sAttr.GetAttributes(baseParameters);
|
||||
if (contentType == null && attributeTable != null && attributeTable[CmsAttributes.ContentType] != null)
|
||||
{
|
||||
IDictionary dictionary = attributeTable.ToDictionary();
|
||||
dictionary.Remove(CmsAttributes.ContentType);
|
||||
attributeTable = new Org.BouncyCastle.Asn1.Cms.AttributeTable(dictionary);
|
||||
}
|
||||
asn1Set = outer.GetAttributeSet(attributeTable);
|
||||
array = asn1Set.GetEncoded("DER");
|
||||
}
|
||||
else if (_encName.Equals("RSA"))
|
||||
{
|
||||
DigestInfo digestInfo = new DigestInfo(digestAlgorithm, calculatedDigest);
|
||||
array = digestInfo.GetEncoded("DER");
|
||||
}
|
||||
_sig.BlockUpdate(array, 0, array.Length);
|
||||
byte[] array2 = _sig.GenerateSignature();
|
||||
Asn1Set unauthenticatedAttributes = null;
|
||||
if (_unsAttr != null)
|
||||
{
|
||||
IDictionary baseParameters2 = outer.GetBaseParameters(contentType, digestAlgorithm, calculatedDigest);
|
||||
baseParameters2[CmsAttributeTableParameter.Signature] = array2.Clone();
|
||||
Org.BouncyCastle.Asn1.Cms.AttributeTable attributes = _unsAttr.GetAttributes(baseParameters2);
|
||||
unauthenticatedAttributes = outer.GetAttributeSet(attributes);
|
||||
}
|
||||
Asn1Encodable defaultX509Parameters = SignerUtilities.GetDefaultX509Parameters(algorithm);
|
||||
AlgorithmIdentifier encAlgorithmIdentifier = Helper.GetEncAlgorithmIdentifier(new DerObjectIdentifier(_encOID), defaultX509Parameters);
|
||||
return new SignerInfo(_signerIdentifier, digestAlgorithm, asn1Set, encAlgorithmIdentifier, new DerOctetString(array2), unauthenticatedAttributes);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new CmsStreamException("encoding error.", e);
|
||||
}
|
||||
catch (SignatureException e2)
|
||||
{
|
||||
throw new CmsStreamException("error creating signature.", e2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CmsSignedDataOutputStream : BaseOutputStream
|
||||
{
|
||||
private readonly CmsSignedDataStreamGenerator outer;
|
||||
|
||||
private Stream _out;
|
||||
|
||||
private DerObjectIdentifier _contentOID;
|
||||
|
||||
private BerSequenceGenerator _sGen;
|
||||
|
||||
private BerSequenceGenerator _sigGen;
|
||||
|
||||
private BerSequenceGenerator _eiGen;
|
||||
|
||||
public CmsSignedDataOutputStream(CmsSignedDataStreamGenerator outer, Stream outStream, string contentOID, BerSequenceGenerator sGen, BerSequenceGenerator sigGen, BerSequenceGenerator eiGen)
|
||||
{
|
||||
this.outer = outer;
|
||||
_out = outStream;
|
||||
_contentOID = new DerObjectIdentifier(contentOID);
|
||||
_sGen = sGen;
|
||||
_sigGen = sigGen;
|
||||
_eiGen = eiGen;
|
||||
}
|
||||
|
||||
public override void WriteByte(byte b)
|
||||
{
|
||||
_out.WriteByte(b);
|
||||
}
|
||||
|
||||
public override void Write(byte[] bytes, int off, int len)
|
||||
{
|
||||
_out.Write(bytes, off, len);
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
DoClose();
|
||||
base.Close();
|
||||
}
|
||||
|
||||
private void DoClose()
|
||||
{
|
||||
Platform.Dispose(_out);
|
||||
_eiGen.Close();
|
||||
outer._digests.Clear();
|
||||
if (outer._certs.Count > 0)
|
||||
{
|
||||
Asn1Set obj = (outer.UseDerForCerts ? CmsUtilities.CreateDerSetFromList(outer._certs) : CmsUtilities.CreateBerSetFromList(outer._certs));
|
||||
WriteToGenerator(_sigGen, new BerTaggedObject(explicitly: false, 0, obj));
|
||||
}
|
||||
if (outer._crls.Count > 0)
|
||||
{
|
||||
Asn1Set obj2 = (outer.UseDerForCrls ? CmsUtilities.CreateDerSetFromList(outer._crls) : CmsUtilities.CreateBerSetFromList(outer._crls));
|
||||
WriteToGenerator(_sigGen, new BerTaggedObject(explicitly: false, 1, obj2));
|
||||
}
|
||||
foreach (object messageDigest in outer._messageDigests)
|
||||
{
|
||||
DictionaryEntry dictionaryEntry = (DictionaryEntry)messageDigest;
|
||||
outer._messageHashes.Add(dictionaryEntry.Key, DigestUtilities.DoFinal((IDigest)dictionaryEntry.Value));
|
||||
}
|
||||
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector();
|
||||
foreach (DigestAndSignerInfoGeneratorHolder signerInf in outer._signerInfs)
|
||||
{
|
||||
AlgorithmIdentifier digestAlgorithm = signerInf.DigestAlgorithm;
|
||||
byte[] array = (byte[])outer._messageHashes[Helper.GetDigestAlgName(signerInf.digestOID)];
|
||||
outer._digests[signerInf.digestOID] = array.Clone();
|
||||
asn1EncodableVector.Add(signerInf.signerInf.Generate(_contentOID, digestAlgorithm, array));
|
||||
}
|
||||
foreach (SignerInformation signer in outer._signers)
|
||||
{
|
||||
asn1EncodableVector.Add(signer.ToSignerInfo());
|
||||
}
|
||||
WriteToGenerator(_sigGen, new DerSet(asn1EncodableVector));
|
||||
_sigGen.Close();
|
||||
_sGen.Close();
|
||||
}
|
||||
|
||||
private static void WriteToGenerator(Asn1Generator ag, Asn1Encodable ae)
|
||||
{
|
||||
byte[] encoded = ae.GetEncoded();
|
||||
ag.GetRawOutputStream().Write(encoded, 0, encoded.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
|
||||
|
||||
private readonly IList _signerInfs = Platform.CreateArrayList();
|
||||
|
||||
private readonly ISet _messageDigestOids = new HashSet();
|
||||
|
||||
private readonly IDictionary _messageDigests = Platform.CreateHashtable();
|
||||
|
||||
private readonly IDictionary _messageHashes = Platform.CreateHashtable();
|
||||
|
||||
private bool _messageDigestsLocked;
|
||||
|
||||
private int _bufferSize;
|
||||
|
||||
public CmsSignedDataStreamGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
public CmsSignedDataStreamGenerator(SecureRandom rand)
|
||||
: base(rand)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetBufferSize(int bufferSize)
|
||||
{
|
||||
_bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void AddDigests(params string[] digestOids)
|
||||
{
|
||||
AddDigests((IEnumerable)digestOids);
|
||||
}
|
||||
|
||||
public void AddDigests(IEnumerable digestOids)
|
||||
{
|
||||
foreach (string digestOid in digestOids)
|
||||
{
|
||||
ConfigureDigest(digestOid);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string digestOid)
|
||||
{
|
||||
AddSigner(privateKey, cert, digestOid, new DefaultSignedAttributeTableGenerator(), null);
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string encryptionOid, string digestOid)
|
||||
{
|
||||
AddSigner(privateKey, cert, encryptionOid, digestOid, new DefaultSignedAttributeTableGenerator(), null);
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string digestOid, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr)
|
||||
{
|
||||
AddSigner(privateKey, cert, digestOid, new DefaultSignedAttributeTableGenerator(signedAttr), new SimpleAttributeTableGenerator(unsignedAttr));
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string encryptionOid, string digestOid, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr)
|
||||
{
|
||||
AddSigner(privateKey, cert, encryptionOid, digestOid, new DefaultSignedAttributeTableGenerator(signedAttr), new SimpleAttributeTableGenerator(unsignedAttr));
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
|
||||
{
|
||||
AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOid), digestOid, signedAttrGenerator, unsignedAttrGenerator);
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
|
||||
{
|
||||
DoAddSigner(privateKey, CmsSignedGenerator.GetSignerIdentifier(cert), encryptionOid, digestOid, signedAttrGenerator, unsignedAttrGenerator);
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string digestOid)
|
||||
{
|
||||
AddSigner(privateKey, subjectKeyID, digestOid, new DefaultSignedAttributeTableGenerator(), null);
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string encryptionOid, string digestOid)
|
||||
{
|
||||
AddSigner(privateKey, subjectKeyID, encryptionOid, digestOid, new DefaultSignedAttributeTableGenerator(), null);
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string digestOid, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr)
|
||||
{
|
||||
AddSigner(privateKey, subjectKeyID, digestOid, new DefaultSignedAttributeTableGenerator(signedAttr), new SimpleAttributeTableGenerator(unsignedAttr));
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
|
||||
{
|
||||
AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOid), digestOid, signedAttrGenerator, unsignedAttrGenerator);
|
||||
}
|
||||
|
||||
public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
|
||||
{
|
||||
DoAddSigner(privateKey, CmsSignedGenerator.GetSignerIdentifier(subjectKeyID), encryptionOid, digestOid, signedAttrGenerator, unsignedAttrGenerator);
|
||||
}
|
||||
|
||||
private void DoAddSigner(AsymmetricKeyParameter privateKey, SignerIdentifier signerIdentifier, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
|
||||
{
|
||||
ConfigureDigest(digestOid);
|
||||
SignerInfoGeneratorImpl signerInf = new SignerInfoGeneratorImpl(this, privateKey, signerIdentifier, digestOid, encryptionOid, signedAttrGenerator, unsignedAttrGenerator);
|
||||
_signerInfs.Add(new DigestAndSignerInfoGeneratorHolder(signerInf, digestOid));
|
||||
}
|
||||
|
||||
internal override void AddSignerCallback(SignerInformation si)
|
||||
{
|
||||
RegisterDigestOid(si.DigestAlgorithmID.Algorithm.Id);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStream)
|
||||
{
|
||||
return Open(outStream, encapsulate: false);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStream, bool encapsulate)
|
||||
{
|
||||
return Open(outStream, CmsSignedGenerator.Data, encapsulate);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStream, bool encapsulate, Stream dataOutputStream)
|
||||
{
|
||||
return Open(outStream, CmsSignedGenerator.Data, encapsulate, dataOutputStream);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStream, string signedContentType, bool encapsulate)
|
||||
{
|
||||
return Open(outStream, signedContentType, encapsulate, null);
|
||||
}
|
||||
|
||||
public Stream Open(Stream outStream, string signedContentType, bool encapsulate, Stream dataOutputStream)
|
||||
{
|
||||
if (outStream == null)
|
||||
{
|
||||
throw new ArgumentNullException("outStream");
|
||||
}
|
||||
if (!outStream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("Expected writeable stream", "outStream");
|
||||
}
|
||||
if (dataOutputStream != null && !dataOutputStream.CanWrite)
|
||||
{
|
||||
throw new ArgumentException("Expected writeable stream", "dataOutputStream");
|
||||
}
|
||||
_messageDigestsLocked = true;
|
||||
BerSequenceGenerator berSequenceGenerator = new BerSequenceGenerator(outStream);
|
||||
berSequenceGenerator.AddObject(CmsObjectIdentifiers.SignedData);
|
||||
BerSequenceGenerator berSequenceGenerator2 = new BerSequenceGenerator(berSequenceGenerator.GetRawOutputStream(), 0, isExplicit: true);
|
||||
DerObjectIdentifier derObjectIdentifier = ((signedContentType == null) ? null : new DerObjectIdentifier(signedContentType));
|
||||
berSequenceGenerator2.AddObject(CalculateVersion(derObjectIdentifier));
|
||||
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector();
|
||||
foreach (string messageDigestOid in _messageDigestOids)
|
||||
{
|
||||
asn1EncodableVector.Add(new AlgorithmIdentifier(new DerObjectIdentifier(messageDigestOid), DerNull.Instance));
|
||||
}
|
||||
byte[] encoded = new DerSet(asn1EncodableVector).GetEncoded();
|
||||
berSequenceGenerator2.GetRawOutputStream().Write(encoded, 0, encoded.Length);
|
||||
BerSequenceGenerator berSequenceGenerator3 = new BerSequenceGenerator(berSequenceGenerator2.GetRawOutputStream());
|
||||
berSequenceGenerator3.AddObject(derObjectIdentifier);
|
||||
Stream s = (encapsulate ? CmsUtilities.CreateBerOctetOutputStream(berSequenceGenerator3.GetRawOutputStream(), 0, isExplicit: true, _bufferSize) : null);
|
||||
Stream safeTeeOutputStream = GetSafeTeeOutputStream(dataOutputStream, s);
|
||||
Stream outStream2 = AttachDigestsToOutputStream(_messageDigests.Values, safeTeeOutputStream);
|
||||
return new CmsSignedDataOutputStream(this, outStream2, signedContentType, berSequenceGenerator, berSequenceGenerator2, berSequenceGenerator3);
|
||||
}
|
||||
|
||||
private void RegisterDigestOid(string digestOid)
|
||||
{
|
||||
if (_messageDigestsLocked)
|
||||
{
|
||||
if (!_messageDigestOids.Contains(digestOid))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot register new digest OIDs after the data stream is opened");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_messageDigestOids.Add(digestOid);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureDigest(string digestOid)
|
||||
{
|
||||
RegisterDigestOid(digestOid);
|
||||
string digestAlgName = Helper.GetDigestAlgName(digestOid);
|
||||
IDigest digest = (IDigest)_messageDigests[digestAlgName];
|
||||
if (digest == null)
|
||||
{
|
||||
if (_messageDigestsLocked)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot configure new digests after the data stream is opened");
|
||||
}
|
||||
digest = Helper.GetDigestInstance(digestAlgName);
|
||||
_messageDigests[digestAlgName] = digest;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Generate(Stream outStream, string eContentType, bool encapsulate, Stream dataOutputStream, CmsProcessable content)
|
||||
{
|
||||
Stream stream = Open(outStream, eContentType, encapsulate, dataOutputStream);
|
||||
content?.Write(stream);
|
||||
Platform.Dispose(stream);
|
||||
}
|
||||
|
||||
private DerInteger CalculateVersion(DerObjectIdentifier contentOid)
|
||||
{
|
||||
bool flag = false;
|
||||
bool flag2 = false;
|
||||
bool flag3 = false;
|
||||
bool flag4 = false;
|
||||
if (_certs != null)
|
||||
{
|
||||
foreach (object cert in _certs)
|
||||
{
|
||||
if (cert is Asn1TaggedObject)
|
||||
{
|
||||
Asn1TaggedObject asn1TaggedObject = (Asn1TaggedObject)cert;
|
||||
if (asn1TaggedObject.TagNo == 1)
|
||||
{
|
||||
flag3 = true;
|
||||
}
|
||||
else if (asn1TaggedObject.TagNo == 2)
|
||||
{
|
||||
flag4 = true;
|
||||
}
|
||||
else if (asn1TaggedObject.TagNo == 3)
|
||||
{
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
return new DerInteger(5);
|
||||
}
|
||||
if (_crls != null)
|
||||
{
|
||||
foreach (object crl in _crls)
|
||||
{
|
||||
if (crl is Asn1TaggedObject)
|
||||
{
|
||||
flag2 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag2)
|
||||
{
|
||||
return new DerInteger(5);
|
||||
}
|
||||
if (flag4)
|
||||
{
|
||||
return new DerInteger(4);
|
||||
}
|
||||
if (flag3 || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(_signers))
|
||||
{
|
||||
return new DerInteger(3);
|
||||
}
|
||||
return new DerInteger(1);
|
||||
}
|
||||
|
||||
private bool CheckForVersion3(IList signerInfos)
|
||||
{
|
||||
foreach (SignerInformation signerInfo in signerInfos)
|
||||
{
|
||||
SignerInfo instance = SignerInfo.GetInstance(signerInfo.ToSignerInfo());
|
||||
if (instance.Version.Value.IntValue == 3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Stream AttachDigestsToOutputStream(ICollection digests, Stream s)
|
||||
{
|
||||
Stream stream = s;
|
||||
foreach (IDigest digest in digests)
|
||||
{
|
||||
stream = GetSafeTeeOutputStream(stream, new DigestSink(digest));
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
private static Stream GetSafeOutputStream(Stream s)
|
||||
{
|
||||
if (s == null)
|
||||
{
|
||||
return new NullOutputStream();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private static Stream GetSafeTeeOutputStream(Stream s1, Stream s2)
|
||||
{
|
||||
if (s1 == null)
|
||||
{
|
||||
return GetSafeOutputStream(s2);
|
||||
}
|
||||
if (s2 == null)
|
||||
{
|
||||
return GetSafeOutputStream(s1);
|
||||
}
|
||||
return new TeeOutputStream(s1, s2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user