summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorandreas_kupries <akupries@shaw.ca>2008-12-02 18:23:25 (GMT)
committerandreas_kupries <akupries@shaw.ca>2008-12-02 18:23:25 (GMT)
commit2dfd8ade3922490eb358d6d3d64d6f6f19c5192c (patch)
tree372a297a64180cf0b524e9b6fa1c7f17bad5d52e /generic
parente6d9dee6e2c834ae1e8010b08931692f25e6c3b4 (diff)
downloadtcl-2dfd8ade3922490eb358d6d3d64d6f6f19c5192c.zip
tcl-2dfd8ade3922490eb358d6d3d64d6f6f19c5192c.tar.gz
tcl-2dfd8ade3922490eb358d6d3d64d6f6f19c5192c.tar.bz2
* generic/tclIO.c (TclFinalizeIOSubsystem): Replaced Alexandre
Ferrieux's first patch for [Bug 2270477] with a gentler version, also supplied by him.
Diffstat (limited to 'generic')
-rw-r--r--generic/tclIO.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index fdd6cba..e6e11d0 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIO.c,v 1.150 2008/11/25 23:19:01 nijtmans Exp $
+ * RCS: @(#) $Id: tclIO.c,v 1.151 2008/12/02 18:23:25 andreas_kupries Exp $
*/
#include "tclInt.h"
@@ -299,7 +299,7 @@ TclFinalizeIOSubsystem(void)
statePtr != NULL;
statePtr = statePtr->nextCSPtr) {
chanPtr = statePtr->topChanPtr;
- if (!(statePtr->flags & CHANNEL_DEAD)) {
+ if (!(statePtr->flags & (CHANNEL_INCLOSE|CHANNEL_CLOSED|CHANNEL_DEAD))) {
active = 1;
break;
}
@@ -364,8 +364,8 @@ TclFinalizeIOSubsystem(void)
*/
chanPtr->instanceData = NULL;
+ SetFlag(statePtr, CHANNEL_DEAD);
}
- SetFlag(statePtr, CHANNEL_DEAD);
}
}
> 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html.  If you do not have     *
 * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#define H5Z_PACKAGE		/*suppress error about including H5Zpkg	  */

#include "H5private.h"		/* Generic Functions			*/
#include "H5Eprivate.h"		/* Error handling		  	*/
#include "H5MMprivate.h"	/* Memory management			*/
#include "H5Ppublic.h"		/* Property lists			*/
#include "H5Oprivate.h"         /* Object headers                       */
#include "H5Tpublic.h"		/* Datatype functions			*/
#include "H5Zpkg.h"		/* Data filters				*/

#ifdef H5_HAVE_FILTER_NBIT

/* Struct of parameters needed for compressing/decompressing
 * one nbit atomic datatype: integer or floating-point
 */
typedef struct {
   size_t size;   /* size of datatype */
   int order;     /* datatype endianness order */
   int precision; /* datatype precision */
   int offset;    /* datatype offset */
} parms_atomic;

/* Local function prototypes */
static herr_t H5Z_can_apply_nbit(hid_t dcpl_id, hid_t type_id, hid_t space_id);
static herr_t H5Z_set_local_nbit(hid_t dcpl_id, hid_t type_id, hid_t space_id);
static size_t H5Z_filter_nbit(unsigned flags, size_t cd_nelmts, const unsigned cd_values[],
                              size_t nbytes, size_t *buf_size, void **buf);

static void H5Z_calc_parms_nooptype(void);
static void H5Z_calc_parms_atomic(void);
static herr_t H5Z_calc_parms_array(hid_t type_id);
static herr_t H5Z_calc_parms_compound(hid_t type_id);

static herr_t H5Z_set_parms_nooptype(hid_t type_id, unsigned cd_values[]);
static herr_t H5Z_set_parms_atomic(hid_t type_id, unsigned cd_values[]);
static herr_t H5Z_set_parms_array(hid_t type_id, unsigned cd_values[]);
static herr_t H5Z_set_parms_compound(hid_t type_id, unsigned cd_values[]);

static void H5Z_nbit_next_byte(size_t *j, int *buf_len);
static void H5Z_nbit_decompress_one_byte(unsigned char *data, size_t data_offset, int k, int begin_i,
int end_i, unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p, int datatype_len);
static void H5Z_nbit_compress_one_byte(unsigned char *data, size_t data_offset, int k, int begin_i,
int end_i, unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p, int datatype_len);
static void H5Z_nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset,
                       unsigned char *buffer, size_t *j, int *buf_len, unsigned size);
static void H5Z_nbit_decompress_one_atomic(unsigned char *data, size_t data_offset,
                    unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p);
static void H5Z_nbit_decompress_one_array(unsigned char *data, size_t data_offset,
           unsigned char *buffer, size_t *j, int *buf_len, const unsigned parms[]);
static void H5Z_nbit_decompress_one_compound(unsigned char *data, size_t data_offset,
              unsigned char *buffer, size_t *j, int *buf_len, const unsigned parms[]);
static void H5Z_nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
                                const unsigned parms[]);
static void H5Z_nbit_compress_one_nooptype(unsigned char *data, size_t data_offset,
                     unsigned char *buffer, size_t *j, int *buf_len, unsigned size);
static void H5Z_nbit_compress_one_atomic(unsigned char *data, size_t data_offset,
                  unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p);
static void H5Z_nbit_compress_one_array(unsigned char *data, size_t data_offset,
         unsigned char *buffer, size_t *j, int *buf_len, const unsigned parms[]);
static void H5Z_nbit_compress_one_compound(unsigned char *data, size_t data_offset,
            unsigned char *buffer, size_t *j, int *buf_len, const unsigned parms[]);
static void H5Z_nbit_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
                              size_t *buffer_size, const unsigned parms[]);

/* This message derives from H5Z */
H5Z_class_t H5Z_NBIT[1] = {{
    H5Z_CLASS_T_VERS,       /* H5Z_class_t version */
    H5Z_FILTER_NBIT,		/* Filter id number		*/
    1,              /* Assume encoder present: check before registering */
    1,                  /* decoder_present flag (set to true) */
    "nbit",			    /* Filter name for debugging	*/
    H5Z_can_apply_nbit,		/* The "can apply" callback     */
    H5Z_set_local_nbit,         /* The "set local" callback     */
    H5Z_filter_nbit,		/* The actual filter function	*/
}};

