/// <summary> /// Resets the inflater so that a new stream can be decompressed. All /// pending input and output will be discarded. /// </summary> public void Reset() { mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER; totalIn = totalOut = 0; input.Reset(); outputWindow.Reset(); dynHeader = null; litlenTree = null; distTree = null; isLastBlock = false; adler.Reset(); }
/// <summary> /// Resets the inflater so that a new stream can be decompressed. All /// pending input and output will be discarded. /// </summary> public void Reset() { mode = noHeader ? State.Blocks : State.Header; totalIn = 0; TotalOut = 0; input.Reset(); outputWindow.Reset(); dynHeader = null; litlenTree = null; distTree = null; isLastBlock = false; adler.Reset(); }
public void Reset() { mode = (noHeader ? 2 : 0); totalIn = 0L; totalOut = 0L; input.Reset(); outputWindow.Reset(); dynHeader = null; litlenTree = null; distTree = null; isLastBlock = false; adler.Reset(); }
public void TestChecksum() { byte[] arr1 = { 0x2C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0xBD, 0x8C, 0x08, 0x00, 0x19, 0x31, 0x08, 0x00, 0xD1, 0xAF, 0x08, 0x00, 0x69, 0x0F, 0x08, 0x00, 0xF4, 0xAF, 0x08, 0x00, 0x66, 0x94, 0x00, 0x05 }; byte[] arr2 = { 0x1F, 0x0F, 0x08, 0x00, 0xD6, 0xAF, 0x08, 0x00, 0xC0, 0x82, 0x20, 0x00 }; Adler32 adler32 = new Adler32(); adler32.Update(arr1); adler32.Update(arr2); Debug.WriteLine(adler32.Checksum.ToString("X8")); Assert.AreEqual(0xC02709D3, adler32.Checksum); arr1 = new byte[] { 0x2C, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0xBD, 0x8C, 0x08, 0x00, 0x19, 0x31, 0x08, 0x00, 0xD1, 0xAF, 0x08, 0x00, 0x69, 0x0F, 0x08, 0x00, 0xF4, 0xAF, 0x08, 0x00, 0x66, 0x94, 0x00, 0x00 }; arr2 = new byte[] { 0xAB, 0x0F, 0x08, 0x00, 0xD6, 0xAF, 0x08, 0x00, 0xC0, 0x82, 0x20, 0x00 }; adler32.Reset(); adler32.Update(arr1); adler32.Update(arr2); Debug.WriteLine(adler32.Checksum.ToString("X8")); }
public void MixedUpdateTest() { Adler32 checksum = new Adler32(); int i = 0; checksum.Reset(); while (i < LicenseData.Length / 4) { checksum.Update(LicenseData[i++]); } for (int j = 0; j < 2; j++) { checksum.Update(LicenseData, i, LicenseData.Length / 4); i += LicenseData.Length / 4; } while (i < LicenseData.Length) { checksum.Update(LicenseData[i++]); } Assert.AreEqual(LicenseChecksum, checksum.Value); }
/// <summary> /// Reset internal state /// </summary> public void Reset() { huffman.Reset(); adler.Reset(); blockStart = strstart = 1; lookahead = 0; totalIn = 0; prevAvailable = false; matchLen = DeflaterConstants.MIN_MATCH - 1; for (int i = 0; i < DeflaterConstants.HASH_SIZE; i++) { head[i] = 0; } for (int i = 0; i < DeflaterConstants.WSIZE; i++) { prev[i] = 0; } }
public void Reset() { huffman.Reset(); adler.Reset(); blockStart = (strstart = 1); lookahead = 0; totalIn = 0L; prevAvailable = false; matchLen = 2; for (int i = 0; i < 32768; i++) { head[i] = 0; } for (int j = 0; j < 32768; j++) { prev[j] = 0; } }
/// <summary> /// Reset internal state /// </summary> public void Reset() { huffman.Reset(); adler.Reset(); blockStart = strstart = 1; lookahead = 0; totalIn = 0; prevAvailable = false; matchLen = MIN_MATCH - 1; for (var i = 0; i < HASH_SIZE; i++) { head[i] = 0; } for (var i = 0; i < WSIZE; i++) { prev[i] = 0; } }
/// <summary> /// Tests Adler32. /// </summary> public void TestAdler32() { IChecksum check = new Adler32(); check.Update(0); AssertEquals(check.Value, 0x10001); check.Reset(); check.Update(0xFF); AssertEquals(check.Value, 0x1000100); check.Reset(); check.Update(0x64); AssertEquals(check.Value, 0x650065); check.Reset(); byte[] testarray = new byte[256]; for (int i = 0; i < testarray.Length; ++i) { testarray[i] = (byte)i; } check.Update(testarray, 0, testarray.Length); AssertEquals(check.Value, 0xadf67f81); check.Reset(); for (int i = 0; i < testarray.Length; ++i) { testarray[i] = (byte)(i & 0xF); } check.Update(testarray, 0, testarray.Length); AssertEquals(check.Value, 0xafad0781); check.Reset(); for (int i = 0; i < testarray.Length; ++i) { testarray[i] = (byte)((63 * i) % 31); } check.Update(testarray, 0, testarray.Length); AssertEquals(check.Value, 0x39a10ea5); }
public void Adler_32() { var underTestAdler32 = new Adler32(); Assert.AreEqual(0x00000001, underTestAdler32.Value); underTestAdler32.Update(check); Assert.AreEqual(0x091E01DE, underTestAdler32.Value); underTestAdler32.Reset(); Assert.AreEqual(0x00000001, underTestAdler32.Value); exceptionTesting(underTestAdler32); }
/* * val= 393220 * val= 1 * val= 3817105751 t=10982 */ static public void testAdler() { Console.WriteLine("Testing Adler32"); Adler32 crc1 = new Adler32(); crc1.Update(new byte[] { 1, 2 }); Console.WriteLine("val= " + crc1.GetValue()); if (crc1.GetValue() != 393220) { throw new Exception("Bad Adler32!"); } crc1.Reset(); Console.WriteLine("val= " + crc1.GetValue()); if (crc1.GetValue() != 1) { throw new Exception("Bad Adler32!!"); } Random r = new Random(); byte[] all = new byte[2000 * 4]; long t0 = Environment.TickCount; for (int n = 0; n < 2000; n++) { byte[] b = createBytes7(n < 50 ? n : n * n - 7); Adler32 crc = new Adler32(); int offset = 0; while (offset < b.Length) { int len = r.Next(b.Length - offset) + 1; crc.Update(b, offset, len); offset += len; } long x = crc.GetValue(); all[n * 4] = (byte)((x >> 24) & 0xff); all[n * 4 + 1] = (byte)((x >> 16) & 0xff); all[n * 4 + 2] = (byte)((x >> 8) & 0xff); all[n * 4 + 3] = (byte)((x) & 0xff); } long t1 = Environment.TickCount; Adler32 a = new Adler32(); a.Update(all); long v = a.GetValue(); Console.WriteLine("val= " + v + " t=" + (t1 - t0)); if (v != 3817105751) { throw new Exception("Bad Adler32"); // tested with Java CRC32 } }
private void ZlibCompress(MemoryStream dst, MemoryStream src) { dst.Write(_zlibHeader, 0, _zlibHeader.Length); src.TryGetBuffer(out ArraySegment <byte> bufArray); _adler32.CalculateChecksum(bufArray.Array, bufArray.Offset, bufArray.Count); using (var deflateStream = new DeflateStream(dst, CompressionMode.Compress, true)) deflateStream.Write(bufArray.Array, bufArray.Offset, bufArray.Count); var checksum = _adler32.Checksum; _checksumBuf[0] = (byte)(checksum >> 24); _checksumBuf[1] = (byte)(checksum >> 16); _checksumBuf[2] = (byte)(checksum >> 8); _checksumBuf[3] = (byte)(checksum >> 0); dst.Write(_checksumBuf, 0, _checksumBuf.Length); _adler32.Reset(); }
// Begin downloading the file at the specified url, and save it to the given folder. void BeginDownload() { DownloadData data = null; FileStream fs = null; try { //start the stopwatch for speed calc sw.Start(); // get download details waitingForResponse = true; data = DownloadData.Create(url, destFolder); waitingForResponse = false; //reset the adler downloadedAdler32.Reset(); DownloadingTo = data.Filename; if (!File.Exists(DownloadingTo)) { // create the file fs = File.Open(DownloadingTo, FileMode.Create, FileAccess.Write); } else { // read in the existing data to calculate the adler32 if (Adler32 != 0) { GetAdler32(DownloadingTo); } // apend to an existing file (resume) fs = File.Open(DownloadingTo, FileMode.Append, FileAccess.Write); } // create the download buffer byte[] buffer = new byte[BufferSize]; int readCount; // update how many bytes have already been read sentSinceLastCalc = data.StartPoint; //for BPS calculation while ((readCount = data.DownloadStream.Read(buffer, 0, BufferSize)) > 0) { // break on cancel if (bw.CancellationPending) { data.Close(); fs.Close(); break; } // update total bytes read data.StartPoint += readCount; // update the adler32 value if (Adler32 != 0) { downloadedAdler32.Update(buffer, 0, readCount); } // save block to end of file fs.Write(buffer, 0, readCount); //calculate download speed calculateBps(data.StartPoint, data.TotalDownloadSize); // send progress info if (!bw.CancellationPending) { bw.ReportProgress(0, new object[] { //use the realtive progress or the raw progress UseRelativeProgress? InstallUpdate.GetRelativeProgess(0, data.PercentDone) : data.PercentDone, // unweighted percent data.PercentDone, downloadSpeed, ProgressStatus.None, null }); } // break on cancel if (bw.CancellationPending) { data.Close(); fs.Close(); break; } } } catch (UriFormatException e) { throw new Exception(string.Format("Could not parse the URL \"{0}\" - it's either malformed or is an unknown protocol.", url), e); } catch (Exception e) { if (string.IsNullOrEmpty(DownloadingTo)) { throw new Exception(string.Format("Error trying to save file: {0}", e.Message), e); } else { throw new Exception(string.Format("Error trying to save file \"{0}\": {1}", DownloadingTo, e.Message), e); } } finally { if (data != null) { data.Close(); } if (fs != null) { fs.Close(); } } }
private void BeginDownload() { DownloadData downloadData = null; FileStream fileStream = null; try { sw.Start(); waitingForResponse = true; downloadData = DownloadData.Create(url, destFolder); waitingForResponse = false; downloadedAdler32.Reset(); DownloadingTo = downloadData.Filename; if (!File.Exists(DownloadingTo)) { fileStream = File.Open(DownloadingTo, FileMode.Create, FileAccess.Write); } else { if (Adler32 != 0) { GetAdler32(DownloadingTo); } fileStream = File.Open(DownloadingTo, FileMode.Append, FileAccess.Write); } byte[] buffer = new byte[4096]; sentSinceLastCalc = downloadData.StartPoint; do { int num; if ((num = downloadData.DownloadStream.Read(buffer, 0, 4096)) <= 0) { return; } if (bw.CancellationPending) { downloadData.Close(); fileStream.Close(); return; } downloadData.StartPoint += num; if (Adler32 != 0) { downloadedAdler32.Update(buffer, 0, num); } fileStream.Write(buffer, 0, num); calculateBps(downloadData.StartPoint, downloadData.TotalDownloadSize); if (!bw.CancellationPending) { bw.ReportProgress(0, new object[5] { UseRelativeProgress?InstallUpdate.GetRelativeProgess(0, downloadData.PercentDone) : downloadData.PercentDone, downloadData.PercentDone, downloadSpeed, ProgressStatus.None, null }); } }while (!bw.CancellationPending); downloadData.Close(); fileStream.Close(); } catch (UriFormatException innerException) { throw new Exception($"Could not parse the URL \"{url}\" - it's either malformed or is an unknown protocol.", innerException); } catch (Exception ex) { if (string.IsNullOrEmpty(DownloadingTo)) { throw new Exception($"Error trying to save file: {ex.Message}", ex); } throw new Exception($"Error trying to save file \"{DownloadingTo}\": {ex.Message}", ex); } finally { downloadData?.Close(); fileStream?.Close(); } }
/// <summary> /// Begins downloading the files. /// </summary> private void BeginDownload() { DownloadData _downloadData = null; FileStream _fileStream = null; try { FileManager.CreateDirectory(_downloadDirectory); // Start the stop stop watch for speed calculation. _stopWatch.Start(); // Receive download details _waitingForResponse = true; _downloadData = new DownloadData(_currentUrl, _downloadDirectory); _downloadData.Create(); _waitingForResponse = false; // Reset the adler _downloaderAdler32.Reset(); DownloadingTo = _downloadData.OutputFilePath; _downloadedFiles.Add(DownloadingTo); if (!File.Exists(DownloadingTo)) { // Create the file. _fileStream = File.Open(DownloadingTo, FileMode.Create, FileAccess.Write); } else { // Read in the existing data to calculate the Adler32 if (Adler32 != 0) { GetAdler32(DownloadingTo); } // Append to an existing file (resume the download) _fileStream = File.Open(DownloadingTo, FileMode.Append, FileAccess.Write); } var _buffer = new byte[_bufferSize]; int _readCount; // Update how many bytes have already been read. _sentSinceLastCalc = _downloadData.StartPoint; // For BPS (bytes/per second) calculation // Only increment once for each %. var _lastProgress = 0; while ((_readCount = _downloadData.DownloadStream.Read(_buffer, 0, _bufferSize)) > 0) { // Break on cancel if (_backgroundDownloader.CancellationPending) { _downloadData.Close(); _fileStream.Close(); break; } // Update total bytes read _downloadData.StartPoint += _readCount; // Update the Adler32 value if (Adler32 != 0) { _downloaderAdler32.Update(_buffer, 0, _readCount); } // Save block to end of file _fileStream.Write(_buffer, 0, _readCount); CalculateBps(_downloadData.StartPoint, _downloadData.TotalDownloadSize); // Send progress info. if (!_backgroundDownloader.CancellationPending && (_downloadData.PercentDone > _lastProgress)) { _backgroundDownloader.ReportProgress(0, new object[] { // use the relative or the raw progress. UseRelativeProgress?GetRelativeProgress(0, _downloadData.PercentDone) : _downloadData.PercentDone, // unweighted percent _downloadData.PercentDone, _downloadSpeed, ProgressStatus.None, null }); _lastProgress = _downloadData.PercentDone; } // Break on cancel if (_backgroundDownloader.CancellationPending) { _downloadData.Close(); _fileStream.Close(); break; } } } catch (UriFormatException e) { VisualExceptionDialog.Show(new Exception($"Could not parse the URL \"{_currentUrl}\" - it's either malformed or is an unknown protocol.", e)); } catch (Exception e) { if (string.IsNullOrEmpty(DownloadingTo)) { VisualExceptionDialog.Show(new Exception($"Error trying to save file: {e.Message}", e)); } else { VisualExceptionDialog.Show(new Exception($"Error trying to save file \"{DownloadingTo}\": {e.Message}", e)); } } finally { _downloadData?.Close(); _fileStream?.Close(); } }
private void WriteDataChunksUncompressed() { // First setup some variables we're going to use later on so we can calculate how big of byte[] we need // to store the entire PNG file in so we only keep a single copy of the data in memory. // Figure out how much image data we're going to have: // H * W * (number of bytes in an ARGB value) + H to account for the filter byte in PNG files int dataLength = _bitmap.PixelWidth * _bitmap.PixelHeight * 4 + _bitmap.PixelHeight; // Variables for the number of PNG blocks and how big the last block is going to be. int blockCount; int lastBlockSize; // We could have an exactly even count of blocks (ie MaxBlockSize * x), but that seems unlikely. // If we don't, then add one for the remainder of the data and figure out how much data will be // left. if ((dataLength % MaxBlockSize) == 0) { blockCount = dataLength / MaxBlockSize; lastBlockSize = MaxBlockSize; } else { blockCount = (dataLength / MaxBlockSize) + 1; lastBlockSize = dataLength - (MaxBlockSize * (blockCount - 1)); } // The size of the PNG file will be: // 2 header bytes + // ( blockCount - 1 ) * // ( // 1 last block byte + // 2 block size bytes + // 2 block size one's complement bytes + // maxBlockSize ) + // ( // 1 last block byte + // 2 block size bytes + // 2 block size one's complement bytes + // lastBlockSize ) + // 4 Adler32 bytes + // // = 2 + ((blockCount-1)*(5+MaxBlockSize)) + (5+lastBlockSize) + 4 // = 11 + ((blockCount-1)*(5+MaxBlockSize)) + lastBlockSize // int pngLength; pngLength = 11 + ((blockCount - 1) * (5 + MaxBlockSize)) + lastBlockSize; // Make a buffer to store the PNG in. byte[] data = new byte[pngLength]; // Write zlib headers. data[0] = 0x78; data[1] = 0xDA; // zlib compression uses Adler32 CRCs instead of CRC32s, so setup on up to calculate. Adler32 crcCode = new Adler32(); crcCode.Reset(); // Setup some variables to use in the loop. var blockRemainder = 0; // How much of the current block we have left, 0 to start so we write the block header out on the first block. var currentBlock = 0; // The current block we're working on, start with 0 as we increment in the first pass thorugh. var dataPointer = 2; // A pointer to where we are in the data array, start at 2 as we 'wrote' two bytes a few lines ago. var pixelSource = 0; // The current pixel we're working on from the image. byte[] pixel = new byte[4]; // Temporary storage to store the current pixel in as a byte array. // This is the main logic loop, we're going to be doing a lot of work so stick with me... // The loop has three parts to it: // 1. looping through each row (y) // 2. looping through each pixel in the row (x) // 3. looping through each byte of the pixel (z) // Loop thorough each row in the image. for (int y = 0; y < _bitmap.PixelHeight; y++) { // This code appears twice, once here and once in the pixel byte loop (loop 3). // It checks to see if we're at the boundry for the PNG block and if so writes // out a new block header. It get executed on the first time through to setup // the first block but is unlikly to get executed again as it would mean the // block boundry is at a row boundry, which seems unlikly. if (blockRemainder == 0) { // Setup a temporary byte array to store the block size in. byte[] tempBytes = new byte[2]; // Increment the current block count. currentBlock++; // Figure out the current block size and if we're at the last block, write // out and 1 to let the zlib decompressor know. By default, use the MaxBlockSize. int length = MaxBlockSize; if (currentBlock == blockCount) { length = lastBlockSize; data[dataPointer] = 0x01; } else { data[dataPointer] = 0x00; } // Each and every time we write something to the data array, increment the pointer. dataPointer++; // Write the block length out. tempBytes = BitConverter.GetBytes(length); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Write one's compliment of length for error checking. tempBytes = BitConverter.GetBytes((ushort)~length); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Reset the remaining block size to the next block's length. blockRemainder = length; } // Set the filter byte to 0, not really required as C# initalizes the byte array to 0 by default, but here for clarity. data[dataPointer] = 0; // Add the current byte to the running Adler32 value, note we ONLY add the filter byte and the pixel bytes to the // Adler32 CRC, all other header and block header bytes are execluded from the CRC. crcCode.Add(data, 1, (uint)dataPointer); // Increment the data pointer and decrement the remain block value. dataPointer++; blockRemainder--; // Loop thorough each pixel in the row, you have to do this as the source format and destination format may be different. for (int x = 0; x < _bitmap.PixelWidth; x++) { // Data is in RGBA format but source may not be pixel = BitConverter.GetBytes(_bitmap.Pixels[pixelSource]); // Loop through the 4 bytes of the pixel and 'write' them to the data array. for (int z = 0; z < 4; z++) { // This is the second appearance of this code code. // It checks to see if we're at the boundry for the PNG block and if so writes // out a new block header. if (blockRemainder == 0) { // Setup a temporary byte array to store the block size in. byte[] tempBytes = new byte[2]; // Increment the current block count. currentBlock++; // Figure out the current block size and if we're at the last block, write // out and 1 to let the zlib decompressor know. By default, use the MaxBlockSize. int length = MaxBlockSize; if (currentBlock == blockCount) { length = lastBlockSize; data[dataPointer] = 0x01; } else { data[dataPointer] = 0x00; } // Each and every time we write something to the data array, increment the pointer. dataPointer++; // Write the block length out. tempBytes = BitConverter.GetBytes(length); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Write one's compliment of length for error checking. tempBytes = BitConverter.GetBytes((ushort)~length); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Reset the remaining block size to the next block's length. blockRemainder = length; } // Store the pixel's byte in to the data array. We use the WBByteOrder array to ensure // we have the write order of bytes to store in the PNG file. if (z != 3 && pixel[WBByteOrder[3]] != 0 && pixel[WBByteOrder[3]] != 255) { // Calculate unmultiplied pixel value from premultiplied value (Windows Phone always uses premultiplied ARGB32) data[dataPointer] = (byte)((255 * pixel[WBByteOrder[z]]) / pixel[WBByteOrder[3]]); } else { // Alpha channel or no need to unpremultiply data[dataPointer] = pixel[WBByteOrder[z]]; } // Add the current byte to the running Adler32 value, note we ONLY add the filter byte and the pixel bytes to the // Adler32 CRC, all other header and block header bytes are execluded from the CRC. crcCode.Add(data, 1, (uint)dataPointer); // Increment the data pointer and decrement the remain block value. dataPointer++; blockRemainder--; } // Increment where we start writting the next pixel and where we get the next pixel from. pixelSource++; } } // Whew, wipe that brow, we're done all the complex bits now! // Write the Adler32 CRC out, but reverse the order of the bytes to match the zlib spec. pixel = BitConverter.GetBytes(crcCode.CurrentValue); data[dataPointer + 0] = pixel[3]; data[dataPointer + 1] = pixel[2]; data[dataPointer + 2] = pixel[1]; data[dataPointer + 3] = pixel[0]; // Yes, yes, I know I said "Each and every time we write something to the data array, increment the pointer." // but we're done with it now so I'm not going to bother ;) // Write the entire PNG data chunk out to the file stream. WriteChunk(PngChunkTypes.Data, data, 0, pngLength); }
// Begin downloading the file at the specified url, and save it to the given folder. private void BeginDownload() { DownloadData data = null; FileStream fs = null; try { //start the stopwatch for speed calc sw.Start(); if (!Directory.Exists(_tempDirectory)) { Directory.CreateDirectory(_tempDirectory); } data = DownloadData.Create(url_, _tempDirectory, _credentials); //reset the adler downloadedAdler32.Reset(); DownloadingTo = data.Filename; if (!File.Exists(DownloadingTo)) { // create the file fs = File.Open(DownloadingTo, FileMode.Create, FileAccess.Write); } else { // read in the existing data to calculate the adler32 if (Adler32 != 0) { GetAdler32(DownloadingTo); } // apend to an existing file (resume) fs = File.Open(DownloadingTo, FileMode.Append, FileAccess.Write); } // create the download buffer byte[] buffer = new byte[BufferSize]; int readCount; // update how many bytes have already been read sentSinceLastCalc = data.StartPoint; //for BPS calculation // Only increment once for each % int LastProgress = 0; while ((readCount = data.DownloadStream.Read(buffer, 0, BufferSize)) > 0) { // update total bytes read data.StartPoint += readCount; // update the adler32 value if (Adler32 != 0) { downloadedAdler32.Update(buffer, 0, readCount); } // save block to end of file fs.Write(buffer, 0, readCount); //calculate download speed calculateBps(data.StartPoint, data.TotalDownloadSize); // send progress info if (data.PercentDone > LastProgress) { _onProgress?.Invoke(new DownloadProgressInfo { Percentage = data.PercentDone, DownloadedInBytes = data.TotalDownloadSize, }); LastProgress = data.PercentDone; } } } catch (UriFormatException e) { throw new Exception(string.Format("Could not parse the URL \"{0}\" - it's either malformed or is an unknown protocol.", url_), e); } catch (WebException e) { throw e; } catch (Exception e) { if (string.IsNullOrEmpty(DownloadingTo)) { throw new Exception(string.Format("Error trying to save file: {0}", e.Message), e); } else { throw new Exception(string.Format("Error trying to save file \"{0}\": {1}", DownloadingTo, e.Message), e); } } finally { if (data != null) { data.Close(); } if (fs != null) { fs.Close(); } } }
private void WriteDataChunksUncompressed() { // First setup some variables we're going to use later on so we can calculate how big of byte[] we need // to store the entire PNG file in so we only keep a single copy of the data in memory. // Figure out how much image data we're going to have: // H * W * (number of bytes in an ARGB value) + H to account for the filter byte in PNG files int dataLength = _bitmap.PixelWidth * _bitmap.PixelHeight * 4 + _bitmap.PixelHeight; // Variables for the number of PNG blocks and how big the last block is going to be. int blockCount; int lastBlockSize; // We could have an exactly even count of blocks (ie MaxBlockSize * x), but that seems unlikely. // If we don't, then add one for the remainder of the data and figure out how much data will be // left. if ( ( dataLength % MaxBlockSize ) == 0 ) { blockCount = dataLength / MaxBlockSize; lastBlockSize = MaxBlockSize; } else { blockCount = ( dataLength / MaxBlockSize ) + 1; lastBlockSize = dataLength - ( MaxBlockSize * ( blockCount - 1 ) ); } // The size of the PNG file will be: // 2 header bytes + // ( blockCount - 1 ) * // ( // 1 last block byte + // 2 block size bytes + // 2 block size one's complement bytes + // maxBlockSize ) + // ( // 1 last block byte + // 2 block size bytes + // 2 block size one's complement bytes + // lastBlockSize ) + // 4 Adler32 bytes + // // = 2 + ((blockCount-1)*(5+MaxBlockSize)) + (5+lastBlockSize) + 4 // = 11 + ((blockCount-1)*(5+MaxBlockSize)) + lastBlockSize // int pngLength; pngLength = 11 + ( ( blockCount - 1 ) * ( 5 + MaxBlockSize ) ) + lastBlockSize; // Make a buffer to store the PNG in. byte[] data = new byte[pngLength]; // Write zlib headers. data[0] = 0x78; data[1] = 0xDA; // zlib compression uses Adler32 CRCs instead of CRC32s, so setup on up to calculate. Adler32 crcCode = new Adler32(); crcCode.Reset(); // Setup some variables to use in the loop. var blockRemainder = 0; // How much of the current block we have left, 0 to start so we write the block header out on the first block. var currentBlock = 0; // The current block we're working on, start with 0 as we increment in the first pass thorugh. var dataPointer = 2; // A pointer to where we are in the data array, start at 2 as we 'wrote' two bytes a few lines ago. var pixelSource = 0; // The current pixel we're working on from the image. byte[] pixel = new byte[4]; // Temporary storage to store the current pixel in as a byte array. // This is the main logic loop, we're going to be doing a lot of work so stick with me... // The loop has three parts to it: // 1. looping through each row (y) // 2. looping through each pixel in the row (x) // 3. looping through each byte of the pixel (z) // Loop thorough each row in the image. for ( int y = 0; y < _bitmap.PixelHeight; y++ ) { // This code appears twice, once here and once in the pixel byte loop (loop 3). // It checks to see if we're at the boundry for the PNG block and if so writes // out a new block header. It get executed on the first time through to setup // the first block but is unlikly to get executed again as it would mean the // block boundry is at a row boundry, which seems unlikly. if ( blockRemainder == 0 ) { // Setup a temporary byte array to store the block size in. byte[] tempBytes = new byte[2]; // Increment the current block count. currentBlock++; // Figure out the current block size and if we're at the last block, write // out and 1 to let the zlib decompressor know. By default, use the MaxBlockSize. int length = MaxBlockSize; if ( currentBlock == blockCount ) { length = lastBlockSize; data[dataPointer] = 0x01; } else { data[dataPointer] = 0x00; } // Each and every time we write something to the data array, increment the pointer. dataPointer++; // Write the block length out. tempBytes = BitConverter.GetBytes( length ); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Write one's compliment of length for error checking. tempBytes = BitConverter.GetBytes( (ushort) ~length ); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Reset the remaining block size to the next block's length. blockRemainder = length; } // Set the filter byte to 0, not really required as C# initalizes the byte array to 0 by default, but here for clarity. data[dataPointer] = 0; // Add the current byte to the running Adler32 value, note we ONLY add the filter byte and the pixel bytes to the // Adler32 CRC, all other header and block header bytes are execluded from the CRC. crcCode.Add( data, 1, (uint) dataPointer ); // Increment the data pointer and decrement the remain block value. dataPointer++; blockRemainder--; // Loop thorough each pixel in the row, you have to do this as the source format and destination format may be different. for ( int x = 0; x < _bitmap.PixelWidth; x++ ) { // Data is in RGBA format but source may not be pixel = BitConverter.GetBytes( _bitmap.Pixels[pixelSource] ); // Loop through the 4 bytes of the pixel and 'write' them to the data array. for ( int z = 0; z < 4; z++ ) { // This is the second appearance of this code code. // It checks to see if we're at the boundry for the PNG block and if so writes // out a new block header. if ( blockRemainder == 0 ) { // Setup a temporary byte array to store the block size in. byte[] tempBytes = new byte[2]; // Increment the current block count. currentBlock++; // Figure out the current block size and if we're at the last block, write // out and 1 to let the zlib decompressor know. By default, use the MaxBlockSize. int length = MaxBlockSize; if ( currentBlock == blockCount ) { length = lastBlockSize; data[dataPointer] = 0x01; } else { data[dataPointer] = 0x00; } // Each and every time we write something to the data array, increment the pointer. dataPointer++; // Write the block length out. tempBytes = BitConverter.GetBytes( length ); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Write one's compliment of length for error checking. tempBytes = BitConverter.GetBytes( (ushort) ~length ); data[dataPointer + 0] = tempBytes[0]; data[dataPointer + 1] = tempBytes[1]; dataPointer += 2; // Reset the remaining block size to the next block's length. blockRemainder = length; } // Store the pixel's byte in to the data array. We use the WBByteOrder array to ensure // we have the write order of bytes to store in the PNG file. if ( z != 3 && pixel[WBByteOrder[3]] != 0 && pixel[WBByteOrder[3]] != 255 ) { // Calculate unmultiplied pixel value from premultiplied value (Windows Phone always uses premultiplied ARGB32) data[dataPointer] = (byte) ( ( 255 * pixel[WBByteOrder[z]] ) / pixel[WBByteOrder[3]] ); } else { // Alpha channel or no need to unpremultiply data[dataPointer] = pixel[WBByteOrder[z]]; } // Add the current byte to the running Adler32 value, note we ONLY add the filter byte and the pixel bytes to the // Adler32 CRC, all other header and block header bytes are execluded from the CRC. crcCode.Add( data, 1, (uint) dataPointer ); // Increment the data pointer and decrement the remain block value. dataPointer++; blockRemainder--; } // Increment where we start writting the next pixel and where we get the next pixel from. pixelSource++; } } // Whew, wipe that brow, we're done all the complex bits now! // Write the Adler32 CRC out, but reverse the order of the bytes to match the zlib spec. pixel = BitConverter.GetBytes( crcCode.CurrentValue ); data[dataPointer + 0] = pixel[3]; data[dataPointer + 1] = pixel[2]; data[dataPointer + 2] = pixel[1]; data[dataPointer + 3] = pixel[0]; // Yes, yes, I know I said "Each and every time we write something to the data array, increment the pointer." // but we're done with it now so I'm not going to bother ;) // Write the entire PNG data chunk out to the file stream. WriteChunk( PngChunkTypes.Data, data, 0, pngLength ); }
public void MixedUpdateTest() { Adler32 checksum = new Adler32(); int i = 0; checksum.Reset(); while (i < LicenseData.Length / 4) checksum.Update(LicenseData[i++]); for (int j = 0; j < 2; j++) { checksum.Update(LicenseData, i, LicenseData.Length / 4); i += LicenseData.Length / 4; } while (i < LicenseData.Length) checksum.Update(LicenseData[i++]); Assert.AreEqual(LicenseChecksum, checksum.Value); }