int artio_particle_read_root_cell_begin(artio_fileset *handle, int64_t sfc,
		int * num_particles_per_species) {
	int i;
	int ret;
	artio_particle_file *phandle;

	if ( handle == NULL ) {
		return ARTIO_ERR_INVALID_HANDLE;
	}

	if (handle->open_mode != ARTIO_FILESET_READ ||
			!(handle->open_type & ARTIO_OPEN_PARTICLES) ||
			handle->particle == NULL ) {
		return ARTIO_ERR_INVALID_FILESET_MODE;
	}

	phandle = handle->particle;

	ret = artio_particle_seek_to_sfc(handle, sfc);
	if ( ret != ARTIO_SUCCESS ) return ret;

	ret = artio_file_fread(phandle->ffh[phandle->cur_file], num_particles_per_species,
			phandle->num_species, ARTIO_TYPE_INT);
	if ( ret != ARTIO_SUCCESS ) return ret;

	for (i = 0; i < phandle->num_species; i++) {
		phandle->num_particles_per_species[i] = num_particles_per_species[i];
	}

	phandle->cur_sfc = sfc;
	phandle->cur_species = -1;
	phandle->cur_particle = 0;
	return ARTIO_SUCCESS;
}
/* Description  */
int artio_particle_read_particle(artio_fileset *handle, int64_t * pid, int *subspecies,
		double * primary_variables, float * secondary_variables) {
	int ret;
	artio_particle_file *phandle;

	if ( handle == NULL ) {
		return ARTIO_ERR_INVALID_HANDLE;
	}

	if (handle->open_mode != ARTIO_FILESET_READ ||
			!(handle->open_type & ARTIO_OPEN_PARTICLES) ||
			handle->particle == NULL ) {
		return ARTIO_ERR_INVALID_FILESET_MODE;
	}

	phandle = handle->particle;

	if (phandle->cur_species == -1 ||
			phandle->cur_particle >= phandle->num_particles_per_species[phandle->cur_species]) {
		return ARTIO_ERR_INVALID_STATE;
	}

	ret = artio_file_fread(phandle->ffh[phandle->cur_file], pid, 1, ARTIO_TYPE_LONG);
	if ( ret != ARTIO_SUCCESS ) return ret;

	ret = artio_file_fread(phandle->ffh[phandle->cur_file], subspecies, 1, ARTIO_TYPE_INT);
	if ( ret != ARTIO_SUCCESS ) return ret;

	ret = artio_file_fread(phandle->ffh[phandle->cur_file], primary_variables,
			phandle->num_primary_variables[phandle->cur_species],
			ARTIO_TYPE_DOUBLE);
	if ( ret != ARTIO_SUCCESS ) return ret;

	ret = artio_file_fread(phandle->ffh[phandle->cur_file], secondary_variables,
			phandle->num_secondary_variables[phandle->cur_species],
			ARTIO_TYPE_FLOAT);
	if ( ret != ARTIO_SUCCESS ) return ret;

	phandle->cur_particle++;
	return ARTIO_SUCCESS;
}
int artio_particle_cache_sfc_range(artio_fileset *handle,
		int64_t start, int64_t end) {
	int i;
	int ret;
	int first_file, last_file;
	int64_t min, count, cur;
	artio_particle_file *phandle;

	if ( handle == NULL ) {
		return ARTIO_ERR_INVALID_HANDLE;
	}

	if (handle->open_mode != ARTIO_FILESET_READ ||
			!(handle->open_type & ARTIO_OPEN_PARTICLES) ||
			handle->particle == NULL ) {
		return ARTIO_ERR_INVALID_FILESET_MODE;
	}

	phandle = handle->particle;

	if ( start > end || start < handle->proc_sfc_begin ||
			end > handle->proc_sfc_end) {
		return ARTIO_ERR_INVALID_SFC_RANGE;
	}

	/* check if we've already cached the range */
	if ( start >= phandle->cache_sfc_begin &&
			end <= phandle->cache_sfc_end ) {
		return ARTIO_SUCCESS;
	}

	artio_grid_clear_sfc_cache(handle);

	first_file = artio_find_file(phandle->file_sfc_index,
			phandle->num_particle_files, start);
	last_file = artio_find_file(phandle->file_sfc_index,
			phandle->num_particle_files, end);

	phandle->cache_sfc_begin = start;
	phandle->cache_sfc_end = end;
	phandle->sfc_offset_table = (int64_t *)malloc(sizeof(int64_t) * (size_t)(end - start + 1));
	if ( phandle->sfc_offset_table == NULL ) {
		return ARTIO_ERR_MEMORY_ALLOCATION;
	}

	if ( phandle->cur_file != -1 ) {
		artio_file_detach_buffer( phandle->ffh[phandle->cur_file]);
		phandle->cur_file = -1;
	}

	cur = 0;
	for (i = first_file; i <= last_file; i++) {
		min = MAX( 0, start - phandle->file_sfc_index[i] );
		count = MIN( phandle->file_sfc_index[i+1], end+1 )
				- MAX( start, phandle->file_sfc_index[i] );

		artio_file_attach_buffer( phandle->ffh[i],
				phandle->buffer, phandle->buffer_size );

		ret = artio_file_fseek(phandle->ffh[i],
				sizeof(int64_t) * min,
				ARTIO_SEEK_SET);
		if ( ret != ARTIO_SUCCESS ) return ret;

		ret = artio_file_fread(phandle->ffh[i],
				&phandle->sfc_offset_table[cur],
				count, ARTIO_TYPE_LONG);
		if ( ret != ARTIO_SUCCESS ) return ret;

		artio_file_detach_buffer( phandle->ffh[i] );
		cur += count;
	}

	return ARTIO_SUCCESS;
}
int artio_parameter_read(artio_fh *handle, parameter_list *parameters) {
	parameter * item;
	int i;
	int length, re;
	int t_len;
	int32_t endian_tag;

    /* endian check */
	re = artio_file_fread(handle, &endian_tag, 1, ARTIO_TYPE_INT);
	if ( re != ARTIO_SUCCESS ) {
		return ARTIO_ERR_PARAM_CORRUPTED;
	}

	if ( endian_tag != ARTIO_ENDIAN_MAGIC ) {
		artio_int_swap( &endian_tag, 1 );
		if ( endian_tag == ARTIO_ENDIAN_MAGIC ) {
			artio_file_set_endian_swap_tag(handle);
		} else {
			return ARTIO_ERR_PARAM_CORRUPTED_MAGIC;
		}
	}

	re = artio_file_fread(handle, &length, 1, ARTIO_TYPE_INT);
	if ( re != ARTIO_SUCCESS ) {
		return ARTIO_ERR_PARAM_CORRUPTED;
	}

	for ( i = 0; i < length; i++ ) {
		item = (parameter *)malloc(sizeof(parameter));
		if ( item == NULL ) {
			return ARTIO_ERR_MEMORY_ALLOCATION;
		}

		artio_file_fread(handle, &item->key_length, 1, ARTIO_TYPE_INT);
		artio_file_fread(handle, item->key, item->key_length, ARTIO_TYPE_CHAR);
		item->key[item->key_length] = 0;

		artio_file_fread(handle, &item->val_length, 1, ARTIO_TYPE_INT);
		artio_file_fread(handle, &item->type, 1, ARTIO_TYPE_INT);

		t_len = artio_type_size(item->type);
		item->value = (char *)malloc(item->val_length * t_len);

		re = artio_file_fread(handle, item->value, 
				item->val_length, item->type);
		if ( re != ARTIO_SUCCESS ) {
			return ARTIO_ERR_PARAM_CORRUPTED;
		}

		item->next = NULL;
		if (NULL == parameters->tail) {
			parameters->tail = item;
			parameters->head = item;
		} else {
			parameters->tail->next = item;
			parameters->tail = item;
		}
	}

	return ARTIO_SUCCESS;
}