/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * Copyright by the Board of Trustees of the University of Illinois. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the files COPYING and Copyright.html. COPYING can be found at the root * * of the source code distribution tree; Copyright.html can be found at the * * root level of an installed copy of the electronic HDF5 document set and * * is linked from the top-level documents page. It can also be found at * * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * * access to either file, you may request a copy from help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * Programmer: Raymond Lu * Jan 3, 2003 */ #define H5Z_PACKAGE /*suppress error about including H5Zpkg */ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* File access */ #include "H5MMprivate.h" /* Memory management */ #include "H5Zpkg.h" /* Data filters */ #ifdef H5_HAVE_FILTER_FLETCHER32 /* Local function prototypes */ static size_t H5Z_filter_fletcher32 (unsigned flags, size_t cd_nelmts, const unsigned cd_values[], size_t nbytes, size_t *buf_size, void **buf); /* This message derives from H5Z */ const H5Z_class_t H5Z_FLETCHER32[1] = {{ H5Z_FILTER_FLETCHER32, /* Filter id number */ "fletcher32", /* Filter name for debugging */ NULL, /* The "can apply" callback */ NULL, /* The "set local" callback */ H5Z_filter_fletcher32, /* The actual filter function */ }}; #define FLETCHER_LEN 4 /*------------------------------------------------------------------------- * Function: H5Z_filter_fletcher32_compute * * Purpose: Implement an Fletcher32 Checksum using 1's complement. * * Return: Success: Fletcher32 value * * Failure: Can't fail * * Programmer: Raymond Lu * Jan 3, 2003 * * Modifications: Pedro Vicente, March 10, 2004 * defined *SRC as unsigned char for all cases * *------------------------------------------------------------------------- */ static uint32_t H5Z_filter_fletcher32_compute(void *_src, size_t len) { unsigned char *src=(unsigned char *)_src; /*To handle unusual platforms like Cray*/ unsigned short tmp_src; size_t count = len; /* Number of bytes left to checksum */ uint32_t s1 = 0, s2 = 0; /* Temporary partial checksums */ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_filter_fletcher32_compute) /* Compute checksum */ while(count > 1) { /*To handle unusual platforms like Cray*/ tmp_src = (((unsigned short)src[0])<<8) | ((unsigned short)src[1]); src +=2; s1 += tmp_src; if(s1 & 0xFFFF0000) { /*Wrap around carry if occurred*/ s1 &= 0xFFFF; s1++; } s2 += s1; if(s2 & 0xFFFF0000) { /*Wrap around carry if occurred*/ s2 &= 0xFFFF; s2++; } count -= 2; } if(count==1) { s1 += *(unsigned char*)src; if(s1 & 0xFFFF0000) { /*Wrap around carry if occurred*/ s1 &= 0xFFFF; s1++; } s2 += s1; if(s2 & 0xFFFF0000) { /*Wrap around carry if occurred*/ s2 &= 0xFFFF; s2++; } } FUNC_LEAVE_NOAPI((s2 << 16) + s1) } /*------------------------------------------------------------------------- * Function: H5Z_filter_fletcher32 * * Purpose: Implement an I/O filter of Fletcher32 Checksum * * Return: Success: Size of buffer filtered * Failure: 0 * * Programmer: Raymond Lu * Jan 3, 2003 * * Modifications: * Raymond Lu * July 8, 2005 * There was a bug in the calculating code of the Fletcher32 * checksum in the library before v1.6.3. The checksum * value wasn't consistent between big-endian and little-endian * systems. This bug was fixed in Release 1.6.3. However, * after fixing the bug, the checksum value is no longer the * same as before on little-endian system. We'll check both * the correct checksum and the wrong checksum to be consistent * with Release 1.6.2 and before. * *------------------------------------------------------------------------- */ /* ARGSUSED */ static size_t H5Z_filter_fletcher32 (unsigned flags, size_t UNUSED cd_nelmts, const unsigned UNUSED cd_values[], size_t nbytes, size_t *buf_size, void **buf) { void *outbuf = NULL; /* Pointer to new buffer */ unsigned char *src = (unsigned char*)(*buf); uint32_t fletcher; /* Checksum value */ uint32_t reversed_fletcher; /* Possible wrong checksum value */ uint8_t c[4]; uint8_t tmp; size_t ret_value; /* Return value */ FUNC_ENTER_NOAPI(H5Z_filter_fletcher32, 0) assert(sizeof(uint32_t)>=4); if (flags & H5Z_FLAG_REVERSE) { /* Read */ /* Do checksum if it's enabled for read; otherwise skip it * to save performance. */ if (!(flags & H5Z_FLAG_SKIP_EDC)) { unsigned char *tmp_src; /* Pointer to checksum in buffer */ size_t src_nbytes = nbytes; /* Original number of bytes */ uint32_t stored_fletcher; /* Stored checksum value */ /* Get the stored checksum */ src_nbytes -= FLETCHER_LEN; tmp_src=src+src_nbytes; UINT32DECODE(tmp_src, stored_fletcher); /* Compute checksum (can't fail) */ fletcher = H5Z_filter_fletcher32_compute(src,src_nbytes); /* The reversed checksum. There was a bug in the calculating code of * the Fletcher32 checksum in the library before v1.6.3. The checksum * value wasn't consistent between big-endian and little-endian systems. * This bug was fixed in Release 1.6.3. However, after fixing the bug, * the checksum value is no longer the same as before on little-endian * system. We'll check both the correct checksum and the wrong * checksum to be consistent with Release 1.6.2 and before. */ HDmemcpy(c, &fletcher, 4); tmp = c[1]; c[1] = c[0]; c[0] = tmp; tmp = c[3]; c[3] = c[2]; c[2] = tmp; HDmemcpy(&reversed_fletcher, c, 4); /* Verify computed checksum matches stored checksum */ if(stored_fletcher != fletcher && stored_fletcher != reversed_fletcher) HGOTO_ERROR(H5E_STORAGE, H5E_READERROR, 0, "data error detected by Fletcher32 checksum") } /* Set return values */ /* (Re-use the input buffer, just note that the size is smaller by the size of the checksum) */ ret_value = nbytes-FLETCHER_LEN; } else { /* Write */ unsigned char *dst; /* Temporary pointer to destination buffer */ /* Compute checksum (can't fail) */ fletcher = H5Z_filter_fletcher32_compute(src,nbytes); if (NULL==(dst=outbuf=H5MM_malloc(nbytes+FLETCHER_LEN))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "unable to allocate Fletcher32 checksum destination buffer") /* Copy raw data */ HDmemcpy((void*)dst, (void*)(*buf), nbytes); /* Append checksum to raw data for storage */ dst += nbytes; UINT32ENCODE(dst, fletcher); /* Free input buffer */ H5MM_xfree(*buf); /* Set return values */ *buf_size = nbytes + FLETCHER_LEN; *buf = outbuf; outbuf = NULL; ret_value = *buf_size; } done: if(outbuf) H5MM_xfree(outbuf); FUNC_LEAVE_NOAPI(ret_value) } #endif /* H5_HAVE_FILTER_FLETCHER32 */