1//
2// � Copyright Henrik Ravn 2004
3//
4// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
5// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7
8using System;
9using System.Runtime.InteropServices;
10using System.Text;
11
12
13namespace DotZLib
14{
15    #region ChecksumGeneratorBase
16    /// <summary>
17    /// Implements the common functionality needed for all <see cref="ChecksumGenerator"/>s
18    /// </summary>
19    /// <example></example>
20    public abstract class ChecksumGeneratorBase : ChecksumGenerator
21    {
22        /// <summary>
23        /// The value of the current checksum
24        /// </summary>
25        protected uint _current;
26
27        /// <summary>
28        /// Initializes a new instance of the checksum generator base - the current checksum is
29        /// set to zero
30        /// </summary>
31        public ChecksumGeneratorBase()
32        {
33            _current = 0;
34        }
35
36        /// <summary>
37        /// Initializes a new instance of the checksum generator basewith a specified value
38        /// </summary>
39        /// <param name="initialValue">The value to set the current checksum to</param>
40        public ChecksumGeneratorBase(uint initialValue)
41        {
42            _current = initialValue;
43        }
44
45        /// <summary>
46        /// Resets the current checksum to zero
47        /// </summary>
48        public void Reset() { _current = 0; }
49
50        /// <summary>
51        /// Gets the current checksum value
52        /// </summary>
53        public uint Value { get { return _current; } }
54
55        /// <summary>
56        /// Updates the current checksum with part of an array of bytes
57        /// </summary>
58        /// <param name="data">The data to update the checksum with</param>
59        /// <param name="offset">Where in <c>data</c> to start updating</param>
60        /// <param name="count">The number of bytes from <c>data</c> to use</param>
61        /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
62        /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
63        /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
64        /// <remarks>All the other <c>Update</c> methods are implmeneted in terms of this one.
65        /// This is therefore the only method a derived class has to implement</remarks>
66        public abstract void Update(byte[] data, int offset, int count);
67
68        /// <summary>
69        /// Updates the current checksum with an array of bytes.
70        /// </summary>
71        /// <param name="data">The data to update the checksum with</param>
72        public void Update(byte[] data)
73        {
74            Update(data, 0, data.Length);
75        }
76
77        /// <summary>
78        /// Updates the current checksum with the data from a string
79        /// </summary>
80        /// <param name="data">The string to update the checksum with</param>
81        /// <remarks>The characters in the string are converted by the UTF-8 encoding</remarks>
82        public void Update(string data)
83        {
84			Update(Encoding.UTF8.GetBytes(data));
85        }
86
87        /// <summary>
88        /// Updates the current checksum with the data from a string, using a specific encoding
89        /// </summary>
90        /// <param name="data">The string to update the checksum with</param>
91        /// <param name="encoding">The encoding to use</param>
92        public void Update(string data, Encoding encoding)
93        {
94            Update(encoding.GetBytes(data));
95        }
96
97    }
98    #endregion
99
100    #region CRC32
101    /// <summary>
102    /// Implements a CRC32 checksum generator
103    /// </summary>
104    public sealed class CRC32Checksum : ChecksumGeneratorBase
105    {
106        #region DLL imports
107
108        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
109        private static extern uint crc32(uint crc, int data, uint length);
110
111        #endregion
112
113        /// <summary>
114        /// Initializes a new instance of the CRC32 checksum generator
115        /// </summary>
116        public CRC32Checksum() : base() {}
117
118        /// <summary>
119        /// Initializes a new instance of the CRC32 checksum generator with a specified value
120        /// </summary>
121        /// <param name="initialValue">The value to set the current checksum to</param>
122        public CRC32Checksum(uint initialValue) : base(initialValue) {}
123
124        /// <summary>
125        /// Updates the current checksum with part of an array of bytes
126        /// </summary>
127        /// <param name="data">The data to update the checksum with</param>
128        /// <param name="offset">Where in <c>data</c> to start updating</param>
129        /// <param name="count">The number of bytes from <c>data</c> to use</param>
130        /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
131        /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
132        /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
133        public override void Update(byte[] data, int offset, int count)
134        {
135            if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
136            if ((offset+count) > data.Length) throw new ArgumentException();
137            GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
138            try
139            {
140                _current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
141            }
142            finally
143            {
144                hData.Free();
145            }
146        }
147
148    }
149    #endregion
150
151    #region Adler
152    /// <summary>
153    /// Implements a checksum generator that computes the Adler checksum on data
154    /// </summary>
155    public sealed class AdlerChecksum : ChecksumGeneratorBase
156    {
157        #region DLL imports
158
159        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
160        private static extern uint adler32(uint adler, int data, uint length);
161
162        #endregion
163
164        /// <summary>
165        /// Initializes a new instance of the Adler checksum generator
166        /// </summary>
167        public AdlerChecksum() : base() {}
168
169        /// <summary>
170        /// Initializes a new instance of the Adler checksum generator with a specified value
171        /// </summary>
172        /// <param name="initialValue">The value to set the current checksum to</param>
173        public AdlerChecksum(uint initialValue) : base(initialValue) {}
174
175        /// <summary>
176        /// Updates the current checksum with part of an array of bytes
177        /// </summary>
178        /// <param name="data">The data to update the checksum with</param>
179        /// <param name="offset">Where in <c>data</c> to start updating</param>
180        /// <param name="count">The number of bytes from <c>data</c> to use</param>
181        /// <exception cref="ArgumentException">The sum of offset and count is larger than the length of <c>data</c></exception>
182        /// <exception cref="NullReferenceException"><c>data</c> is a null reference</exception>
183        /// <exception cref="ArgumentOutOfRangeException">Offset or count is negative.</exception>
184        public override void Update(byte[] data, int offset, int count)
185        {
186            if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
187            if ((offset+count) > data.Length) throw new ArgumentException();
188            GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
189            try
190            {
191                _current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
192            }
193            finally
194            {
195                hData.Free();
196            }
197        }
198
199    }
200    #endregion
201
202}