/* Local macros */
#define H5Z_NBIT_ATOMIC          1     /* Atomic datatype class: integer/floating-point */
#define H5Z_NBIT_ARRAY           2     /* Array datatype class */
#define H5Z_NBIT_COMPOUND        3     /* Compound datatype class */
#define H5Z_NBIT_NOOPTYPE        4     /* Other datatype class: nbit does no compression */
#define H5Z_NBIT_USER_NPARMS     0     /* Number of parameters that users can set */
#define H5Z_NBIT_MAX_NPARMS      4096  /* Max number of parameters for filter */
#define H5Z_NBIT_ORDER_LE        0     /* Little endian for datatype byte order */
#define H5Z_NBIT_ORDER_BE        1     /* Big endian for datatype byte order */

/* Local variables */
/*
 * cd_values_index: index of array cd_values inside function H5Z_set_local_nbit
 * cd_values_actual_nparms: number of parameters in array cd_values[]
 * need_not_compress: flag if TRUE indicating no need to do nbit compression
 * parms_index: index of array parms used by compression/decompression functions
 */
static unsigned cd_values_index = 0;
static size_t cd_values_actual_nparms = 0;
static unsigned char need_not_compress = FALSE;
static unsigned parms_index = 0;


/*-------------------------------------------------------------------------
 * Function:	H5Z_can_apply_nbit
 *
 * Purpose:	Check the parameters for nbit compression for validity and
 *              whether they fit a particular dataset.
 *
 * Return:	Success: Non-negative
 *		Failure: Negative
 *
 * Programmer:  Xiaowen Wu
 *              Tuesday, December 21, 2004
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5Z_can_apply_nbit(hid_t UNUSED dcpl_id, hid_t type_id, hid_t UNUSED space_id)
{
    herr_t ret_value=TRUE;              /* Return value */

    FUNC_ENTER_NOAPI(H5Z_can_apply_nbit, FAIL)

    /* Get datatype's class, for checking the "datatype class" */
    if(H5Tget_class(type_id) == H5T_NO_CLASS )
	HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class")

    /* Get datatype's size, for checking the "datatype size" */
    if(H5Tget_size(type_id) == 0)
	HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_can_apply_nbit() */


/*-------------------------------------------------------------------------
 * Function:    H5Z_calc_parms_nooptype
 *
 * Purpose:     Calculate the number of parameters of array cd_values[]
 *              of datatype that is not integer, nor floating-point, nor
 *              compound, and nor array.
 *
 * Programmer:  Xiaowen Wu
 *              Thursday, March 3, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static void H5Z_calc_parms_nooptype(void)
{
    /* Store datatype class code */
    ++cd_values_actual_nparms;

    /* Store datatype size */
    ++cd_values_actual_nparms;
}


/*-------------------------------------------------------------------------
 * Function:    H5Z_calc_parms_atomic
 *
 * Purpose:     Calculate the number of parameters of array cd_values[]
 *              of atomic datatype whose datatype class is integer
 *              or floating point
 *
 * Programmer:  Xiaowen Wu
 *              Saturday, January 29, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static void H5Z_calc_parms_atomic(void)
{
    /* Store datatype class code */
    ++cd_values_actual_nparms;

    /* Store datatype size */
    ++cd_values_actual_nparms;

    /* Store datatype endianness */
    ++cd_values_actual_nparms;

    /* Store datatype's precision */
    ++cd_values_actual_nparms;

    /* Store datatype's offset */
    ++cd_values_actual_nparms;
}


