private void SaveData(DataBlock identificationBlock, Collection <DataBlock> applicationData) { _identificationBlock = identificationBlock; StringBuilder sb; if (_identificationBlock.Data.Length < 11) { string message = "The identification block should be 11 bytes long but " + "is only " + _identificationBlock.Data.Length + " bytes."; throw new ArgumentException(message, "identificationBlock"); } if (_identificationBlock.Data.Length > 11) { string message = "The identification block should be 11 bytes long but " + "is " + _identificationBlock.Data.Length + " bytes long. " + "Additional bytes are ignored."; SetStatus(ErrorState.IdentificationBlockTooLong, message); } // Read application identifer sb = new StringBuilder(); for (int i = 0; i < 8; i++) { sb.Append((char)_identificationBlock[i]); } _applicationIdentifier = sb.ToString(); // Read application authentication code sb = new StringBuilder(); for (int i = 8; i < 11; i++) { sb.Append((char)_identificationBlock[i]); } _applicationAuthenticationCode = sb.ToString(); _applicationData = applicationData; if (XmlDebugging) { WriteDebugXmlStartElement("IdentificationData"); WriteDebugXmlNode(identificationBlock.DebugXmlReader); WriteDebugXmlElement("ApplicationIdentifier", _applicationIdentifier); WriteDebugXmlElement("ApplicationAuthenticationCode", _applicationAuthenticationCode); WriteDebugXmlEndElement(); WriteDebugXmlStartElement("ApplicationData"); foreach (DataBlock db in applicationData) { WriteDebugXmlNode(db.DebugXmlReader); } WriteDebugXmlEndElement(); WriteDebugXmlFinish(); } }
/// <summary> /// Constructor. /// </summary> /// <param name="identificationBlock"> /// Sets the <see cref="IdentificationBlock"/> /// </param> /// <param name="applicationData"> /// Sets the <see cref="ApplicationData"/> /// </param> public ApplicationExtension(DataBlock identificationBlock, Collection <DataBlock> applicationData) { SaveData(identificationBlock, applicationData); }
/// <summary> /// Constructor. /// </summary> /// <param name="identificationBlock"> /// Sets the <see cref="IdentificationBlock"/> /// </param> /// <param name="applicationData"> /// Sets the <see cref="ApplicationData"/> /// </param> public ApplicationExtension( DataBlock identificationBlock, Collection<DataBlock> applicationData ) { SaveData( identificationBlock, applicationData ); }
/// <summary> /// Skips variable length blocks up to and including next zero length /// block (block terminator). /// </summary> /// <param name="inputStream"> /// The input stream to read. /// </param> protected void SkipBlocks( Stream inputStream ) { DataBlock block; do { block = new DataBlock( inputStream, _xmlDebugging ); } while( block.DeclaredBlockSize > 0 && block.ErrorState == ErrorState.Ok ); }
public void WriteToStreamTest() { ReportStart(); MemoryStream s = new MemoryStream(); _block.WriteToStream( s ); s.Seek( 0, SeekOrigin.Begin ); DataBlock d = new DataBlock( s ); Assert.AreEqual( ErrorState.Ok, d.ConsolidatedState ); Assert.AreEqual( _block.DeclaredBlockSize, d.DeclaredBlockSize ); Assert.AreEqual( _block.ActualBlockSize, d.ActualBlockSize ); for( int i = 0; i < _block.ActualBlockSize; i++ ) { Assert.AreEqual( _block.Data[i], d.Data[i], "byte " + i ); } ReportEnd(); }
private void ConstructorStreamTestEmptyBlock( bool xmlDebugging ) { Stream s = new MemoryStream(); s.WriteByte( 0 ); // write length (0 bytes) s.Seek( 0, SeekOrigin.Begin ); // go to start of stream _block = new DataBlock( s, xmlDebugging ); Assert.AreEqual( 0, _block.DeclaredBlockSize ); Assert.AreEqual( 0, _block.ActualBlockSize ); Assert.AreEqual( 0, _block.Data.Length ); Assert.AreEqual( ErrorState.Ok, _block.ConsolidatedState ); if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _block.DebugXml ); } }
public void SkipBlocksTest() { ReportStart(); byte[] data1 = new byte[] { 24, 38, 53 }; byte[] data2 = new byte[] { 66, 23, 58, 56, 23 }; byte[] data3 = new byte[] { }; // block terminator byte[] data4 = new byte[] { 43 }; byte[] data5 = new byte[] { }; // block terminator MemoryStream s = new MemoryStream(); s.WriteByte( (byte) data1.Length ); s.Write( data1, 0, data1.Length ); s.WriteByte( (byte) data2.Length ); s.Write( data2, 0, data2.Length ); s.WriteByte( (byte) data3.Length ); s.Write( data3, 0, data3.Length ); s.WriteByte( (byte) data4.Length ); s.Write( data4, 0, data4.Length ); s.WriteByte( (byte) data5.Length ); s.Write( data5, 0, data5.Length ); s.Seek( 0, SeekOrigin.Begin ); _component.CallSkipBlocks( s ); DataBlock db; db = new DataBlock( s ); Assert.AreEqual( data4.Length, db.DeclaredBlockSize ); Assert.AreEqual( data4.Length, db.ActualBlockSize ); Assert.AreEqual( data4, db.Data ); db = new DataBlock( s ); Assert.AreEqual( data5.Length, db.DeclaredBlockSize ); Assert.AreEqual( data5.Length, db.ActualBlockSize ); Assert.AreEqual( data5, db.Data ); ReportEnd(); }
public void ConstructorTestNullArgument() { ReportStart(); try { _block = new DataBlock( 1, null ); } catch( ArgumentNullException ex ) { Assert.AreEqual( "data", ex.ParamName ); ReportEnd(); throw; } }
/// <summary> /// Constructor. /// </summary> /// <param name="inputStream"> /// The stream from which the image data is to be read, starting with /// the LZW minimum code size, and ending with a block terminator. /// </param> /// <param name="pixelCount"> /// Number of pixels in the image. /// </param> /// <param name="xmlDebugging">Whether or not to create debug XML</param> /// <remarks> /// The input stream is read, first into the LZW minimum code size, then /// into data blocks. Bytes are extracted from the data blocks into a /// datum until the datum contains enough bits to form a code; this code /// is then extracted from the datum and decoded into a pixel index. /// Once all data has been read, or a block terminator, /// end-of-information code or error condition is encountered, any /// remaining pixel indices not already populated default to zero. /// </remarks> public TableBasedImageData( Stream inputStream, int pixelCount, bool xmlDebugging ) : base( xmlDebugging ) { #region guard against silly image sizes if( pixelCount < 1 ) { string message = "The pixel count must be greater than zero. " + "Supplied value was " + pixelCount; throw new ArgumentOutOfRangeException( "pixelCount", message ); } #endregion #region declare / initialise local variables _pixels = new IndexedPixels( pixelCount ); _dataBlocks = new Collection<DataBlock>(); int nextAvailableCode; // the next code to be added to the dictionary int currentCodeSize; int in_code; int previousCode; int code; int datum = 0; // temporary storage for codes read from the input stream int meaningfulBitsInDatum = 0; // number of bits of useful information held in the datum variable int firstCode = 0; // first code read from the stream since last clear code int indexInDataBlock = 0; int pixelIndex = 0; // number of bytes still to be extracted from the current data block int bytesToExtract = 0; short[] prefix = new short[_maxStackSize]; byte[] suffix = new byte[_maxStackSize]; Stack<byte> pixelStack = new Stack<byte>(); #endregion // Initialize GIF data stream decoder. _lzwMinimumCodeSize = Read( inputStream ); // number of bits initially used for LZW codes in image data WriteDebugXmlElement( "LzwMinimumCodeSize", _lzwMinimumCodeSize ); nextAvailableCode = ClearCode + 2; previousCode = _nullCode; currentCodeSize = InitialCodeSize; #region guard against LZW code size being too large if( ClearCode >= _maxStackSize ) { string message = "LZW minimum code size: " + _lzwMinimumCodeSize + ". Clear code: " + ClearCode + ". Max stack size: " + _maxStackSize; SetStatus( ErrorState.LzwMinimumCodeSizeTooLarge, message ); WriteDebugXmlFinish(); return; } #endregion // TODO: what are prefix and suffix and why are we initialising them like this? for( code = 0; code < ClearCode; code++ ) { prefix[code] = 0; suffix[code] = (byte) code; } WriteDebugXmlStartElement( "DataBlocks" ); #region decode LZW image data // Initialise block to an empty data block. This will be overwritten // first time through the loop with a data block read from the input // stream. DataBlock block = new DataBlock( 0, new byte[0] ); for( pixelIndex = 0; pixelIndex < pixelCount; ) { if( pixelStack.Count == 0 ) { // There are no pixels in the stack at the moment, so... #region get some pixels and put them on the stack if( meaningfulBitsInDatum < currentCodeSize ) { // Then we don't have enough bits in the datum to make // a code; we need to get some more from the current // data block, or we may need to read another data // block from the input stream #region get another byte from the current data block if( bytesToExtract == 0 ) { // Then we've extracted all the bytes from the // current data block, so... #region read the next data block from the stream block = ReadDataBlock( inputStream ); bytesToExtract = block.ActualBlockSize; // Point to the first byte in the new data block indexInDataBlock = 0; if( block.TestState( ErrorState.DataBlockTooShort ) ) { // then we've reached the end of the stream // prematurely break; } if( bytesToExtract == 0 ) { // then it's a block terminator, end of the // image data (this is a data block other than // the first one) break; } #endregion } // Append the contents of the current byte in the data // block to the beginning of the datum int newDatum = block[indexInDataBlock] << meaningfulBitsInDatum; datum += newDatum; // so we've now got 8 more bits of information in the // datum. meaningfulBitsInDatum += 8; // Point to the next byte in the data block indexInDataBlock++; // We've one less byte still to read from the data block // now. bytesToExtract--; // and carry on reading through the data block continue; #endregion } #region get the next code from the datum // Get the least significant bits from the read datum, up // to the maximum allowed by the current code size. code = datum & GetMaximumPossibleCode( currentCodeSize ); // Drop the bits we've just extracted from the datum. datum >>= currentCodeSize; // Reduce the count of meaningful bits held in the datum meaningfulBitsInDatum -= currentCodeSize; #endregion #region interpret the code #region end of information? if( code == EndOfInformation ) { // We've reached an explicit marker for the end of the // image data. break; } #endregion #region code not in dictionary? if( code > nextAvailableCode ) { // We expect the code to be either one which is already // in the dictionary, or the next available one to be // added. If it's neither of these then abandon // processing of the image data. string message = "Next available code: " + nextAvailableCode + ". Last code read from input stream: " + code; SetStatus( ErrorState.CodeNotInDictionary, message ); break; } #endregion #region clear code? if( code == ClearCode ) { // We can get a clear code at any point in the image // data, this is an instruction to reset the decoder // and empty the dictionary of codes. currentCodeSize = InitialCodeSize; nextAvailableCode = ClearCode + 2; previousCode = _nullCode; // Carry on reading from the input stream. continue; } #endregion #region first code since last clear code? if( previousCode == _nullCode ) { // This is the first code read since the start of the // image data or the most recent clear code. // There's no previously read code in memory yet, so // get the pixel index for the current code and add it // to the stack. pixelStack.Push( suffix[code] ); previousCode = code; firstCode = code; // and carry on to the next pixel continue; } #endregion in_code = code; if( code == nextAvailableCode ) { pixelStack.Push( (byte) firstCode ); code = previousCode; } while( code > ClearCode ) { pixelStack.Push( suffix[code] ); code = prefix[code]; } #endregion firstCode = ((int) suffix[code]) & 0xff; #region add a new string to the string table if( nextAvailableCode >= _maxStackSize ) { // TESTME: constructor - next available code >- _maxStackSize break; } pixelStack.Push( (byte) firstCode ); prefix[nextAvailableCode] = (short) previousCode; suffix[nextAvailableCode] = (byte) firstCode; nextAvailableCode++; #endregion #region do we need to increase the code size? if( ( nextAvailableCode & GetMaximumPossibleCode( currentCodeSize ) ) == 0 ) { // We've reached the largest code possible for this size if( nextAvailableCode < _maxStackSize ) { // so increase the code size by 1 currentCodeSize++; } } #endregion previousCode = in_code; #endregion } // Pop all the pixels currently on the stack off, and add them // to the return value. _pixels[pixelIndex] = pixelStack.Pop(); pixelIndex++; } #endregion #region check input stream contains enough data to fill the image if( pixelIndex < pixelCount ) { string message = "Expected pixel count: " + pixelCount + ". Actual pixel count: " + pixelIndex; SetStatus( ErrorState.TooFewPixelsInImageData, message ); } #endregion if( XmlDebugging ) { WriteDebugXmlEndElement(); byte[] bytes = new byte[_pixels.Count]; _pixels.CopyTo( bytes, 0 ); WriteDebugXmlByteValues( "IndexedPixels", bytes ); WriteDebugXmlFinish(); } }
private DataBlock ReadDataBlock( Stream inputStream ) { DataBlock block = new DataBlock( inputStream, XmlDebugging ); _dataBlocks.Add( block ); WriteDebugXmlNode( block.DebugXmlReader ); return block; }
private static Collection<DataBlock> GetApplicationData( int repeatCount ) { MemoryStream s = new MemoryStream(); WriteByte( 1, s ); WriteShort( repeatCount, s ); s.Seek( 0, SeekOrigin.Begin ); byte[] repeatData = new byte[3]; s.Read( repeatData, 0, 3 ); DataBlock repeatBlock = new DataBlock( 3, repeatData ); byte[] terminatorData = new byte[0]; DataBlock terminatorBlock = new DataBlock( 0, terminatorData ); Collection<DataBlock> appData = new Collection<DataBlock>(); appData.Add( repeatBlock ); appData.Add( terminatorBlock ); return appData; }
private static DataBlock GetIdentificationBlock() { MemoryStream s = new MemoryStream(); WriteString( "NETSCAPE2.0", s ); s.Seek( 0, SeekOrigin.Begin ); byte[] identificationData = new byte[11]; s.Read( identificationData, 0, 11 ); DataBlock identificationBlock = new DataBlock( 11, identificationData ); return identificationBlock; }
/// <summary> /// Reads and returns an application extension from the supplied input /// stream. /// </summary> /// <param name="inputStream"> /// The input stream to read. /// </param> /// <param name="xmlDebugging">Whether or not to create debug XML</param> public ApplicationExtension( Stream inputStream, bool xmlDebugging ) : base( xmlDebugging ) { DataBlock identificationBlock = new DataBlock( inputStream, XmlDebugging ); Collection<DataBlock> applicationData = new Collection<DataBlock>(); if( !identificationBlock.TestState( ErrorState.EndOfInputStream ) ) { // Read application specific data DataBlock thisBlock; do { thisBlock = new DataBlock( inputStream, XmlDebugging ); applicationData.Add( thisBlock ); } // A zero-length block indicates the end of the data blocks while( thisBlock.DeclaredBlockSize != 0 && !thisBlock.TestState( ErrorState.EndOfInputStream ) ); } SaveData( identificationBlock, applicationData ); }
public void ConstructorTest() { ReportStart(); _block = new DataBlock( 4, _data ); Assert.AreEqual( 4, _block.ActualBlockSize ); Assert.AreEqual( 4, _block.DeclaredBlockSize ); Assert.AreEqual( ErrorState.Ok, _block.ConsolidatedState ); Assert.AreEqual( _data.Length, _block.Data.Length ); for( int i = 0; i < _data.Length; i++ ) { Assert.AreEqual( _data[i], _block.Data[i], i ); Assert.AreEqual( _data[i], _block[i], i ); } ReportEnd(); }
public void ConstructorTestNot2Point0() { byte[] idData = new byte[] { (byte) 'N', (byte) 'E', (byte) 'T', (byte) 'S', (byte) 'C', (byte) 'A', (byte) 'P', (byte) 'E', (byte) '3', (byte) '.', (byte) '0', }; DataBlock idBlock = new DataBlock( 11, idData ); ApplicationExtension appExt = new ApplicationExtension( idBlock, new Collection<DataBlock>() ); try { _ne = new NetscapeExtension( appExt ); } catch( ArgumentException ex ) { string message = "The application authentication code is not '2.0' " + "therefore this application extension is not a " + "Netscape extension. Application authentication code: 3.0"; StringAssert.Contains( message, ex.Message ); Assert.AreEqual( "applicationExtension", ex.ParamName ); throw; } }
public void ConstructorTestBlockSizeTooSmall() { ReportStart(); _block = new DataBlock( 5, _data ); Assert.AreEqual( 4, _block.ActualBlockSize ); Assert.AreEqual( 5, _block.DeclaredBlockSize ); Assert.AreEqual( ErrorState.DataBlockTooShort, _block.ErrorState ); Assert.AreEqual( _data.Length, _block.Data.Length ); for( int i = 0; i < _data.Length; i++ ) { Assert.AreEqual( _data[i], _block.Data[i], i ); } ReportEnd(); }
public void ConstructorTestNotNetscape() { byte[] idData = new byte[] { (byte) 'B', (byte) 'I', (byte) 'G', (byte) 'P', (byte) 'A', (byte) 'N', (byte) 'T', (byte) 'S', (byte) '2', (byte) '.', (byte) '0', }; DataBlock idBlock = new DataBlock( 11, idData ); ApplicationExtension appExt = new ApplicationExtension( idBlock, new Collection<DataBlock>() ); try { _ne = new NetscapeExtension( appExt ); } catch( ArgumentException ex ) { string message = "The application identifier is not 'NETSCAPE' " + "therefore this application extension is not a " + "Netscape extension. Application identifier: BIGPANTS"; StringAssert.Contains( message, ex.Message ); Assert.AreEqual( "applicationExtension", ex.ParamName ); throw; } }
public void IndexerTestArgumentOutOfRange() { ReportStart(); _block = new DataBlock( 4, _data ); try { byte b = _block[4]; } catch( ArgumentOutOfRangeException ex ) { string message = "Supplied index: 4. Array length: 4"; StringAssert.Contains( message, ex.Message ); Assert.AreEqual( "index", ex.ParamName ); ReportEnd(); throw; } }
public void ConstructorTest() { byte[] idData = new byte[] { (byte) 'N', (byte) 'E', (byte) 'T', (byte) 'S', (byte) 'C', (byte) 'A', (byte) 'P', (byte) 'E', (byte) '2', (byte) '.', (byte) '0', }; DataBlock idBlock = new DataBlock( 11, idData ); Collection<DataBlock> appData = new Collection<DataBlock>(); // First byte in the data block is always 1 for a netscape extension // Second and third bytes are the loop count, lsb first byte[] loopCount = new byte[] { 1, 4, 0 }; appData.Add( new DataBlock( 3, loopCount ) ); // Add the block terminator appData.Add( new DataBlock( 0, new byte[0] ) ); ApplicationExtension appExt = new ApplicationExtension( idBlock, appData ); _ne = new NetscapeExtension( appExt ); Assert.AreEqual( 4, _ne.LoopCount ); Assert.AreEqual( "NETSCAPE", _ne.ApplicationIdentifier ); Assert.AreEqual( "2.0", _ne.ApplicationAuthenticationCode ); Assert.AreEqual( ErrorState.Ok, _ne.ConsolidatedState ); }
private void ConstructorStreamTestBlockSizeTooLarge( bool xmlDebugging ) { Stream s = new MemoryStream(); s.WriteByte( 5 ); // write block size s.Write( _data, 0, _data.Length ); // write data block s.Seek( 0, SeekOrigin.Begin ); // go to start of stream _block = new DataBlock( s, xmlDebugging ); Assert.AreEqual( 5, _block.ActualBlockSize ); Assert.AreEqual( 5, _block.DeclaredBlockSize ); Assert.AreEqual( ErrorState.DataBlockTooShort, _block.ErrorState ); Assert.AreEqual( 5, _block.Data.Length ); for( int i = 0; i < _data.Length; i++ ) { Assert.AreEqual( _data[i], _block.Data[i], i ); } if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _block.DebugXml ); } }
/// <summary> /// Constructor. /// </summary> /// <param name="inputStream"> /// The stream from which the image data is to be read, starting with /// the LZW minimum code size, and ending with a block terminator. /// </param> /// <param name="pixelCount"> /// Number of pixels in the image. /// </param> /// <param name="xmlDebugging">Whether or not to create debug XML</param> /// <remarks> /// The input stream is read, first into the LZW minimum code size, then /// into data blocks. Bytes are extracted from the data blocks into a /// datum until the datum contains enough bits to form a code; this code /// is then extracted from the datum and decoded into a pixel index. /// Once all data has been read, or a block terminator, /// end-of-information code or error condition is encountered, any /// remaining pixel indices not already populated default to zero. /// </remarks> public TableBasedImageData(Stream inputStream, int pixelCount, bool xmlDebugging) : base(xmlDebugging) { #region guard against silly image sizes if (pixelCount < 1) { string message = "The pixel count must be greater than zero. " + "Supplied value was " + pixelCount; throw new ArgumentOutOfRangeException("pixelCount", message); } #endregion #region declare / initialise local variables _pixels = new IndexedPixels(pixelCount); _dataBlocks = new Collection <DataBlock>(); int nextAvailableCode; // the next code to be added to the dictionary int currentCodeSize; int in_code; int previousCode; int code; int datum = 0; // temporary storage for codes read from the input stream int meaningfulBitsInDatum = 0; // number of bits of useful information held in the datum variable int firstCode = 0; // first code read from the stream since last clear code int indexInDataBlock = 0; int pixelIndex = 0; // number of bytes still to be extracted from the current data block int bytesToExtract = 0; short[] prefix = new short[_maxStackSize]; byte[] suffix = new byte[_maxStackSize]; Stack <byte> pixelStack = new Stack <byte>(); #endregion // Initialize GIF data stream decoder. _lzwMinimumCodeSize = Read(inputStream); // number of bits initially used for LZW codes in image data WriteDebugXmlElement("LzwMinimumCodeSize", _lzwMinimumCodeSize); nextAvailableCode = ClearCode + 2; previousCode = _nullCode; currentCodeSize = InitialCodeSize; #region guard against LZW code size being too large if (ClearCode >= _maxStackSize) { string message = "LZW minimum code size: " + _lzwMinimumCodeSize + ". Clear code: " + ClearCode + ". Max stack size: " + _maxStackSize; SetStatus(ErrorState.LzwMinimumCodeSizeTooLarge, message); WriteDebugXmlFinish(); return; } #endregion // TODO: what are prefix and suffix and why are we initialising them like this? for (code = 0; code < ClearCode; code++) { prefix[code] = 0; suffix[code] = (byte)code; } WriteDebugXmlStartElement("DataBlocks"); #region decode LZW image data // Initialise block to an empty data block. This will be overwritten // first time through the loop with a data block read from the input // stream. DataBlock block = new DataBlock(0, new byte[0]); for (pixelIndex = 0; pixelIndex < pixelCount;) { if (pixelStack.Count == 0) { // There are no pixels in the stack at the moment, so... #region get some pixels and put them on the stack if (meaningfulBitsInDatum < currentCodeSize) { // Then we don't have enough bits in the datum to make // a code; we need to get some more from the current // data block, or we may need to read another data // block from the input stream #region get another byte from the current data block if (bytesToExtract == 0) { // Then we've extracted all the bytes from the // current data block, so... #region read the next data block from the stream block = ReadDataBlock(inputStream); bytesToExtract = block.ActualBlockSize; // Point to the first byte in the new data block indexInDataBlock = 0; if (block.TestState(ErrorState.DataBlockTooShort)) { // then we've reached the end of the stream // prematurely break; } if (bytesToExtract == 0) { // then it's a block terminator, end of the // image data (this is a data block other than // the first one) break; } #endregion } // Append the contents of the current byte in the data // block to the beginning of the datum int newDatum = block[indexInDataBlock] << meaningfulBitsInDatum; datum += newDatum; // so we've now got 8 more bits of information in the // datum. meaningfulBitsInDatum += 8; // Point to the next byte in the data block indexInDataBlock++; // We've one less byte still to read from the data block // now. bytesToExtract--; // and carry on reading through the data block continue; #endregion } #region get the next code from the datum // Get the least significant bits from the read datum, up // to the maximum allowed by the current code size. code = datum & GetMaximumPossibleCode(currentCodeSize); // Drop the bits we've just extracted from the datum. datum >>= currentCodeSize; // Reduce the count of meaningful bits held in the datum meaningfulBitsInDatum -= currentCodeSize; #endregion #region interpret the code #region end of information? if (code == EndOfInformation) { // We've reached an explicit marker for the end of the // image data. break; } #endregion #region code not in dictionary? if (code > nextAvailableCode) { // We expect the code to be either one which is already // in the dictionary, or the next available one to be // added. If it's neither of these then abandon // processing of the image data. string message = "Next available code: " + nextAvailableCode + ". Last code read from input stream: " + code; SetStatus(ErrorState.CodeNotInDictionary, message); break; } #endregion #region clear code? if (code == ClearCode) { // We can get a clear code at any point in the image // data, this is an instruction to reset the decoder // and empty the dictionary of codes. currentCodeSize = InitialCodeSize; nextAvailableCode = ClearCode + 2; previousCode = _nullCode; // Carry on reading from the input stream. continue; } #endregion #region first code since last clear code? if (previousCode == _nullCode) { // This is the first code read since the start of the // image data or the most recent clear code. // There's no previously read code in memory yet, so // get the pixel index for the current code and add it // to the stack. pixelStack.Push(suffix[code]); previousCode = code; firstCode = code; // and carry on to the next pixel continue; } #endregion in_code = code; if (code == nextAvailableCode) { pixelStack.Push((byte)firstCode); code = previousCode; } while (code > ClearCode) { pixelStack.Push(suffix[code]); code = prefix[code]; } #endregion firstCode = ((int)suffix[code]) & 0xff; #region add a new string to the string table if (nextAvailableCode >= _maxStackSize) { // TESTME: constructor - next available code >- _maxStackSize break; } pixelStack.Push((byte)firstCode); prefix[nextAvailableCode] = (short)previousCode; suffix[nextAvailableCode] = (byte)firstCode; nextAvailableCode++; #endregion #region do we need to increase the code size? if ((nextAvailableCode & GetMaximumPossibleCode(currentCodeSize)) == 0) { // We've reached the largest code possible for this size if (nextAvailableCode < _maxStackSize) { // so increase the code size by 1 currentCodeSize++; } } #endregion previousCode = in_code; #endregion } // Pop all the pixels currently on the stack off, and add them // to the return value. _pixels[pixelIndex] = pixelStack.Pop(); pixelIndex++; } #endregion #region check input stream contains enough data to fill the image if (pixelIndex < pixelCount) { string message = "Expected pixel count: " + pixelCount + ". Actual pixel count: " + pixelIndex; SetStatus(ErrorState.TooFewPixelsInImageData, message); } #endregion if (XmlDebugging) { WriteDebugXmlEndElement(); byte[] bytes = new byte[_pixels.Count]; _pixels.CopyTo(bytes, 0); WriteDebugXmlByteValues("IndexedPixels", bytes); WriteDebugXmlFinish(); } }
private void ConstructorStreamTestEndOfStream( bool xmlDebugging ) { Stream s = new MemoryStream(); s.Seek( 0, SeekOrigin.Begin ); _block = new DataBlock( s, xmlDebugging ); Assert.AreEqual( ErrorState.EndOfInputStream, _block.ErrorState ); if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _block.DebugXml ); } }
private void SaveData( DataBlock identificationBlock, Collection<DataBlock> applicationData ) { _identificationBlock = identificationBlock; StringBuilder sb; if( _identificationBlock.Data.Length < 11 ) { string message = "The identification block should be 11 bytes long but " + "is only " + _identificationBlock.Data.Length + " bytes."; throw new ArgumentException( message, "identificationBlock" ); } if( _identificationBlock.Data.Length > 11 ) { string message = "The identification block should be 11 bytes long but " + "is " + _identificationBlock.Data.Length + " bytes long. " + "Additional bytes are ignored."; SetStatus( ErrorState.IdentificationBlockTooLong, message ); } // Read application identifer sb = new StringBuilder(); for( int i = 0; i < 8; i++ ) { sb.Append( (char) _identificationBlock[i] ); } _applicationIdentifier = sb.ToString(); // Read application authentication code sb = new StringBuilder(); for( int i = 8; i < 11; i++ ) { sb.Append( (char) _identificationBlock[i] ); } _applicationAuthenticationCode = sb.ToString(); _applicationData = applicationData; if( XmlDebugging ) { WriteDebugXmlStartElement( "IdentificationData" ); WriteDebugXmlNode( identificationBlock.DebugXmlReader ); WriteDebugXmlElement( "ApplicationIdentifier", _applicationIdentifier ); WriteDebugXmlElement( "ApplicationAuthenticationCode", _applicationAuthenticationCode ); WriteDebugXmlEndElement(); WriteDebugXmlStartElement( "ApplicationData" ); foreach( DataBlock db in applicationData ) { WriteDebugXmlNode( db.DebugXmlReader ); } WriteDebugXmlEndElement(); WriteDebugXmlFinish(); } }