private static void ValidatePart(YencArticle article, ICollection <ValidationFailure> failures) { YencHeader header = article.Header; YencFooter footer = article.Footer; if (header.PartNumber != footer.PartNumber) { failures.Add(new ValidationFailure( YencValidationErrorCodes.PartMismatch, Resources.Yenc.PartMismatch, new { HeaderPart = header.PartNumber, FooterPart = footer.PartNumber })); } if (!(footer.PartSize == article.Data.Length && footer.PartSize == header.PartSize)) { failures.Add(new ValidationFailure( YencValidationErrorCodes.SizeMismatch, Resources.Yenc.PartSizeMismatch, new { DataSize = article.Data.Length, HeaderSize = header.PartSize, FooterSize = footer.PartSize })); } if (!footer.PartCrc32.HasValue) { failures.Add(new ValidationFailure( YencValidationErrorCodes.MissingChecksum, Resources.Yenc.MissingPartChecksum)); return; } uint calculatedCrc32 = Crc32.CalculateChecksum(article.Data); if (calculatedCrc32 != footer.PartCrc32.Value) { failures.Add(new ValidationFailure( YencValidationErrorCodes.ChecksumMismatch, Resources.Yenc.PartChecksumMismatch, new { CalculatedChecksum = calculatedCrc32, FooterChecksum = footer.PartCrc32 })); } }
/// <summary> /// Decodes yEnc-encoded text into a <see cref="YencArticle"/> /// using the specified charcter encoding. /// </summary> /// <param name="encodedLines">The yEnc-encoded lines to decode.</param> /// <param name="encoding">The charcter encoding to use.</param> /// <returns>A <see cref="YencArticle"/> containing the decoded binary data and meta-data.</returns> public static YencArticle Decode(IEnumerable <string> encodedLines, Encoding encoding) { Guard.ThrowIfNull(encodedLines, nameof(encodedLines)); Guard.ThrowIfNull(encoding, nameof(encoding)); using (IEnumerator <string> enumerator = encodedLines.GetEnumerator()) { IDictionary <string, string> headers = YencMeta.GetHeaders(enumerator); int part = headers.GetAndConvert(YencKeywords.Part, int.Parse); if (part > 0) { headers.Merge(YencMeta.GetPartHeaders(enumerator), false); } YencHeader header = YencMeta.ParseHeader(headers); YencFooter footer = null; // create buffer for part or entire file if single part var decodedBytes = new byte[header.PartSize]; var decodedBytesIndex = 0; while (enumerator.MoveNext()) { if (enumerator.Current == null) { continue; } if (enumerator.Current.StartsWith(yEnd)) { footer = YencMeta.ParseFooter(YencMeta.ParseLine(enumerator.Current)); // skip remainder if there is some while (enumerator.MoveNext()) { } break; } byte[] encodedBytes = encoding.GetBytes(enumerator.Current); decodedBytesIndex += YencLineDecoder.Decode(encodedBytes, decodedBytes, decodedBytesIndex); } return(new YencArticle(header, footer, decodedBytes)); } }
/// <summary> /// Validates the specified <see cref="YencArticle"/>. /// </summary> /// <param name="article">The yEnc-encoded article to validate.</param> /// <returns>A <see cref="ValidationResult"/> containing a list of 0 or more validation failures.</returns> public static ValidationResult Validate(YencArticle article) { var failures = new List <ValidationFailure>(); YencHeader header = article.Header; YencFooter footer = article.Footer; if (footer == null) { // nothing to validate return(new ValidationResult(failures)); } if (header.PartNumber > 0) { ValidatePart(article, failures); return(new ValidationResult(failures)); } if (footer.PartSize != article.Data.Length) { failures.Add(new ValidationFailure( YencValidationErrorCodes.SizeMismatch, Resources.Yenc.SizeMismatch, new { DataSize = article.Data.Length, FooterSize = footer.PartSize })); } if (!footer.Crc32.HasValue) { failures.Add(new ValidationFailure( YencValidationErrorCodes.MissingChecksum, Resources.Yenc.MissingChecksum)); return(new ValidationResult(failures)); } uint calculatedCrc32 = Crc32.CalculateChecksum(article.Data); if (calculatedCrc32 != footer.Crc32.Value) { failures.Add(new ValidationFailure( YencValidationErrorCodes.ChecksumMismatch, Resources.Yenc.ChecksumMismatch, new { CalculatedChecksum = calculatedCrc32, FooterChecksum = footer.Crc32.Value })); } return(new ValidationResult(failures)); }
/// <summary> /// Creates a new instance of the <see cref="YencArticle"/> class. /// </summary> /// <param name="header">The header of the Yenc-encoded article.</param> /// <param name="footer">The optional footer of the Yenc-encoded article.</param> /// <param name="data">The binary data obtained by decoding the Yenc-decoded article.</param> public YencArticle(YencHeader header, YencFooter footer, byte[] data) { Header = header.ThrowIfNull(nameof(header)); Footer = footer; Data = data.ThrowIfNull(nameof(data)); }