Skip to content

Commit

Permalink
OpenEXR/IlmImf/ImfHuf.cpp: Fix OS dependent exr binary data for piz.
Browse files Browse the repository at this point in the history
Issue: piz compressed binary data was OS dependent e.g. different betw linux
 and osx. For example if one did a md5 checksum on the compressed data of an exr with identical image pixel/channel data it would return different checksums on linux and osx for the Piz compressor.

This was due to the fact that the encoding huffman table stored, while having the same entries on linux and osx were sorted differently due to the differing behavior of STL heap sort for encode table entries that were equivalent.

Fix was to simply update the heap compare operator to also handled this equality case.

Updated: OpenEXR/IlmImfTest/testHuf.cpp to test for identical platform/os piz compressed exr file data blocks.

Signed-off-by: Arkell Rasiah <arasiah@pixsystem.com>
  • Loading branch information
arkellr authored and cary-ilm committed Feb 5, 2020
1 parent 89ce46f commit 0042c45
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
22 changes: 21 additions & 1 deletion OpenEXR/IlmImf/ImfHuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,13 @@ getBits (int nBits, Int64 &c, int &lc, const char *&in)
// - see http://www.compressconsult.com/huffman/
//

#if !defined (OPENEXR_IMF_HAVE_LARGE_STACK)
void
hufCanonicalCodeTable (Int64 *hcode)
#else
void
hufCanonicalCodeTable (Int64 hcode[HUF_ENCSIZE])
#endif
{
Int64 n[59];

Expand Down Expand Up @@ -263,11 +268,19 @@ hufCanonicalCodeTable (Int64 hcode[HUF_ENCSIZE])
// - original frequencies are destroyed;
// - encoding tables are used by hufEncode() and hufBuildDecTable();
//
// NB: The following code "(*a == *b) && (a > b))" was added to ensure
// elements in the heap with the same value are sorted by index.
// This is to ensure, the STL make_heap()/pop_heap()/push_heap() methods
// produced a resultant sorted heap that is identical across OSes.
//


struct FHeapCompare
{
bool operator () (Int64 *a, Int64 *b) {return *a > *b;}
bool operator () (Int64 *a, Int64 *b)
{
return ((*a > *b) || ((*a == *b) && (a > b)));
}
};


Expand Down Expand Up @@ -967,10 +980,17 @@ hufDecode
}


#if !defined (OPENEXR_IMF_HAVE_LARGE_STACK)
void
countFrequencies (Int64 *freq,
const unsigned short data[/*n*/],
int n)
#else
void
countFrequencies (Int64 freq[HUF_ENCSIZE],
const unsigned short data[/*n*/],
int n)
#endif
{
for (int i = 0; i < HUF_ENCSIZE; ++i)
freq[i] = 0;
Expand Down
36 changes: 36 additions & 0 deletions OpenEXR/IlmImfTest/testHuf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,41 @@ compressUncompressSubset(const unsigned short raw[], int n)
}



//
// Check the hash is 'dekHash'.
// This check is intended to test for regressions
// in the hufCompress() result or difference results across OSes.
//
void
compressVerify (const unsigned short raw[],
int n,
const unsigned int dekHash)
{
Array <char> compressed (3 * n + 4 * 65536);

int nCompressed = hufCompress (raw, n, compressed);

//
// This hash algorithm proposed by Donald E. Knuth in
// The Art Of Computer Programming Volume 3,
// under the topic of sorting and search chapter 6.4.
//
unsigned int compressedHash = nCompressed;
const char* cptr = compressed;
for (int i = 0; i < nCompressed; ++i)
{
compressedHash =
((compressedHash << 5) ^ (compressedHash >> 27)) ^ (*cptr++);
}

cout << "verifying compressed checksum hash = "
<< compressedHash << std::endl;

assert (compressedHash == dekHash);
}


} // namespace


Expand All @@ -186,6 +221,7 @@ testHuf (const std::string&)
Array <unsigned short> raw (N);

fill1 (raw, N, 1, rand48); // test various symbol distributions
compressVerify(raw, N, 3762495704U);
compressUncompress (raw, N);
compressUncompressSubset (raw, N);
fill1 (raw, N, 10, rand48);
Expand Down

0 comments on commit 0042c45

Please sign in to comment.