// ------------------------------------------------------------------------------------------- /// <summary> /// Gives, in a target byte array, another one readed from a stream, until consume a number of bytes or before some marks. /// Return the index of the found mark or -1 if the consumable bytes limit was reached. /// For efficiency, this capture is divided in two types... /// One simple, applicable to any underlying Stream, for when the marks only have one byte of lenght, /// and other complex for when the marks are of greater lenght (in that case the Stream must support Seek). /// </summary> public static int CaptureStreamReaderSegment(ref byte[] TargetSegment, BinaryReader TorrentReader, int BytesNumberLimit, params byte[][] LimitMarks) { if (BytesNumberLimit < 1 || LimitMarks.GetLength(0) < 1) { throw new UsageAnomaly("Limits for stream reading are not well established.", new DataWagon("BytesNumberLimit", BytesNumberLimit) .Add("LimitMarks", LimitMarks)); } // Note: It could be validated that each LimitMarks item is a byte array and not a null reference, // but that is omitted to avoid performance impact. int MarksCount = LimitMarks.GetLength(0); int Ind = 0; int MarksMaxLength = 0; // Next, the lenght of the marks are determined bool MarksAreShort = true; for (Ind = 0; Ind < MarksCount; Ind++) { if (LimitMarks[Ind].Length > 1) { MarksAreShort = false; if (LimitMarks[Ind].Length > MarksMaxLength) { MarksMaxLength = LimitMarks[Ind].Length; } } } if (MarksMaxLength > LimitMarkMaxLength) { throw new UsageAnomaly("Segment limit marks exceeds the limit established at " + LimitMarkMaxLength.ToString() + ".", MarksMaxLength); } if (MarksAreShort) // Simple implementation, applicable to any stream { return(CaptureSegmentWithSimpleStreamReader(ref TargetSegment, TorrentReader, BytesNumberLimit, LimitMarks)); } // Complex implementetion, only applicable for seek-capable streams. if (!TorrentReader.BaseStream.CanSeek) { throw new UsageAnomaly("A seek capable Stream is required when exists limit marks with more than one byte.", TorrentReader.BaseStream); } return(CaptureSegmentWithComplexStreamReader(ref TargetSegment, TorrentReader, BytesNumberLimit, MarksMaxLength, LimitMarks)); }
// ------------------------------------------------------------------------------------------- /// <summary> /// Gives, in a target byte array, another one readed from a stream, until consume a number of bytes or before some marks conformed by more than one byte. /// Return the index of the found mark or -1 if the consumable bytes limit was reached. /// </summary> private static int CaptureSegmentWithComplexStreamReader(ref byte[] TargetSegment, BinaryReader TorrentReader, int BytesNumberLimit, int MarksMaxLength, params byte[][] LimitMarks) { int CaptureEndingCause = -1; int MarksCount = LimitMarks.GetLength(0); SimpleList <byte[]> Parts = new SimpleList <byte[]>(); byte[] Part = new byte[0]; int ConsumedBytesCount = 0; int ConsumedBytesTotal = 0; int FoundedPosition = 0; int Pos = 0; while ((ConsumedBytesCount = (Part = TorrentReader.ReadBytes(BLOCK_SIZE_TINY)).Length) > 0) { ConsumedBytesTotal += ConsumedBytesCount; Pos = -1; foreach (byte[] Mark in LimitMarks) { Pos++; if ((FoundedPosition = Search(Part, Mark)) >= 0) { CaptureEndingCause = Pos; TorrentReader.BaseStream.Seek((Part.Length - (FoundedPosition + Mark.Length)) * -1, SeekOrigin.Current); Part = ExtractSegment(Part, 0, FoundedPosition); break; } } if (FoundedPosition >= 0) { Parts.Add(Part); break; } if (ConsumedBytesTotal >= BytesNumberLimit) { throw new UsageAnomaly("Stream has been readed/consumed until reach the " + BytesNumberLimit.ToString() + " bytes limit.", new DataWagon("ConsumedBytesCount", ConsumedBytesCount)); } if (ConsumedBytesCount == BLOCK_SIZE_TINY) { Part = ExtractSegment(Part, 0, Part.Length - MarksMaxLength); } Parts.Add(Part); // If less than the expected bytes were read, then means the stream's end was reached. if (ConsumedBytesCount < BLOCK_SIZE_TINY) { break; } TorrentReader.BaseStream.Seek(MarksMaxLength * -1, SeekOrigin.Current); } TargetSegment = new byte[((BLOCK_SIZE_TINY - MarksMaxLength) * (Parts.Count - 1)) + Part.Length]; Pos = 0; foreach (byte[] Fragment in Parts) { CopyByteArray(TargetSegment, Fragment, Pos, (byte)0, false); Pos += Fragment.Length; } return(CaptureEndingCause); }
// ------------------------------------------------------------------------------------------- /// <summary> /// Gives, in a target byte array, another one readed from a stream, until consume a number of bytes or before some marks conformed by only one byte. /// Return the index of the found mark or -1 if the consumable bytes limit was reached. /// </summary> private static int CaptureSegmentWithSimpleStreamReader(ref byte[] TargetSegment, BinaryReader TorrentReader, int BytesNumberLimit, params byte[][] LimitMarks) { int CaptureEndingCause = -1; int MarksCount = LimitMarks.GetLength(0); int Ind = 0; int Pos = 0; int ConsumedBytesCount = 0; bool FoundedMark = false; byte Atom = 0; SimpleList <byte[]> Parts = new SimpleList <byte[]>(); byte[] Part = new byte[0]; int PartBytesCount = 0; Parts.Add(Part); try { while (ConsumedBytesCount < BytesNumberLimit) { Atom = TorrentReader.ReadByte(); ConsumedBytesCount++; FoundedMark = false; for (Ind = 0; Ind < MarksCount; Ind++) { if (Atom == LimitMarks[Ind][0]) { FoundedMark = true; CaptureEndingCause = Ind; break; } } if (FoundedMark) { break; } if (PartBytesCount == BLOCK_SIZE_TINY) { Part = new byte[BLOCK_SIZE_TINY]; PartBytesCount = 0; Parts.Add(Part); } Part[PartBytesCount] = Atom; PartBytesCount++; } throw new UsageAnomaly("Stream has been readed/consumed until reach the " + BytesNumberLimit.ToString() + " bytes limit.", new DataWagon("ConsumedBytesCount", ConsumedBytesCount)); } #pragma warning disable 168 catch (EndOfStreamException Anomaly) { // The possible end of the stream is expected. }; #pragma warning restore 168 TargetSegment = new byte[(BLOCK_SIZE_TINY * (Parts.Count - 1)) + PartBytesCount]; Ind = 0; Pos = 0; foreach (byte[] Fragment in Parts) { Ind++; CopyByteArray(TargetSegment, (Ind < Parts.Count ? Fragment : BytesHandling.ExtractSegment(Fragment, 0, PartBytesCount)), Pos, (byte)0, false); Pos += BLOCK_SIZE_TINY; } return(CaptureEndingCause); }