Skip to content

Instantly share code, notes, and snippets.

@espresso3389
Created June 1, 2016 20:45
Show Gist options
  • Save espresso3389/a4a7ffcc28cbd15dce61a5f45a94c3bf to your computer and use it in GitHub Desktop.
Save espresso3389/a4a7ffcc28cbd15dce61a5f45a94c3bf to your computer and use it in GitHub Desktop.
JPEG 2000 Parser
//----------------------------------------------------------------------------
// JPEG 2000 Parser
//----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace JPXDump
{
class JPXDump
{
public static void Main(string[] args)
{
for (int i = 0; i < args.Length; i++)
process(args[i]);
}
static void process(string fileName)
{
using (FileStream fs = File.OpenRead(fileName))
{
var jpxd = new JPXDump();
jpxd.process(fs, 0, 0);
}
}
int jpmVerMajor;
int jpmVerMinor;
void process(Stream stream, int level, long baseOffset)
{
for (;;)
{
long pos = stream.Position;
if(pos >= stream.Length)
break;
int hdrSize = 8;
int boxLen = IO.ReadU32(stream, "BOXLEN");
string boxType = IO.ReadString(stream, 4, "BOXTYPE");
if (boxLen == 0)
{
boxLen = hdrSize + (int)(stream.Length - stream.Position);
}
else if (boxLen == 1)
{
IO.SkipBytes(stream, 4);
boxLen = IO.ReadU32(stream, "BOXLEN");
hdrSize = 16;
}
Console.Write("{1:X8} {3:X8} {0}{2} ",
new string(' ', level), baseOffset, boxType, boxLen);
int size = boxLen - hdrSize;
baseOffset += hdrSize;
process(new PartialStream(stream, size), level, boxType, baseOffset);
baseOffset += size;
}
}
void process(Stream stream, int level, string boxType, long baseOffset)
{
string spc = "";
int minlevel = 6;
if (level < minlevel)
{
Console.Write(new String (' ', minlevel - level));
spc = new String(' ', minlevel + 23);
}
else
spc = new String(' ', level + 23);
if (isSuperBox(boxType))
{
Console.WriteLine("");
process(stream, level + 1, baseOffset + stream.Position);
}
else if (boxType == "jP ")
{
Console.WriteLine("");
if(IO.ReadU32(stream, "JP2 sig") != 0x0d0a870a)
throw new Exception("Invalid JP2 signature.");
}
else if (boxType == "ftyp")
{
var brand = IO.ReadString(stream, 4, "ftyp BR");
var minV = IO.ReadU32(stream, "ftyp MinV");
Console.Write("Brand={0} MinV={1} CL", brand, minV);
for (int i = 0; stream.Position < stream.Length; i++)
{
var cl = IO.ReadString(stream, 4, string.Format("ftyp CL{0}", i));
Console.Write("{0}\"{1}\"", i == 0 ? "={" : ",", cl);
}
Console.WriteLine("}");
}
else if (boxType == "ihdr")
{
string[] compStr = {
"Uncompressed", "ModHuff", "ModREAD", "MMREAD",
"JBIG", "JPEG", "JPEG-LS", "JP2K", "JBIG2"};
int h = IO.ReadU32(stream, "ihdr height");
int w = IO.ReadU32(stream, "ihdr width");
int comps = IO.ReadU16(stream, "ihdr comps");
int bpc = IO.ReadU8(stream, "ihdr bpc");
int compression = IO.ReadU8(stream, "ihdr compression");
bool unkC = IO.ReadU8(stream, "ihdr unkC") != 0;
bool ipr = IO.ReadU8(stream, "ihdr ipr") != 0;
Console.WriteLine(
"{0}x{1} N={2} BPC={3} C.={4} UnkC={5} IPR={6}",
w, h, comps, bpc,
compression >= 0 && compression < compStr.Length ? (object)compStr[compression] : (object)compression,
unkC, ipr);
}
else if (boxType == "colr")
{
int meth = IO.ReadU8(stream, "colr meth");
int precedence = IO.ReadU8(stream, "colr precedence");
int approx = IO.ReadU8(stream, "colr approx");
if (meth == 1)
{
int enumCs = IO.ReadU32(stream, "colr enumCs");
string cs;
if (enumCs == 16) cs = "sRGB (IEC 61966-2-1)";
else if (enumCs == 17) cs = "Grayscale";
else cs = string.Format("CS={0}", enumCs);
Console.WriteLine("meth={0} precedence={1} approx={2} {3}", meth, precedence, approx, cs);
}
else if (meth == 2)
{
Console.WriteLine("meth={0} precedence={1} approx={2} ICC profile", meth, precedence, approx);
}
}
else if (boxType == "resd" || boxType == "resc")
{
// resolution in samples/meter
double vn = IO.ReadU16(stream, "resd/resc vn") * 2.54f;
double vd = IO.ReadU16(stream, "resd/resc vd") * 100f;
double hn = IO.ReadU16(stream, "resd/resc hn") * 2.54f;
double hd = IO.ReadU16(stream, "resd/resc hd") * 100f;
double ve = IO.ReadU8(stream, "resd/resc ve");
double he = IO.ReadU8(stream, "resd/resc he");
double vres = vn * Math.Pow(10f, ve) / vd;
double hres = hn * Math.Pow(10f, he) / hd;
Console.WriteLine("Resolution H={0} V={1}", hres, vres);
}
else if (boxType == "jp2c")
{
Console.WriteLine("");
process_jp2c(stream, level);
}
else if (boxType == "mhdr")
{
// Part 6
jpmVerMajor = IO.ReadU8(stream, "mhdr VERS[0]");
jpmVerMinor = IO.ReadU8(stream, "mhdr VERS[1]");
var numberOfPages = IO.ReadU16(stream, "mhdr NP");
var profileID = IO.ReadU8(stream, "mhdr P");
var mc = IO.ReadMSB7ExtendedBytes(stream, "mhdr MC");
var ic = IO.ReadMSB7ExtendedBytes(stream, "mhdr IC");
var ipr = IO.ReadU8(stream, "mhdr IPR");
Console.WriteLine("Version={0:X2}.{1:X2} NumOfPages={2} Profile={3} IPR={4}",
jpmVerMajor, jpmVerMinor, numberOfPages, getPart6ProfileName(profileID), ipr);
showPart6MaskCoders(mc, spc);
showPart6ImageCoders(ic, spc);
}
else if (boxType == "lbl ")
{
// Part 6
var len = (int)(stream.Length - stream.Position);
var bytes = new byte[len];
stream.Read(bytes, 0, len);
Console.WriteLine("Label=\"{0}\"", Encoding.UTF8.GetString(bytes));
}
else if (boxType == "pagt")
{
// Part 6
var npc = IO.ReadU16(stream, "pagt NPC");
var ne = IO.ReadU16(stream, "pagt NE");
Console.WriteLine("NumOfPagesInCollection={0}, NumOfEntries={1}", npc, ne);
for (int i = 0; i < ne; i++)
{
var offset = IO.ReadU64(stream, string.Format("pagt OFF{0}", i));
var length = IO.ReadU32(stream, string.Format("pagt LEN{0}", i));
var dataRef = IO.ReadU16(stream, string.Format("pagt DR{0}", i));
var flags = IO.ReadU8(stream, string.Format("pagt FL{0}", i));
var meaning = "";
if ((flags & 7) == 1)
meaning = "Offset to Page box";
else if ((flags & 7) == 5)
meaning = "Offset to Page box containing thumbnail";
else if ((flags & 7) == 4)
meaning = "Offset to Page Collection box";
else if ((flags & 8) == 8)
meaning = "Offset to Page or Page Collection box containing metadata";
else
meaning = "Reserved for ISO use";
Console.WriteLine(
"{0}{1}: OFF={2:X8}h LEN={3:X8}h, DataRef={4}, Flags={5:X2}h: {6}",
spc, i, offset, length, dataRef, flags, meaning);
}
}
else if (boxType == "phdr")
{
// Part 6
int pageID, nlObj;
if (jpmVerMajor == 0)
{
pageID = IO.ReadU8(stream, "phdr PageID");
nlObj = IO.ReadU8(stream, "phdr NLobj");
}
else
{
pageID = IO.ReadU16(stream, "phdr PageID");
nlObj = IO.ReadU16(stream, "phdr NLobj");
}
var pHeight = IO.ReadU32(stream, "phdr PHeight");
var pWidth = IO.ReadU32(stream, "phdr PWidth");
var or = (Part6OrientationClockWise) IO.ReadU16(stream, "phdr OR");
var pColor = (Part6PageColor) IO.ReadU16(stream, "phdr PColor");
Console.WriteLine(
"PageID={0} NLobj={1} PHeight={2} PWidth={3} OR={4} PColor={5}",
pageID, nlObj, pHeight, pWidth, or, pColor);
for (int i = 0; stream.Position < stream.Length; i++)
{
var offset = IO.ReadU64(stream, string.Format("phdr OFF{0}", i));
var length = IO.ReadU32(stream, string.Format("phdr LEN{0}", i));
var dataRef = IO.ReadU16(stream, string.Format("phdr DR{0}", i));
Console.WriteLine(
"{0}{1}: OFF={2:X8}h LEN={3:X8}h, DataRef={4}",
spc, i, offset, length, dataRef);
}
}
else if (boxType == "ppcl")
{
var ppcOff = IO.ReadU64(stream, "ppcl PPCOff");
var ppcLen = IO.ReadU32(stream, "ppcl PPCLen");
var ppcDataRef = IO.ReadU16(stream, "ppcl PPCDR");
var pIx = IO.ReadU32(stream, "ppcl PIx");
Console.WriteLine("PPCOff={0:X8}h PPCLen={1:X8} PPCDR={2} PIx={3}",
ppcOff, ppcLen, ppcDataRef, pIx);
}
else if (boxType == "lhdr")
{
var lObjID = IO.ReadU16(stream, "lhdr LObjID");
var lHeight = IO.ReadU32(stream, "lhdr LHeight");
var lWidth = IO.ReadU32(stream, "lhdr LWidth");
var lvOffset = IO.ReadU32(stream, "lhdr LVoff");
var lhOffset = IO.ReadU32(stream, "lhdr LHoff");
Console.Write(
"LObjID={0} LHeight={1} LWidth={2} LVoff={3} LHoff={4}",
lObjID, lHeight, lWidth, lvOffset, lhOffset);
if (stream.Position + 2 <= stream.Length)
{
var style = (Part6LayoutObjectStyle) IO.ReadU16(stream, "lhdr Style");
Console.WriteLine(" Style={0}", style);
}
else if (stream.Position + 1 <= stream.Length)
{
// Not compliant to ISO/IEC WD15444-6: 2001 (FCD, 16 November 2001)
// but some jpm have 1-byte Style.
var style = (Part6LayoutObjectStyle) IO.ReadU8(stream, "lhdr Style");
Console.WriteLine(" Style={0}", style);
}
else
{
// Not compliant to ISO/IEC WD15444-6: 2001 (FCD, 16 November 2001)
// but some jpm do not have Style.
Console.WriteLine("");
}
}
else if (boxType == "ohdr")
{
Part6ObjectType objType;
bool noCodestream;
if (jpmVerMajor == 0)
{
objType = (Part6ObjectType) IO.ReadU8(stream, "ohdr ObjType");
noCodestream = IO.ReadU8(stream, "ohdr NoCodestream") != 0 ? true : false;
}
else
{
objType = (Part6ObjectType) IO.ReadU16(stream, "ohdr ObjType");
noCodestream = IO.ReadU16(stream, "ohdr NoCodestream") != 0 ? true : false;
}
var oVoff = IO.ReadU32(stream, "ohdr OVoff");
var oHoff = IO.ReadU32(stream, "ohdr OHoff");
var offset = IO.ReadU64(stream, "ohdr OFF");
var length = IO.ReadU32(stream, "ohdr LEN");
var dataRef = 0;//IO.ReadU16(stream, "ohdr DR");
Console.Write(
"Type={0} NoCodestream={1}", objType, noCodestream);
if (!noCodestream)
{
Console.WriteLine(" OVoff={0} OHoff={1} OFF={2:X8}h LEN={3:X8}h DR={4}",
oVoff, oHoff, offset, length, dataRef);
}
else
{
Console.WriteLine("");
}
}
else if (boxType == "scal")
{
var vrn = IO.ReadU16(stream, "scal VRN");
var vrd = IO.ReadU16(stream, "scal VRD");
var hrn = IO.ReadU16(stream, "scal HRN");
var hrd = IO.ReadU16(stream, "scal HRD");
Console.WriteLine("VScale={0}/{1} HScale={2}/{3}", vrn, vrd, hrn, hrd);
}
else
{
Console.WriteLine("");
}
// skip the trailing bytes
IO.SkipBytes(stream, (int)(stream.Length - stream.Position));
}
enum Part6OrientationClockWise
{
NotSpecified = 0,
Rotate0 = 1,
Rotate90 = 2,
Rotate180 = 3,
Rotate270 = 4
}
enum Part6PageColor
{
Transparent = 0,
White = 1,
Black = 2,
SpecifiedInBaseColourBox = 255
}
enum Part6LayoutObjectStyle
{
SepObjsForImageAndMask = 0,
SingleObjForImageAndMask = 1,
SingleObjForImageOnly = 2,
SingleObjForMaskOnly = 3,
VendorSpecific = 255,
}
enum Part6ObjectType
{
MaskOfLayoutObj = 0,
ImageOfLayoutObj = 1,
ImageAndMaskOfLayoutObj = 2,
}
static bool isSuperBox(string boxType)
{
if (boxType == "jp2h") return true;
else if (boxType == "res ") return true; // resc/resd
else if (boxType == "pcol") return true; // pcol: ISO/IEC WD15444-6: 2001
else if (boxType == "page") return true; // page: ISO/IEC WD15444-6: 2001
else if (boxType == "lobj") return true; // lobj: ISO/IEC WD15444-6: 2001
else if (boxType == "objc") return true; // objc: ISO/IEC WD15444-6: 2001
return false;
}
static void process_jp2c(Stream stream, int level)
{
long basePos = 0;
if(stream is PartialStream)
basePos = ((PartialStream)stream).BasePosition;
for (;;)
{
long pos = basePos + stream.Position;
int marker = IO.ReadU16(stream, "marker");
if ((marker & 0xff00) != 0xff00)
throw new Exception(string.Format("Not a marker: {0:X2}", marker));
marker &= 0xff;
if (marker == 0xd9) // EOC
{
Console.WriteLine("{0:X8} 00000002 EOC(D9)", pos);
break;
}
if (marker == 0x93) // SOD
{
int len = (int)(stream.Length - stream.Position) - 2;
Console.WriteLine("{0:X8} 00000002 SOD(93)", pos);
Console.WriteLine("{0:X8} {1:X8} Coded Data", pos + 2, len);
IO.SkipBytes(stream, len);
continue;
}
int size;
if (marker == 0x4f || (marker >= 0xd0 && marker <= 0xd8))
{
// SOC, SOI, RSTx
size = 0;
}
else
{
size = IO.ReadU16(stream, "size");
size -= 2;
}
string m = markerNames[marker];
if (m == null)
m = string.Format("{0:X2}", marker);
else
m = string.Format("{0}({1:X2})", m, marker);
Console.WriteLine("{0:X8} {1:X8} {2}", pos, size, m);
IO.SkipBytes(stream, size);
}
}
static string getPart6ProfileName(int profileID)
{
switch (profileID)
{
case 0: return "None";
case 1: return "Web";
case 2: return "T.44-compatible";
default: return "Reserved";
}
}
static void showBits(byte[] b, string title, string[] names, string spc)
{
if (b[0] != 0)
Console.WriteLine("{0}{1}: {2:X2}h", spc, title, b[0]);
for (int i = 0; i < 7; i++)
{
if ((b[0] & (1 << i)) != 0)
Console.WriteLine("{0} {1}", spc, names[i]);
}
}
static string[] Part6MaskCoders = {
"One dimensional T.4 (MH) coding",
"Two dimensional T.4 (MR) coding",
"T.6 (MMR) coding",
"T.82 (JBIG) coding applying Recommendation T.85",
"T.88 (JBIG2) coding applying ITU-T Rec, T.89",
"T.800 (JPEG 2000) coding",
"Uncompressed"
};
static void showPart6MaskCoders(byte[] mc, string spc)
{
showBits(mc, "Mask Coders", Part6MaskCoders, spc);
}
static string[] Part6ImageCoders = {
"T.81 (JPEG) coding",
"T.82 (JBIG) coding applying Recommendation T.43",
"T.800 (JPEG 2000) coding",
"T.87 (JPEG-LS) coding",
"T.45 (Run-Length Colour Encoding)",
"Uncompressed",
"Reserved"
};
static void showPart6ImageCoders(byte[] ic, string spc)
{
showBits(ic, "Image Coders", Part6ImageCoders, spc);
}
static string[] markerNames = {
null, "TEM", null, null, null, null, null, null, // 00-
null, null, null, null, null, null, null, null, // 08-
null, null, null, null, null, null, null, null, // 10-
null, null, null, null, null, null, null, null, // 18-
null, null, null, null, null, null, null, null, // 20-
null, null, null, null, null, null, null, null, // 28-
null, null, null, null, null, null, null, null, // 30-
null, null, null, null, null, null, null, null, // 38-
null, null, null, null, null, null, null, null, // 40-
null, null, null, null, null, null, null, "SOC", // 48-
null, "SIZ", "COD", "COC", null, "TLM", null, "PLM", // 50-
"PLT", null, null, null, "QCD", "QCC", "RGN", "POC", // 58-
"PPM", "PPT", null, "CRG", "COM", null, null, null, // 60-
null, null, null, null, null, null, null, null, // 68-
null, null, null, null, null, null, null, null, // 70-
null, null, null, null, null, null, null, null, // 78-
null, null, null, null, null, null, null, null, // 80-
null, null, null, null, null, null, null, null, // 88-
"SOT", "SOP", "EPH", "SOD", null, null, null, null, // 90-
null, null, null, null, null, null, null, null, // 98-
null, null, null, null, null, null, null, null, // A0-
null, null, null, null, null, null, null, null, // A8-
null, null, null, null, null, null, null, null, // B0-
null, null, null, null, null, null, null, null, // B8-
"SOF0", "SOF1", "SOF2", "SOF3", "DHT", "SOF5", "SOF6", "SOF7", // C0-
"JPG", "SOF9", "SOF10", "SOF11", "DAC", "SOF13", "SOF14", "SOF15", // C8-
"RST0", "RST1", "RST2", "RST3", "RST4", "RST5", "RST6", "RST7", // D0-
"SOI", "EOC", "SOS", "DQT", "DNL", "DRI", "DHP", "EXP", // D8-
"APP0", "APP1", "APP2", "APP3", "APP4", "APP5", "APP6", "APP7", // E0-
"APP8", "APP9", "APP10", "APP11", "APP12", "APP13", "APP14", "APP15", // E8-
"JPG0", "JPG1", "JPG2", "JPG3", "JPG4", "JPG5", "JPG6", "JPG7", // F0-
"JPG8", "JPG9", "JPG10", "JPG11", "JPG12", "JPG13", "COM", null // F8-
};
}
//------------------------------------------------------------------------
/// <summary>
/// This class provides easy stream I/O functions.
/// </summary>
public abstract class IO
{
//--------------------------------------------------------------------
/// <summary>
/// Read specified number of bytes from a stream.
/// If stream reachs EOF before reading all of the specified bytes,
/// this function throws an exception.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <param name="n">Number of bytes to read.</param>
/// <returns></returns>
public static byte[] ReadBytes(Stream stream, int n, String tag)
{
var pos = stream.Position;
var buf = new byte[n];
var bytes = stream.Read(buf, 0, n);
if (bytes < n)
throw new Exception(string.Format("EOF during reading {0}: {1} bytes of {2} bytes from {3:X8}", tag, bytes, n, pos));
return buf;
}
//--------------------------------------------------------------------
/// <summary>
/// Read a byte value from a stream.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <returns>The byte read.</returns>
public static int ReadU8(Stream stream, String tag)
{
return (int)ReadBytes(stream, 1, tag)[0];
}
//--------------------------------------------------------------------
/// <summary>
/// Read a byte value from binary data.
/// </summary>
/// <param name="data">Binary data array.</param>
/// <param name="index">Location of the data to read.</param>
/// <returns>The byte read.</returns>
public static int ReadU8(byte[] data, int index)
{
return (int)data[index];
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 16-bit value from a stream.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <returns>The value read.</returns>
public static int ReadU16(Stream stream, String tag)
{
return ReadU16(ReadBytes(stream, 2, tag), 0);
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 16-bit value from binary data.
/// </summary>
/// <param name="data">Binary data array.</param>
/// <param name="index">Location of the data to read.</param>
/// <returns>The value read.</returns>
public static int ReadU16(byte[] buf, int index)
{
unchecked
{
return ((int)buf[index] << 8) | buf[index + 1];
}
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 24-bit value from a stream.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <returns>The value read.</returns>
public static int ReadU24(Stream stream, String tag)
{
return ReadU24(ReadBytes(stream, 3, tag), 0);
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 24-bit value from binary data.
/// </summary>
/// <param name="data">Binary data array.</param>
/// <param name="index">Location of the data to read.</param>
/// <returns>The value read.</returns>
public static int ReadU24(byte[] buf, int index)
{
unchecked
{
return ((int)buf[index] << 16) | (buf[index + 1] << 8) | buf[index + 2];
}
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 32-bit value from a stream.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <returns>The value read.</returns>
public static int ReadU32(Stream stream, String tag)
{
return ReadU32(ReadBytes(stream, 4, tag), 0);
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 32-bit value from binary data.
/// </summary>
/// <param name="data">Binary data array.</param>
/// <param name="index">Location of the data to read.</param>
/// <returns>The value read.</returns>
public static int ReadU32(byte[] buf, int index)
{
unchecked
{
return ((int)buf[index] << 24) |
(buf[index + 1] << 16) |
(buf[index + 2] << 8) |
buf[index + 3];
}
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 64-bit value from a stream.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <returns>The value read.</returns>
public static long ReadU64(Stream stream, String tag)
{
return ReadU64(ReadBytes(stream, 8, tag), 0);
}
//--------------------------------------------------------------------
/// <summary>
/// Read a big-endian 64-bit value from binary data.
/// </summary>
/// <param name="data">Binary data array.</param>
/// <param name="index">Location of the data to read.</param>
/// <returns>The value read.</returns>
public static long ReadU64(byte[] buf, int index)
{
unchecked
{
return
((long)buf[index] << 56) |
((long)buf[index + 1] << 48) |
((long)buf[index + 2] << 40) |
((long)buf[index + 3] << 32) |
((long)buf[index + 4] << 24) |
((long)buf[index + 5] << 16) |
((long)buf[index + 6] << 8) |
(long)buf[index + 7];
}
}
//--------------------------------------------------------------------
public static byte[] ReadMSB7ExtendedBytes(Stream stream, String tag)
{
var bytes = new List<byte>();
for (;;)
{
var b = (byte)ReadU8(stream, tag);
bytes.Add(b);
if ((b & 0x80) == 0)
return bytes.ToArray();
}
}
public delegate int ReadStreamDelegate(Stream stream);
public delegate int ReadMemoryDelegate(byte[] buf, int index);
//--------------------------------------------------------------------
/// <summary>
/// Read a UTF-8 string from a stream.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <param name="sizeInBytes">Number of bytes.</param>
/// <returns></returns>
public static string ReadString(Stream stream, int sizeInBytes, String tag)
{
byte[] bytes = ReadBytes(stream, sizeInBytes, tag);
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
//--------------------------------------------------------------------
/// <summary>
/// Skip (just read) the specified bytes.
/// </summary>
/// <param name="stream">Stream to read.</param>
/// <param name="count">Number of bytes to skip.</param>
public static void SkipBytes(Stream stream, int count)
{
if (count == 0)
return;
if (stream.CanSeek)
{
stream.Seek(count, SeekOrigin.Current);
return;
}
const int BUFSIZE = 1024 * 10;
byte[] tmp = new byte[count < BUFSIZE ? count : BUFSIZE];
for (; ;)
{
int byte2Read = count < BUFSIZE ? count : BUFSIZE;
int bytesRead = stream.Read(tmp, 0, byte2Read);
if(bytesRead == 0)
return;
count -= bytesRead;
if(count == 0)
return;
}
}
}
/// <summary>
/// This class enables create a new short stream on an existing
/// stream.
/// </summary>
public class PartialStream : Stream
{
/// <summary>
/// Initializes a new instance.
/// </summary>
/// <param name="stream">Stream.</param>
/// <param name="length">Length of the new stream.</param>
public PartialStream(Stream stream, int length)
{
m_stream = stream;
m_length = length;
m_firstPos = m_stream.CanSeek ? m_stream.Position : 0L;
m_pos = 0;
}
public long BasePosition { get { return m_firstPos; } }
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return m_stream.CanSeek; } }
public override bool CanWrite { get { return false; } }
public override void Flush() { }
public override long Length { get { return m_length; } }
public override long Position
{
get { return m_pos; }
set { m_pos = m_stream.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
if (m_pos >= m_length)
return 0;
if (m_pos + count > m_length)
count = (int)(m_length - m_pos);
int bytes = m_stream.Read(buffer, offset, count);
m_pos += bytes;
return bytes;
}
public override long Seek(long offset, SeekOrigin origin)
{
if (m_stream.CanSeek)
{
switch (origin)
{
case SeekOrigin.Begin:
offset += m_firstPos;
break;
case SeekOrigin.End:
offset += m_firstPos + m_length;
origin = SeekOrigin.Begin;
break;
}
m_pos = m_stream.Seek(offset, origin) - m_firstPos;
return m_pos;
}
else
{
throw new NotSupportedException();
}
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
Stream m_stream;
long m_length;
long m_firstPos;
long m_pos;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment