/// <summary> /// This loosely parses JPEG data so And returns a <code>Tuple<long, long></code> containing the first And last /// offsets of the JPEG bytes within the file. It does Not parse data within the markers; it simply determines their /// length where possible And skips over them. This means that it Is possible that it may misidentify the bounds of /// faulty JPEGs. /// </summary> /// <param name="startOfJpeg">The offset of the first byte of the JPEG data.</param> /// <param name="offset">Current file offset that will be updated.</param> /// <returns> /// A Tuple<long, long> containing the offsets of the first And last byte of the JPEG, Or null if no complete /// JPEG was found. /// </returns> /// </summary> private Tuple <long, long> WalkJpeg(long startOfJpeg, ref long offset) { var position = startOfJpeg; if (_readable.ReadUInt16(position) != 0xD8FF) { return(null); } // TODO: explain += 2 position += 2; // TODO: again... - 4 while (position < _readable.Capacity - 4) { var marker = FlipUShort(_readable.ReadUInt16(position)); var length = FlipUShort(_readable.ReadUInt16(position + 2)); if (marker == 0xFFFF) { // Skip filler byte position += 1; } else if ((marker & 0xFF) >= 0xD0 && (marker & 0xFF) <= 0xD7) { // RST markers with no params position += 2; } else if (marker == 0xFFDA) { // SOS marker; skip and then continue until EOI position += length + 2; marker = FlipUShort(_readable.ReadUInt16(position)); while (marker != 0xFFD9) { position++; marker = _readable.ReadUInt16(position); } offset = position + 2; return(new Tuple <long, long>(startOfJpeg, position + 1)); } else if ((marker & 0xFF00) == 0xFF00) { // All other markers have lengths or are reserved. Skip over. position += length + 2; } else { // No marker found. Invalid JPEG. offset += 1; break; } } return(null); }