/*-------------------------------------------------------------------------
 * Function:    H5Z_calc_parms_array
 *
 * Purpose:     Calculate the number of parameters of array cd_values[]
 *              for a given datatype identifier type_id
 *              if its datatype class is array datatype
 *
 * Return:      Success: Non-negative
 *              Failure: Negative
 *
 * Programmer:  Xiaowen Wu
 *              Wednesday, January 19, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t H5Z_calc_parms_array(hid_t type_id)
{
    hid_t       dtype_base;        /* Array datatype's base datatype */
    H5T_class_t dtype_base_class;  /* Array datatype's base datatype's class */
    herr_t ret_value=SUCCEED;      /* Return value */

    FUNC_ENTER_NOAPI(H5Z_calc_parms_array, FAIL)

    /* Store datatype class code */
    ++cd_values_actual_nparms;

    /* Store array datatype's size */
    ++cd_values_actual_nparms;

    /* Get array datatype's base datatype */
    if((dtype_base=H5Tget_super(type_id))<0)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype")

    /* Get base datatype's class */
    if((dtype_base_class=H5Tget_class(dtype_base))==H5T_NO_CLASS )
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype class")

    /* Calculate number of the rest parameters according to base datatype's class */
    switch(dtype_base_class) {
        case H5T_INTEGER:
        case H5T_FLOAT:
            H5Z_calc_parms_atomic();
            break;
        case H5T_ARRAY:
            if(H5Z_calc_parms_array(dtype_base)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot compute parameters for datatype")
            break;
        case H5T_COMPOUND:
            if(H5Z_calc_parms_compound(dtype_base)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot compute parameters for datatype")
            break;
        default: /* Other datatype class: nbit does no compression */
            H5Z_calc_parms_nooptype();
            break;
    } /* end switch */

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_calc_parms_array() */


/*-------------------------------------------------------------------------
 * Function:    H5Z_calc_parms_compound
 *
 * Purpose:     Calculate the number of parameters of array cd_values[]
 *              for a given datatype identifier type_id
 *              if its datatype class is compound datatype
 *
 * Return:      Success: Non-negative
 *              Failure: Negative
 *
 * Programmer:  Xiaowen Wu
 *              Wednesday, January 19, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t H5Z_calc_parms_compound(hid_t type_id)
{
    int         i;                  /* local index variable */
    int         nmembers;           /* Compound datatype's number of members */
    hid_t       dtype_member;       /* Compound datatype's member datatype */
    H5T_class_t dtype_member_class; /* Compound datatype's member datatype's class */
    herr_t ret_value=SUCCEED;       /* Return value */

    FUNC_ENTER_NOAPI(H5Z_calc_parms_compound, FAIL)

    /* Store compound datatype class code */
    ++cd_values_actual_nparms;

    /* Store compound datatype's size */
    ++cd_values_actual_nparms;

    /* Get number of members */
    if((nmembers=H5Tget_nmembers(type_id))<0)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype number of members")

    /* Store number of members */
    ++cd_values_actual_nparms;

    /* For each member, calculate parameters */
    for(i = 0; i < nmembers; i++) {
        /* Get member datatype */
        if((dtype_member=H5Tget_member_type(type_id, (unsigned)i))<0)
            HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype")

        /* Get member datatype's class */
        if((dtype_member_class=H5Tget_member_class(type_id, (unsigned)i))<0)
            HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype class")

        /* Store member offset */
        ++cd_values_actual_nparms;

        /* Calculate parameters according to member's datatype class */
        switch(dtype_member_class) {
            case H5T_INTEGER:
            case H5T_FLOAT:
                H5Z_calc_parms_atomic();
                break;
            case H5T_ARRAY:
                if(H5Z_calc_parms_array(dtype_member)==FAIL)
                    HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot compute parameters for datatype")
                break;
            case H5T_COMPOUND:
                if(H5Z_calc_parms_compound(dtype_member)==FAIL)
                    HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot compute parameters for datatype")
                break;
            default: /* Other datatype class: nbit does no compression */
                H5Z_calc_parms_nooptype();
                break;
        } /* end switch */
    } /* end for */
done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_calc_params_compound */


/*-------------------------------------------------------------------------
 * Function:    H5Z_set_parms_nooptype
 *
 * Purpose:     Set the array cd_values[] for a given datatype identifier
 *              type_id if its datatype class is not integer, nor
 *              floating-point, nor array, nor compound, nor VL datatype,
 *              and nor VL string
 *
 * Return:      Success: Non-negative
 *              Failure: Negative
 *
 * Programmer:  Xiaowen Wu
 *              Tuesday, April 5, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t H5Z_set_parms_nooptype(hid_t type_id, unsigned cd_values[])
{
    size_t dtype_size;          /* No-op datatype's size (in bytes) */
    herr_t ret_value=SUCCEED;   /* Return value */

    FUNC_ENTER_NOAPI(H5Z_set_parms_nooptype, FAIL)

    /* Set datatype class code */
    cd_values[cd_values_index++] = H5Z_NBIT_NOOPTYPE;

    /* Get datatype's size */
    if((dtype_size=H5Tget_size(type_id))==0)
	HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")

    /* Set "local" parameter for datatype size */
    cd_values[cd_values_index++] = dtype_size;

done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_set_parms_nooptype() */


/*-------------------------------------------------------------------------
 * Function:    H5Z_set_parms_atomic
 *
 * Purpose:     Set the array cd_values[] for a given datatype identifier
 *              type_id if its datatype class is integer or floating point
 *
 * Return:      Success: Non-negative
 *              Failure: Negative
 *
 * Programmer:  Xiaowen Wu
 *              Tuesday, January 11, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t H5Z_set_parms_atomic(hid_t type_id, unsigned cd_values[])
{
    H5T_order_t dtype_order;    /* Atomic datatype's endianness order */
    size_t dtype_size;          /* Atomic datatype's size (in bytes) */
    size_t dtype_precision;     /* Atomic datatype's precision (in bits) */
    int dtype_offset;           /* Atomic datatype's offset (in bits) */
    herr_t ret_value=SUCCEED;   /* Return value */

    FUNC_ENTER_NOAPI(H5Z_set_parms_atomic, FAIL)

    /* Set datatype class code */
    cd_values[cd_values_index++] = H5Z_NBIT_ATOMIC;

    /* Get datatype's size */
    if((dtype_size=H5Tget_size(type_id))==0)
	HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")

    /* Set "local" parameter for datatype size */
    cd_values[cd_values_index++] = dtype_size;

    /* Get datatype's endianness order */
    if((dtype_order=H5Tget_order(type_id))==H5T_ORDER_ERROR)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")

    /* Set "local" parameter for datatype endianness */
    switch(dtype_order) {
        case H5T_ORDER_LE:      /* Little-endian byte order */
            cd_values[cd_values_index++] = H5Z_NBIT_ORDER_LE;
            break;
        case H5T_ORDER_BE:      /* Big-endian byte order */
            cd_values[cd_values_index++] = H5Z_NBIT_ORDER_BE;
            break;
        default:
            HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype endianness order")
    } /* end switch */

    /* Get datatype's precision */
    if((dtype_precision=H5Tget_precision(type_id))==0)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype precision")

    /* Get datatype's offset */
    if((dtype_offset=H5Tget_offset(type_id))<0)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype offset")

    /* Check values of precision and offset */
    if(dtype_precision>dtype_size*8 || (dtype_precision+dtype_offset)>dtype_size*8
       || dtype_precision<=0 || dtype_offset<0)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "invalid datatype precision/offset")

    /* Set "local" parameter for datatype precision */
    cd_values[cd_values_index++] = dtype_precision;

    /* Set "local" parameter for datatype offset */
    cd_values[cd_values_index++] = dtype_offset;

    /* If before this point, there is no need to compress, check the need to
     * compress at this point. If current datatype is not full-precision,
     * flag need_not_compress should be set to FALSE.
     */
    if(need_not_compress) /* so far no need to compress */
       if(dtype_offset != 0 || dtype_precision != dtype_size * 8)
          need_not_compress = FALSE;
done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_set_parms_atomic() */


/*-------------------------------------------------------------------------
 * Function:    H5Z_set_parms_array
 *
 * Purpose:     Set the array cd_values[] for a given datatype identifier
 *              type_id if its datatype class is array datatype
 *
 * Return:      Success: Non-negative
 *              Failure: Negative
 *
 * Programmer:  Xiaowen Wu
 *              Tuesday, April 5, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t H5Z_set_parms_array(hid_t type_id, unsigned cd_values[])
{
    hid_t       dtype_base;        /* Array datatype's base datatype */
    H5T_class_t dtype_base_class;  /* Array datatype's base datatype's class */
    size_t dtype_size;             /* Array datatype's size (in bytes) */
    htri_t is_vlstring;            /* flag indicating if datatype is varible-length string */
    herr_t ret_value=SUCCEED;      /* Return value */

    FUNC_ENTER_NOAPI(H5Z_set_parms_array, FAIL)

    /* Set datatype class code */
    cd_values[cd_values_index++] = H5Z_NBIT_ARRAY;

    /* Get array datatype's size */
    if((dtype_size=H5Tget_size(type_id))==0)
	HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")

    /* Set "local" parameter for array datatype's size */
    cd_values[cd_values_index++]=dtype_size;

    /* Get array datatype's base datatype */
    if((dtype_base=H5Tget_super(type_id))<0)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype")

    /* Get base datatype's class */
    if((dtype_base_class=H5Tget_class(dtype_base))==H5T_NO_CLASS )
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad base datatype class")

    /* Call appropriate function according to base datatype's class */
    switch(dtype_base_class) {
        case H5T_INTEGER:
        case H5T_FLOAT:
            if(H5Z_set_parms_atomic(dtype_base, cd_values)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
            break;
        case H5T_ARRAY:
            if(H5Z_set_parms_array(dtype_base, cd_values)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
            break;
        case H5T_COMPOUND:
            if(H5Z_set_parms_compound(dtype_base, cd_values)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
            break;
        default: /* other datatype that nbit does no compression */
            /* Check if base datatype is a variable-length string */
            if((is_vlstring=H5Tis_variable_str(dtype_base))<0)
                HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL,
                            "cannot determine if datatype is a variable-length string")

            /* base datatype of VL or VL-string is not supported */
            if(dtype_base_class == H5T_VLEN || is_vlstring)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"datatype not supported by nbit")

            if(H5Z_set_parms_nooptype(dtype_base, cd_values)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
            break;
    } /* end switch */
done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_set_parms_array() */


/*-------------------------------------------------------------------------
 * Function:    H5Z_set_parms_compound
 *
 * Purpose:     Set the array cd_values[] for a given datatype identifier
 *              type_id if its datatype class is compound datatype
 *
 * Return:      Success: Non-negative
 *              Failure: Negative
 *
 * Programmer:  Xiaowen Wu
 *              Tuesday, April 5, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t H5Z_set_parms_compound(hid_t type_id, unsigned cd_values[])
{
    int         i;                  /* local index variable */
    int         nmembers;           /* Compound datatype's number of members */
    hid_t       dtype_member;       /* Compound datatype's member datatype */
    H5T_class_t dtype_member_class; /* Compound datatype's member datatype's class */
    size_t dtype_member_offset;     /* Compound datatype's current member datatype's offset (in bytes) */
    size_t dtype_next_member_offset;/* Compound datatype's next member datatype's offset (in bytes) */
    size_t dtype_size;              /* Compound datatype's size (in bytes) */
    htri_t is_vlstring;             /* flag indicating if datatype is varible-length string */
    herr_t ret_value=SUCCEED;       /* Return value */

    FUNC_ENTER_NOAPI(H5Z_set_parms_compound, FAIL)

    /* Set "local" parameter for compound datatype class code */
    cd_values[cd_values_index++] = H5Z_NBIT_COMPOUND;

    /* Get datatype's size */
    if((dtype_size=H5Tget_size(type_id))==0)
	HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype size")

    /* Set "local" parameter for compound datatype size */
    cd_values[cd_values_index++] = dtype_size;

    /* Get number of members */
    if((nmembers=H5Tget_nmembers(type_id))<0)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype number of members")

    /* Set "local" parameter for number of members */
    cd_values[cd_values_index++] = nmembers;

    /* For each member, set parameters */
    for(i = 0; i < nmembers; i++) {
        /* Get member datatype */
        if((dtype_member=H5Tget_member_type(type_id, (unsigned)i))<0)
            HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype")

        /* Get member datatype's class */
        if((dtype_member_class=H5Tget_member_class(type_id, (unsigned)i))<0)
            HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad member datatype class")

        /* Get member offset, success if H5Tget_member_class() success */
        dtype_member_offset =  H5Tget_member_offset(type_id, (unsigned)i);

        /* Set "local" parameter for member offset */
        cd_values[cd_values_index++] = dtype_member_offset;

        /* Call appropriate function according to member's datatype class */
        switch(dtype_member_class) {
            case H5T_INTEGER:
            case H5T_FLOAT:
                if(H5Z_set_parms_atomic(dtype_member, cd_values)==FAIL)
                    HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
                break;
            case H5T_ARRAY:
                if(H5Z_set_parms_array(dtype_member, cd_values)==FAIL)
                    HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
                break;
            case H5T_COMPOUND:
                if(H5Z_set_parms_compound(dtype_member, cd_values)==FAIL)
                    HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
                break;
            default: /* other datatype that nbit does no compression */
                /* Check if datatype is a variable-length string */
                if((is_vlstring=H5Tis_variable_str(dtype_member))<0)
                    HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL,
                                "cannot determine if datatype is a variable-length string")

                /* Because for some no-op datatype (VL datatype and VL string datatype), its
		 * size can not be retrieved correctly by using function call H5Tget_size,
		 * special handling is needed for getting the size. Here the difference between
                 * adjacent member offset is used (if alignment is present, the result can be
		 * larger, but it does not affect the nbit filter's correctness).
                 */
                if(dtype_member_class == H5T_VLEN || is_vlstring) {
                    /* Set datatype class code */
                    cd_values[cd_values_index++] = H5Z_NBIT_NOOPTYPE;

                    if(i != nmembers - 1)
                        dtype_next_member_offset = H5Tget_member_offset(type_id,(unsigned)i+1);
                    else /* current member is the last member */
                        dtype_next_member_offset = dtype_size;

                    /* Set "local" parameter for datatype size */
                    cd_values[cd_values_index++] = dtype_next_member_offset - dtype_member_offset;
                } else
                    if(H5Z_set_parms_nooptype(dtype_member, cd_values)==FAIL)
                        HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
                break;
        } /* end switch */
    } /* end for */
done:
    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_set_params_compound */


/*-------------------------------------------------------------------------
 * Function:	H5Z_set_local_nbit
 *
 * Purpose:	Set the "local" dataset parameters for nbit compression.
 *
 * Return:	Success: Non-negative
 *		Failure: Negative
 *
 * Programmer:	Xiaowen Wu
 *              Tuesday, January 11, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static herr_t
H5Z_set_local_nbit(hid_t dcpl_id, hid_t type_id, hid_t space_id)
{
    unsigned flags;         /* Filter flags */
    size_t cd_nelmts=H5Z_NBIT_USER_NPARMS;  /* Number of filter parameters */
    unsigned *cd_values = NULL;    /* Filter parameters */
    hssize_t npoints;              /* Number of points in the dataspace */
    H5T_class_t dtype_class;       /* Datatype's class */
    herr_t ret_value=SUCCEED;      /* Return value */

    FUNC_ENTER_NOAPI(H5Z_set_local_nbit, FAIL)

    /* Get datatype's class */
    if((dtype_class = H5Tget_class(type_id)) == H5T_NO_CLASS )
	HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "bad datatype class")

    /* Calculate how many parameters will fill the cd_values array
     * First three parameters reserved for:
     *   1. number of parameters in array cd_values
     *   2. flag if TRUE indicating no need to do nbit compression
     *   3. number of elements in the chunk
     */
    cd_values_actual_nparms = 3;
    switch(dtype_class) {
        case H5T_INTEGER:
        case H5T_FLOAT:
            H5Z_calc_parms_atomic();
            break;
        case H5T_ARRAY:
            if(H5Z_calc_parms_array(type_id)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot compute parameters for datatype")
            break;
        case H5T_COMPOUND:
            if(H5Z_calc_parms_compound(type_id)==FAIL)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot compute parameters for datatype")
            break;
        default: /* no need to calculate other datatypes at top level */
             break;
    } /* end switch */

    /* Check if the number of parameters exceed what cd_values[] can store */
    if(cd_values_actual_nparms > H5Z_NBIT_MAX_NPARMS)
        HGOTO_ERROR(H5E_PLINE, H5E_BADTYPE, FAIL, "datatype needs too many nbit parameters")

    /* Allocate memory space for cd_values[] */
    if(NULL == (cd_values = H5MM_malloc(cd_values_actual_nparms * sizeof(unsigned))))
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for cd_values[]")

    /* Get the filter's current parameters */
#ifdef H5_WANT_H5_V1_6_COMPAT
    if(H5Pget_filter_by_id(dcpl_id, H5Z_FILTER_NBIT, &flags, &cd_nelmts, cd_values, (size_t)0, NULL) < 0)
#else
    if(H5Pget_filter_by_id(dcpl_id, H5Z_FILTER_NBIT, &flags, &cd_nelmts, cd_values, (size_t)0, NULL, NULL) < 0)
#endif
	HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "can't get nbit parameters")

    /* Get total number of elements in the chunk */
    if((npoints = H5Sget_simple_extent_npoints(space_id)) < 0)
        HGOTO_ERROR(H5E_PLINE, H5E_CANTGET, FAIL, "unable to get number of points in the dataspace")

    /* Initialize index for cd_values array starting from the third entry */
    cd_values_index = 2;

    /* Set "local" parameter for number of elements in the chunk */
    H5_ASSIGN_OVERFLOW(cd_values[cd_values_index++], npoints, hssize_t, unsigned);

    /* Assume no need to compress now, will be changed to FALSE later if not */
    need_not_compress = TRUE;

    /* Call appropriate function according to the datatype class */
    switch(dtype_class) {
        case H5T_INTEGER:
        case H5T_FLOAT:
            if(H5Z_set_parms_atomic(type_id, cd_values) < 0)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
            break;

        case H5T_ARRAY:
            if(H5Z_set_parms_array(type_id, cd_values) < 0)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
            break;

        case H5T_COMPOUND:
            if(H5Z_set_parms_compound(type_id, cd_values) < 0)
                HGOTO_ERROR(H5E_PLINE,H5E_BADTYPE,FAIL,"nbit cannot set parameters for datatype")
            break;

        default: /* no need to set parameters for other datatypes at top level */
             break;
    } /* end switch */

    /* Check if calculation of parameters matches with setting of parameters */
    HDassert(cd_values_actual_nparms == cd_values_index);

    /* Finally set the first two entries of cd_values[] */
    cd_values[0] = cd_values_actual_nparms;
    cd_values[1] = need_not_compress;

    /* Modify the filter's parameters for this dataset */
    if(H5Pmodify_filter(dcpl_id, H5Z_FILTER_NBIT, flags, cd_values_actual_nparms, cd_values) < 0)
	HGOTO_ERROR(H5E_PLINE, H5E_CANTSET, FAIL, "can't set local nbit parameters")

done:
    if(cd_values)
	H5MM_xfree(cd_values);

    FUNC_LEAVE_NOAPI(ret_value)
} /* end H5Z_set_local_nbit() */


