-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* The author would like to thank Hex-Rays SA for helping develop many…
… of these changes and pointing out their importance and use case. * Implement official XZ/CRC-64 and XZ/CRC-32 routines, since different checksum algorithms use different tables/polynominals and mechanisms, and especially in the case of XZ/CRC-64, it is a fairly unique algorithm (*not* ECMA-182). Since the XZ standard places the algorithm and sample code as part of their RFC, we'll call this XzCrc.c. These routines are only compiled in with MINLZ_INTEGRITY_CHECKS. * Introduce a new API -- XzChecksumError -- which returns if the last decoded file encountered CRC errors (always returning false if MINLZ_INTEGRITY_CHECKS isn't used). This is to go alongside new behavior whereas checksum failures will no longer fail the decoding process but instead attempting partial decompression anyway, especially in helpful cases where archive size might be the only thing needed. This allows users to potentially implement their own error recovery mechanism, instead of having the API fail at all times. * Support (by ignoring) checksums other than XZ/CRC-32 and XZ/CRC-64, instead of failing. Correctly handle unrecognized checksum sizes, which are still defined in the standard. * Force MINLZ_META_CHECKS to be defined when MINLZ_INTEGRITY_CHECKS is used, as it is a dependency. * Remove XZ_DECODE_BLOCK_HEADER_RESULT return value and go back to a single true/false. If the file is empty, returning false will skip the call to XzDecodeBlock and set the output size to 0 bytes, and then, if meta-data checks are enabled, scan the index and stream footer -- if the file was truncated, these would fail anyway, but in the case of an empty file, the index and footer will be parsed OK. This has the benefit of correctly zero-initializing the output size if there appears not to be a valid block, as well. * Introduce const-correctness in a number of places. * Some small number of stylistic changes, such as increased constant usage instead of magics. * Guard #pragma warning for _MSC_VER only, for support with other/older compilers. * Bump version to 1.1.5 to recognize these changes.
- Loading branch information
1 parent
e78970e
commit 1f5976d
Showing
11 changed files
with
359 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/*++ | ||
Copyright (c) Alex Ionescu. All rights reserved. | ||
Module Name: | ||
xzcrc.c | ||
Abstract: | ||
This module implements the XZ checksum algorithms for CRC32 and CRC64. The | ||
latter is a specialized implementation (ofter mislabelled "ECMA-182") which | ||
is only available in Go, making it highly unlikely to be found in any other | ||
OS or language runtime. See the XZ Format Specification, Section 6. | ||
Author: | ||
Alex Ionescu (@aionescu) 15-May-2021 - Initial version | ||
Environment: | ||
Windows & Linux, user mode and kernel mode. | ||
--*/ | ||
|
||
#include "minlzlib.h" | ||
|
||
#ifdef MINLZ_INTEGRITY_CHECKS | ||
const uint32_t k_Crc32Polynomial = UINT32_C(0xEDB88320); | ||
const uint64_t k_Crc64Polynomial = UINT64_C(0xC96C5795D7870F42); | ||
|
||
// | ||
// XZ CRC State | ||
// | ||
typedef struct _CHECKSUM_STATE | ||
{ | ||
uint32_t Crc32Table[256]; | ||
uint64_t Crc64Table[256]; | ||
bool Initialized; | ||
} CHECKSUM_STATE, * PCHECKSUM_STATE; | ||
CHECKSUM_STATE Checksum; | ||
|
||
void | ||
XzCrcInitialize ( | ||
void | ||
) | ||
{ | ||
uint32_t i; | ||
uint32_t j; | ||
uint32_t crc32; | ||
uint64_t crc64; | ||
|
||
// | ||
// Don't do anything if the tables are already computed | ||
// | ||
if (!Checksum.Initialized) | ||
{ | ||
// | ||
// Build a table of all possible CRC values for each byte, essentially | ||
// creating the checksums for either 00 00 00 XX in the case of 32-bit | ||
// CRC or for 00 00 00 00 00 00 XX in the base of 64-bit CRC. | ||
// | ||
for (i = 0; i < 256; i++) | ||
{ | ||
crc32 = i; | ||
crc64 = i; | ||
|
||
// | ||
// Divide the input in the 8 coefficients, where the LSB represents | ||
// the coefficient of the highest degree term of the dividend. | ||
// | ||
for (j = 0; j < 8; j++) | ||
{ | ||
// | ||
// Is the current coefficient set? | ||
// | ||
if (crc32 & 1) | ||
{ | ||
// | ||
// Move to next coefficient and add the rest of the divisor | ||
// | ||
crc32 = (crc32 >> 1) ^ k_Crc32Polynomial; | ||
} | ||
else | ||
{ | ||
// | ||
// Skip this and move to the next coefficient | ||
// | ||
crc32 >>= 1; | ||
} | ||
|
||
// | ||
// Compute the 64-bit entry using the same algorithm | ||
// | ||
if (crc64 & 1) | ||
{ | ||
crc64 = (crc64 >> 1) ^ k_Crc64Polynomial; | ||
} | ||
else | ||
{ | ||
crc64 >>= 1; | ||
} | ||
} | ||
|
||
// | ||
// Store the final generated result | ||
// | ||
Checksum.Crc32Table[i] = crc32; | ||
Checksum.Crc64Table[i] = crc64; | ||
} | ||
|
||
// | ||
// No need to do this again | ||
// | ||
Checksum.Initialized = true; | ||
} | ||
} | ||
|
||
uint32_t | ||
XzCrc32 ( | ||
uint32_t Crc, | ||
const uint8_t *Buffer, | ||
uint32_t Length | ||
) | ||
{ | ||
uint32_t i; | ||
|
||
// | ||
// This uses the Dilip V. Sarwate algorithm which shifts one byte at a time | ||
// and produces an intermediate remainder which can then be subtracted from | ||
// the lookup table by using the high 8 bits as an index (since we computed | ||
// all possible one-byte inputs). This relies on the following property: | ||
// | ||
// Mod(A * x^n, P(x)) = Mod(x^n * Mod(A, P(X)), P(X)) | ||
// | ||
for (XzCrcInitialize(), Crc = ~Crc, i = 0; i < Length; ++i) | ||
{ | ||
Crc = Checksum.Crc32Table[Buffer[i] ^ (Crc & 0xFF)] ^ (Crc >> 8); | ||
} | ||
return ~Crc; | ||
} | ||
|
||
uint64_t | ||
XzCrc64 ( | ||
uint64_t Crc, | ||
const uint8_t *Buffer, | ||
uint32_t Length | ||
) | ||
{ | ||
uint32_t i; | ||
// | ||
// Use the same algorithm to the 64-bit case too. Note that for very large | ||
// input data, a parallel "slicing by 8" approach would yield much faster | ||
// results (as would a "slicing by 4" approach for the 32-bit CRC case). | ||
// | ||
for (XzCrcInitialize(), Crc = ~Crc, i = 0; i < Length; ++i) | ||
{ | ||
Crc = Checksum.Crc64Table[Buffer[i] ^ (Crc & 0xFF)] ^ (Crc >> 8); | ||
} | ||
return ~Crc; | ||
} | ||
#endif |
Oops, something went wrong.