Click here to Skip to main content
15,894,546 members
Articles / Programming Languages / VC++

PNG Image Steganography with libpng

Rate me:
Please Sign up or sign in to vote.
4.96/5 (16 votes)
22 Apr 2013GPL317 min read 62K   4.8K   33  
Performing steganography on PNG images
//
// � Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0. 
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

using System;
using System.Runtime.InteropServices;

namespace DotZLib
{
	/// <summary>
	/// Implements the common functionality needed for all <see cref="Codec"/>s
	/// </summary>
	public abstract class CodecBase : Codec, IDisposable
	{

        #region Data members

        /// <summary>
        /// Instance of the internal zlib buffer structure that is 
        /// passed to all functions in the zlib dll
        /// </summary>
        internal ZStream _ztream = new ZStream();

        /// <summary>
        /// True if the object instance has been disposed, false otherwise
        /// </summary>
        protected bool _isDisposed = false;

        /// <summary>
        /// The size of the internal buffers
        /// </summary>
        protected const int kBufferSize = 16384;

        private byte[] _outBuffer = new byte[kBufferSize];
        private byte[] _inBuffer = new byte[kBufferSize];

        private GCHandle _hInput;
        private GCHandle _hOutput;

        private uint _checksum = 0;

        #endregion

        /// <summary>
        /// Initializes a new instance of the <c>CodeBase</c> class. 
        /// </summary>
		public CodecBase()
		{
            try
            {
                _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned);
                _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned);
            }
            catch (Exception)
            {
                CleanUp(false);
                throw;
            }
        }


        #region Codec Members

        /// <summary>
        /// Occurs when more processed data are available.
        /// </summary>
        public event DataAvailableHandler DataAvailable;

        /// <summary>
        /// Fires the <see cref="DataAvailable"/> event
        /// </summary>
        protected void OnDataAvailable()
        {
            if (_ztream.total_out > 0)
            {
                if (DataAvailable != null)
                    DataAvailable( _outBuffer, 0, (int)_ztream.total_out); 
                resetOutput();
            }
        }

        /// <summary>
        /// Adds more data to the codec to be processed.
        /// </summary>
        /// <param name="data">Byte array containing the data to be added to the codec</param>
        /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
        public void Add(byte[] data)
        {
            Add(data,0,data.Length);
        }

        /// <summary>
        /// Adds more data to the codec to be processed.
        /// </summary>
        /// <param name="data">Byte array containing the data to be added to the codec</param>
        /// <param name="offset">The index of the first byte to add from <c>data</c></param>
        /// <param name="count">The number of bytes to add</param>
        /// <remarks>Adding data may, or may not, raise the <c>DataAvailable</c> event</remarks>
        /// <remarks>This must be implemented by a derived class</remarks>
        public abstract void Add(byte[] data, int offset, int count);

        /// <summary>
        /// Finishes up any pending data that needs to be processed and handled.
        /// </summary>
        /// <remarks>This must be implemented by a derived class</remarks>
        public abstract void Finish();

        /// <summary>
        /// Gets the checksum of the data that has been added so far
        /// </summary>
        public uint Checksum { get { return _checksum; } }

        #endregion

        #region Destructor & IDisposable stuff

        /// <summary>
        /// Destroys this instance
        /// </summary>
        ~CodecBase()
        {
            CleanUp(false);
        }

        /// <summary>
        /// Releases any unmanaged resources and calls the <see cref="CleanUp()"/> method of the derived class
        /// </summary>
        public void Dispose()
        {
            CleanUp(true);
        }

        /// <summary>
        /// Performs any codec specific cleanup
        /// </summary>
        /// <remarks>This must be implemented by a derived class</remarks>
        protected abstract void CleanUp();

        // performs the release of the handles and calls the dereived CleanUp()
        private void CleanUp(bool isDisposing)
        {
            if (!_isDisposed)
            {
                CleanUp();
                if (_hInput.IsAllocated)
                    _hInput.Free();
                if (_hOutput.IsAllocated)
                    _hOutput.Free();

                _isDisposed = true;
            }
        }


        #endregion

        #region Helper methods

        /// <summary>
        /// Copies a number of bytes to the internal codec buffer - ready for proccesing
        /// </summary>
        /// <param name="data">The byte array that contains the data to copy</param>
        /// <param name="startIndex">The index of the first byte to copy</param>
        /// <param name="count">The number of bytes to copy from <c>data</c></param>
        protected void copyInput(byte[] data, int startIndex, int count)
        {
            Array.Copy(data, startIndex, _inBuffer,0, count);
            _ztream.next_in = _hInput.AddrOfPinnedObject();
            _ztream.total_in = 0;
            _ztream.avail_in = (uint)count;

        }

        /// <summary>
        /// Resets the internal output buffers to a known state - ready for processing
        /// </summary>
        protected void resetOutput()
        {
            _ztream.total_out = 0;
            _ztream.avail_out = kBufferSize;
            _ztream.next_out = _hOutput.AddrOfPinnedObject();
        }

        /// <summary>
        /// Updates the running checksum property
        /// </summary>
        /// <param name="newSum">The new checksum value</param>
        protected void setChecksum(uint newSum)
        {
            _checksum = newSum;
        }
        #endregion

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
United States United States
Grant is a specialist in computer security and networking. He holds a bachelors degree in Computer Science and Engineering from the Ohio State University. Certs: CCNA, CCNP, CCDA, CCDP, Sec+, and GCIH.

Comments and Discussions