/*-------------------------------------------------------------------------
 * Function:	H5Z_filter_nbit
 *
 * Purpose:	Implement an I/O filter for storing packed nbit data
 *
 * Return:	Success: Size of buffer filtered
 *		Failure: 0
 *
 * Programmer:	Xiaowen Wu
 *              Friday, January 21, 2005
 *
 * Modifications:
 *
 *-------------------------------------------------------------------------
 */
static size_t
H5Z_filter_nbit(unsigned flags, size_t cd_nelmts, const unsigned cd_values[],
                size_t nbytes, size_t *buf_size, void **buf)
{
    size_t ret_value = 0;          /* return value */
    size_t size_out  = 0;          /* size of output buffer */
    unsigned d_nelmts = 0;         /* number of elements in the chunk */
    unsigned char *outbuf = NULL;  /* pointer to new output buffer */

    FUNC_ENTER_NOAPI(H5Z_filter_nbit, 0)

    /* check arguments
     * cd_values[0] stores actual number of parameters in cd_values[]
     */
    if (cd_nelmts!=cd_values[0])
	HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid nbit aggression level")

    /* check if need to do nbit compress or decompress
     * cd_values[1] stores the flag if true indicating no need to compress
     */
    if (cd_values[1]) {
        ret_value = *buf_size;
        goto done;
    }

    /* copy a filter parameter to d_nelmts */
    d_nelmts = cd_values[2];

    /* input; decompress */
    if (flags & H5Z_FLAG_REVERSE) {
        size_out = d_nelmts * cd_values[4]; /* cd_values[4] stores datatype size */

        /* allocate memory space for decompressed buffer */
        if(NULL==(outbuf = H5MM_malloc(size_out)))
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for nbit decompression")

        /* decompress the buffer */
        H5Z_nbit_decompress(outbuf, d_nelmts, *buf, cd_values);
    }
    /* output; compress */
    else {
        assert(nbytes == d_nelmts * cd_values[4]);

        size_out = nbytes;

        /* allocate memory space for compressed buffer */
        if(NULL==(outbuf = H5MM_malloc(size_out)))
            HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "memory allocation failed for nbit compression")

        /* compress the buffer, size_out will be changed */
        H5Z_nbit_compress(*buf, d_nelmts, outbuf, &size_out, cd_values);
    }

    /* free the input buffer */
    H5MM_xfree(*buf);

    /* set return values */
    *buf = outbuf;
    outbuf = NULL;
    *buf_size = size_out;
    ret_value = size_out;

done:
    if(outbuf)
        H5MM_xfree(outbuf);
    FUNC_LEAVE_NOAPI(ret_value)
}

/* ======== Nbit Algorithm ===============================================
 * assume one byte has 8 bit
 * assume padding bit is 0
 * assume size of unsigned char is one byte
 * assume one data item of certain datatype is stored continously in bytes
 * atomic datatype is treated on byte basis
 */

static void H5Z_nbit_next_byte(size_t *j, int *buf_len)
{
   ++(*j);
   *buf_len = 8 * sizeof(unsigned char);
}

static void H5Z_nbit_decompress_one_byte(unsigned char *data, size_t data_offset, int k, int begin_i,
int end_i, unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p, int datatype_len)
{
   int dat_len; /* dat_len is the number of bits to be copied in each data byte */
   int uchar_offset;
   unsigned char val; /* value to be copied in each data byte */

   /* initialize value and bits of unsigned char to be copied */
   val = buffer[*j];
   uchar_offset = 0;

   if(begin_i != end_i) { /* significant bits occupy >1 unsigned char */
      if(k == begin_i)
         dat_len = 8 - (datatype_len - p.precision - p.offset) % 8;
      else if(k == end_i) {
         dat_len = 8 - p.offset %8;
         uchar_offset = 8 - dat_len;
      }
      else
         dat_len = 8;
   } else { /* all significant bits in one unsigned char */
      uchar_offset = p.offset % 8;
      dat_len = p.precision;
   }

   if(*buf_len > dat_len) {
      data[data_offset + k] =
      ((val >> (*buf_len - dat_len)) & ~(~0 << dat_len)) << uchar_offset;
      *buf_len -= dat_len;
   } else {
      data[data_offset + k] =
      ((val & ~(~0 << *buf_len)) << (dat_len - *buf_len)) << uchar_offset;
      dat_len -= *buf_len;
      H5Z_nbit_next_byte(j, buf_len);
      if(dat_len == 0) return;

      val = buffer[*j];
      data[data_offset + k] |=
      ((val >> (*buf_len - dat_len)) & ~(~0 << dat_len)) << uchar_offset;
      *buf_len -= dat_len;
   }
}

static void H5Z_nbit_decompress_one_nooptype(unsigned char *data, size_t data_offset,
                       unsigned char *buffer, size_t *j, int *buf_len, unsigned size)
{
   unsigned i;        /* index */
   unsigned dat_len;  /* dat_len is the number of bits to be copied in each data byte */
   unsigned char val; /* value to be copied in each data byte */

   for(i = 0; i < size; i++) {
      /* initialize value and bits of unsigned char to be copied */
      val = buffer[*j];
      dat_len = sizeof(unsigned char) * 8;

      data[data_offset + i] = ((val & ~(~0 << *buf_len)) << (dat_len - *buf_len));
      dat_len -= *buf_len;
      H5Z_nbit_next_byte(j, buf_len);
      if(dat_len == 0) continue;

      val = buffer[*j];
      data[data_offset + i] |= ((val >> (*buf_len - dat_len)) & ~(~0 << dat_len));
      *buf_len -= dat_len;
   }
}

static void H5Z_nbit_decompress_one_atomic(unsigned char *data, size_t data_offset,
                    unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p)
{
   /* begin_i: the index of byte having first significant bit
      end_i: the index of byte having last significant bit */
   int k, begin_i, end_i, datatype_len;

   datatype_len = p.size * 8;

   if(p.order == H5Z_NBIT_ORDER_LE) { /* little endian */
      /* calculate begin_i and end_i */
      if((p.precision + p.offset) % 8 != 0)
         begin_i = (p.precision + p.offset) / 8;
      else
         begin_i = (p.precision + p.offset) / 8 - 1;
      end_i = p.offset / 8;

      for(k = begin_i; k >= end_i; k--)
         H5Z_nbit_decompress_one_byte(data, data_offset, k, begin_i, end_i,
                                      buffer, j, buf_len, p, datatype_len);
   }

   if(p.order == H5Z_NBIT_ORDER_BE) { /* big endian */
      /* calculate begin_i and end_i */
      begin_i = (datatype_len - p.precision - p.offset) / 8;
      if(p.offset % 8 != 0)
         end_i = (datatype_len - p.offset) / 8;
      else
         end_i = (datatype_len - p.offset) / 8 - 1;

      for(k = begin_i; k <= end_i; k++)
         H5Z_nbit_decompress_one_byte(data, data_offset, k, begin_i, end_i,
                                      buffer, j, buf_len, p, datatype_len);
   }
}

static void H5Z_nbit_decompress_one_array(unsigned char *data, size_t data_offset,
           unsigned char *buffer, size_t *j, int *buf_len, const unsigned parms[])
{
   unsigned i, total_size, base_class, base_size, n, begin_index;
   parms_atomic p;

   total_size = parms[parms_index++];
   base_class = parms[parms_index++];

   switch(base_class) {
      case H5Z_NBIT_ATOMIC:
           p.size = parms[parms_index++];
           p.order = parms[parms_index++];
           p.precision = parms[parms_index++];
           p.offset = parms[parms_index++];
           n = total_size/p.size;
           for(i = 0; i < n; i++)
              H5Z_nbit_decompress_one_atomic(data, data_offset + i*p.size,
                                             buffer, j, buf_len, p);
           break;
      case H5Z_NBIT_ARRAY:
           base_size = parms[parms_index]; /* read in advance */
           n = total_size/base_size; /* number of base_type elements inside the array datatype */
           begin_index = parms_index;
           for(i = 0; i < n; i++) {
              H5Z_nbit_decompress_one_array(data, data_offset + i*base_size,
                                            buffer, j, buf_len, parms);
              parms_index = begin_index;
           }
           break;
      case H5Z_NBIT_COMPOUND:
           base_size = parms[parms_index]; /* read in advance */
           n = total_size/base_size; /* number of base_type elements inside the array datatype */
           begin_index = parms_index;
           for(i = 0; i < n; i++) {
              H5Z_nbit_decompress_one_compound(data, data_offset + i*base_size,
                                               buffer, j, buf_len, parms);
              parms_index = begin_index;
           }
           break;
      case H5Z_NBIT_NOOPTYPE:
           parms_index++; /* skip size of no-op type */
           H5Z_nbit_decompress_one_nooptype(data, data_offset, buffer, j, buf_len, total_size);
           break;
   } /* end switch */
}

static void H5Z_nbit_decompress_one_compound(unsigned char *data, size_t data_offset,
              unsigned char *buffer, size_t *j, int *buf_len, const unsigned parms[])
{
   unsigned i, nmembers, member_offset, member_class, size;
   parms_atomic p;

   parms_index++; /* skip total size of compound datatype */
   nmembers = parms[parms_index++];

   for(i = 0; i < nmembers; i++) {
      member_offset = parms[parms_index++];
      member_class = parms[parms_index++];
      switch(member_class) {
         case H5Z_NBIT_ATOMIC:
              p.size = parms[parms_index++];
              p.order = parms[parms_index++];
              p.precision = parms[parms_index++];
              p.offset = parms[parms_index++];
              H5Z_nbit_decompress_one_atomic(data, data_offset + member_offset,
                                             buffer, j, buf_len, p);
              break;
         case H5Z_NBIT_ARRAY:
              H5Z_nbit_decompress_one_array(data, data_offset + member_offset,
                                            buffer, j, buf_len, parms);
              break;
         case H5Z_NBIT_COMPOUND:
              H5Z_nbit_decompress_one_compound(data, data_offset+member_offset,
                                               buffer, j, buf_len, parms);
              break;
         case H5Z_NBIT_NOOPTYPE:
              size = parms[parms_index++];
              H5Z_nbit_decompress_one_nooptype(data, data_offset+member_offset,
                                               buffer, j, buf_len, size);
              break;
      } /* end switch */
   }
}

static void H5Z_nbit_decompress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
                                const unsigned parms[])
{
   /* i: index of data, j: index of buffer,
      buf_len: number of bits to be filled in current byte */
   size_t i, j, size;
   int buf_len;
   parms_atomic p;

   /* may not have to initialize to zeros */
   for(i = 0; i < d_nelmts*parms[4]; i++) data[i] = 0;

   /* initialization before the loop */
   j = 0;
   buf_len = sizeof(unsigned char) * 8;

   switch(parms[3]) {
      case H5Z_NBIT_ATOMIC:
           /* set the index before goto function call */
           p.size = parms[4];
           p.order = parms[5];
           p.precision = parms[6];
           p.offset = parms[7];
           for(i = 0; i < d_nelmts; i++) {
              H5Z_nbit_decompress_one_atomic(data, i*p.size, buffer, &j, &buf_len, p);
           }
           break;
      case H5Z_NBIT_ARRAY:
           size = parms[4];
           parms_index = 4;
           for(i = 0; i < d_nelmts; i++) {
              H5Z_nbit_decompress_one_array(data, i*size, buffer, &j, &buf_len, parms);
              parms_index = 4;
           }
           break;
      case H5Z_NBIT_COMPOUND:
           size = parms[4];
           parms_index = 4;
           for(i = 0; i < d_nelmts; i++) {
              H5Z_nbit_decompress_one_compound(data, i*size, buffer, &j, &buf_len, parms);
              parms_index = 4;
           }
           break;
   } /* end switch */
}

static void H5Z_nbit_compress_one_byte(unsigned char *data, size_t data_offset, int k, int begin_i,
int end_i, unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p, int datatype_len)
{
   int dat_len; /* dat_len is the number of bits to be copied in each data byte */
   unsigned char val; /* value to be copied in each data byte */

   /* initialize value and bits of unsigned char to be copied */
   val = data[data_offset + k];
   if(begin_i != end_i) { /* significant bits occupy >1 unsigned char */
      if(k == begin_i)
         dat_len = 8 - (datatype_len - p.precision - p.offset) % 8;
      else if(k == end_i) {
         dat_len = 8 - p.offset % 8;
         val >>= 8 - dat_len;
      }
      else
         dat_len = 8;
   } else { /* all significant bits in one unsigned char */
      val >>= p.offset % 8;
      dat_len = p.precision;
   }

   if(*buf_len > dat_len) {
      buffer[*j] |= (val & ~(~0 << dat_len)) << (*buf_len - dat_len);
      *buf_len -= dat_len;
   } else {
      buffer[*j] |= (val >> (dat_len - *buf_len)) & ~(~0 << *buf_len);
      dat_len -= *buf_len;
      H5Z_nbit_next_byte(j, buf_len);
      if(dat_len == 0) return;

      buffer[*j] = (val & ~(~0 << dat_len)) << (*buf_len - dat_len);
      *buf_len -= dat_len;
   }
}

static void H5Z_nbit_compress_one_nooptype(unsigned char *data, size_t data_offset,
                     unsigned char *buffer, size_t *j, int *buf_len, unsigned size)
{
   unsigned i;        /* index */
   unsigned dat_len;  /* dat_len is the number of bits to be copied in each data byte */
   unsigned char val; /* value to be copied in each data byte */

   for(i = 0; i < size; i++) {
      /* initialize value and bits of unsigned char to be copied */
      val = data[data_offset + i];
      dat_len = sizeof(unsigned char) * 8;

      buffer[*j] |= (val >> (dat_len - *buf_len)) & ~(~0 << *buf_len);
      dat_len -= *buf_len;
      H5Z_nbit_next_byte(j, buf_len);
      if(dat_len == 0) continue;

      buffer[*j] = (val & ~(~0 << dat_len)) << (*buf_len - dat_len);
      *buf_len -= dat_len;
   }
}

static void H5Z_nbit_compress_one_atomic(unsigned char *data, size_t data_offset,
                  unsigned char *buffer, size_t *j, int *buf_len, parms_atomic p)
{
   /* begin_i: the index of byte having first significant bit
      end_i: the index of byte having last significant bit */
   int k, begin_i, end_i, datatype_len;

   datatype_len = p.size * 8;

   if(p.order == H5Z_NBIT_ORDER_LE) { /* little endian */
      /* calculate begin_i and end_i */
      if((p.precision + p.offset) % 8 != 0)
         begin_i = (p.precision + p.offset) / 8;
      else
         begin_i = (p.precision + p.offset) / 8 - 1;
      end_i = p.offset / 8;

      for(k = begin_i; k >= end_i; k--)
         H5Z_nbit_compress_one_byte(data, data_offset, k, begin_i, end_i,
                                    buffer, j, buf_len, p, datatype_len);
   }

   if(p.order == H5Z_NBIT_ORDER_BE) { /* big endian */
      /* calculate begin_i and end_i */
      begin_i = (datatype_len - p.precision - p.offset) / 8;
      if(p.offset % 8 != 0)
         end_i = (datatype_len - p.offset) / 8;
      else
         end_i = (datatype_len - p.offset) / 8 - 1;

      for(k = begin_i; k <= end_i; k++)
         H5Z_nbit_compress_one_byte(data, data_offset, k, begin_i, end_i,
                                    buffer, j, buf_len, p, datatype_len);
   }
}

static void H5Z_nbit_compress_one_array(unsigned char *data, size_t data_offset, unsigned char *buffer,
                                 size_t *j, int *buf_len, const unsigned parms[])
{
   unsigned i, total_size, base_class, base_size, n, begin_index;
   parms_atomic p;

   total_size = parms[parms_index++];
   base_class = parms[parms_index++];

   switch(base_class) {
      case H5Z_NBIT_ATOMIC:
           p.size = parms[parms_index++];
           p.order = parms[parms_index++];
           p.precision = parms[parms_index++];
           p.offset = parms[parms_index++];
           n = total_size/p.size;
           for(i = 0; i < n; i++)
              H5Z_nbit_compress_one_atomic(data, data_offset + i*p.size,
                                           buffer, j, buf_len, p);
           break;
      case H5Z_NBIT_ARRAY:
           base_size = parms[parms_index]; /* read in advance */
           n = total_size/base_size; /* number of base_type elements inside the array datatype */
           begin_index = parms_index;
           for(i = 0; i < n; i++) {
              H5Z_nbit_compress_one_array(data, data_offset + i*base_size,
                                          buffer, j, buf_len, parms);
              parms_index = begin_index;
           }
           break;
      case H5Z_NBIT_COMPOUND:
           base_size = parms[parms_index]; /* read in advance */
           n = total_size/base_size; /* number of base_type elements inside the array datatype */
           begin_index = parms_index;
           for(i = 0; i < n; i++) {
              H5Z_nbit_compress_one_compound(data, data_offset + i*base_size,
                                             buffer, j, buf_len, parms);
              parms_index = begin_index;
           }
           break;
      case H5Z_NBIT_NOOPTYPE:
           parms_index++; /* skip size of no-op type */
           H5Z_nbit_compress_one_nooptype(data, data_offset, buffer, j, buf_len, total_size);
           break;
   } /* end switch */
}

static void H5Z_nbit_compress_one_compound(unsigned char *data, size_t data_offset,
            unsigned char *buffer, size_t *j, int *buf_len, const unsigned parms[])
{
   unsigned i, nmembers, member_offset, member_class, size;
   parms_atomic p;

   parms_index++; /* skip size of compound datatype */
   nmembers = parms[parms_index++];

   for(i = 0; i < nmembers; i++) {
      member_offset = parms[parms_index++];
      member_class = parms[parms_index++];

      switch(member_class) {
         case H5Z_NBIT_ATOMIC:
              p.size = parms[parms_index++];
              p.order = parms[parms_index++];
              p.precision = parms[parms_index++];
              p.offset = parms[parms_index++];
              H5Z_nbit_compress_one_atomic(data, data_offset + member_offset,
                                           buffer, j, buf_len, p);
              break;
         case H5Z_NBIT_ARRAY:
              H5Z_nbit_compress_one_array(data, data_offset + member_offset,
                                          buffer, j, buf_len, parms);
              break;
         case H5Z_NBIT_COMPOUND:
              H5Z_nbit_compress_one_compound(data, data_offset+member_offset,
                                             buffer, j, buf_len, parms);
              break;
         case H5Z_NBIT_NOOPTYPE:
              size = parms[parms_index++];
              H5Z_nbit_compress_one_nooptype(data, data_offset+member_offset,
                                             buffer, j, buf_len, size);
              break;
      } /* end switch */
   }
}

static void H5Z_nbit_compress(unsigned char *data, unsigned d_nelmts, unsigned char *buffer,
                              size_t *buffer_size, const unsigned parms[])
{
   /* i: index of data, j: index of buffer,
      buf_len: number of bits to be filled in current byte */
   size_t i, j, size;
   int buf_len;
   parms_atomic p;

   /* must initialize buffer to be zeros */
   for(j = 0; j < *buffer_size; j++) buffer[j] = 0;

   /* initialization before the loop */
   j = 0;
   buf_len = sizeof(unsigned char) * 8;

   switch(parms[3]) {
      case H5Z_NBIT_ATOMIC:
           /* set the index before goto function call */
           p.size = parms[4];
           p.order = parms[5];
           p.precision = parms[6];
           p.offset = parms[7];

           for(i = 0; i < d_nelmts; i++) {
              H5Z_nbit_compress_one_atomic(data, i*p.size, buffer, &j, &buf_len, p);
           }
           break;
      case H5Z_NBIT_ARRAY:
           size = parms[4];
           parms_index = 4;
           for(i = 0; i < d_nelmts; i++) {
              H5Z_nbit_compress_one_array(data, i*size, buffer, &j, &buf_len, parms);
              parms_index = 4;
           }
           break;
      case H5Z_NBIT_COMPOUND:
           size = parms[4];
           parms_index = 4;
           for(i = 0; i < d_nelmts; i++) {
              H5Z_nbit_compress_one_compound(data, i*size, buffer, &j, &buf_len, parms);
              parms_index = 4;
           }
           break;
   } /* end switch */

   *buffer_size = j + 1; /* sometimes is catually j, but to be safe */
}
#endif /* H5_HAVE_FILTER_NZIP */