static int init(grib_iterator* i,grib_handle* h,grib_arguments* args)
{
  grib_iterator_latlon* self = (grib_iterator_latlon*)i;
  int ret = GRIB_SUCCESS;
  double jdir;
  double laf;
  long jScansPositively;

  long lai;

  const char* latofirst   = grib_arguments_get_name(h,args,self->carg++);
  const char* jdirec      = grib_arguments_get_name(h,args,self->carg++);
  const char* s_jScansPositively   = grib_arguments_get_name(h,args,self->carg++);

  if((ret = grib_get_double_internal(h,latofirst,     &laf))) return ret;
  if((ret = grib_get_double_internal(h,jdirec,        &jdir))) return ret;
  if((ret = grib_get_long_internal(h,s_jScansPositively,&jScansPositively)))
      return ret;

  if (jScansPositively) jdir=-jdir;

  for( lai = 0; lai <  self->nam; lai++ )  {
    self->las[lai] = laf;
    laf -= jdir ;
  }

  i->e = -1;
  return ret;
}
static int    unpack_double   (grib_accessor* a, double* val, size_t *len)
{
	grib_accessor_g1_increment* self = (grib_accessor_g1_increment*)a;
	int ret = 0;

	long directionIncrementGiven=0;
	long directionIncrement;
	double first = 0;
	double last = 0;
	long numberOfPoints = 0;

	if(*len < 1)
		ret = GRIB_ARRAY_TOO_SMALL;

	if((ret = grib_get_long_internal(a->parent->h, self->directionIncrementGiven,&directionIncrementGiven)) 
					!= GRIB_SUCCESS)
		return ret;
	
	if((ret = grib_get_long_internal(a->parent->h, self->directionIncrement,&directionIncrement)) 
				!= GRIB_SUCCESS)
		return ret;
	
	if((ret = grib_get_double_internal(a->parent->h, self->first,&first)) != GRIB_SUCCESS)
		return ret;
	
	if((ret = grib_get_double_internal(a->parent->h, self->last,&last)) != GRIB_SUCCESS)
		return ret;

	if((ret = grib_get_long_internal(a->parent->h, self->numberOfPoints,&numberOfPoints))
       != GRIB_SUCCESS)
		return ret;
	
	if (!directionIncrementGiven || directionIncrement == GRIB_MISSING_LONG) {
		*val = fabs(last-first)/(double)(numberOfPoints-1);
	} else {
		*val = (double)directionIncrement/1000.0;
	} 
	
#if 0
	printf("unpack -- %s=%ld %s=%ld %s=%f %s=%f %s=%ld %s=%f\n",
						self->directionIncrementGiven,directionIncrementGiven,
						self->directionIncrement,directionIncrement,
						self->last,last,
						self->first,first,
						self->numberOfPoints,numberOfPoints,
						a->name,*val);
#endif
	if (ret == GRIB_SUCCESS) *len = 1;
		
	return ret;
} 
static int init(grib_iterator* i,grib_handle* h,grib_arguments* args)
{
  grib_iterator_regular* self = (grib_iterator_regular*)i;
  int ret = GRIB_SUCCESS;

  long nap;
  long nam;
  double idir;

  double lof,lol;
  long loi;
  
  const char* longoffirst = grib_arguments_get_name(h,args,self->carg++);
  const char* idirec      = grib_arguments_get_name(h,args,self->carg++);
  const char* nalpar      = grib_arguments_get_name(h,args,self->carg++);
  const char* nalmer      = grib_arguments_get_name(h,args,self->carg++);
  const char* iScansNegatively  = grib_arguments_get_name(h,args,self->carg++);

  
  if((ret = grib_get_double_internal(h,longoffirst,   &lof))) return ret;
  if((ret = grib_get_double_internal(h,"longitudeOfLastGridPointInDegrees",   &lol))) return ret;

  if((ret = grib_get_double_internal(h,idirec,        &idir))) return ret;

  if((ret = grib_get_long_internal(h,nalpar,          &nap))) return ret;
  if((ret = grib_get_long_internal(h,nalmer,          &nam))) return ret;
  if((ret = grib_get_long_internal(h,iScansNegatively,&self->iScansNegatively)))
     return ret;

  idir=fabs(lof-lol)/(nap-1);
  if (self->iScansNegatively) {
    idir=-idir;
  } else {
	if (lof+(nap-2)*idir>360) lof-=360;
    else if (lof+nap*idir>360) idir=360.0/(float)nap;
  }

  self->nap = nap;
  self->nam = nam;

  self->las = grib_context_malloc(h->context,nam*sizeof(double));
  self->los = grib_context_malloc(h->context,nap*sizeof(double));

  for( loi = 0; loi < nap; loi++ )  {
    self->los[loi] = lof;
    lof += idir ;
  }

  return ret;
}
static int  unpack_double(grib_accessor* a, double* val, size_t *len)
{
    grib_accessor_data_dummy_field* self =  (grib_accessor_data_dummy_field*)a;
    size_t i = 0;
    size_t n_vals = 0;
    long numberOfPoints;
    double missing_value = 0;
    int err = 0;

    if((err = grib_get_long_internal(a->parent->h,self->numberOfPoints, &numberOfPoints))
            != GRIB_SUCCESS)  return err;
    n_vals =numberOfPoints;

    if((err = grib_get_double_internal(a->parent->h,self->missing_value, &missing_value))
            != GRIB_SUCCESS)		return err;

    if(*len < n_vals) {
        *len = n_vals;
        return GRIB_ARRAY_TOO_SMALL;
    }

    for(i=0; i < n_vals; i++)
        val[i] = missing_value;

    if(grib_find_accessor(a->parent->h,self->bitmap)) {
        if((err = grib_set_double_array_internal(a->parent->h,self->bitmap,val,n_vals)) != GRIB_SUCCESS)
            return err;
    }

    *len = (long) n_vals;
    return err;
}
static int  unpack_double(grib_accessor* a, double* val, size_t *len)
{
	grib_accessor_data_constant_field* self =  (grib_accessor_data_constant_field*)a;
	size_t i = 0;
	long n_vals = 0;
	int err=0;
	double reference_value = 0;

	err=grib_value_count(a,&n_vals);
	if (err) return err;

	if(*len < n_vals){
		*len = n_vals;
		return GRIB_ARRAY_TOO_SMALL;
	}

	if((err = grib_get_double_internal(a->parent->h,self->reference_value, &reference_value)) != GRIB_SUCCESS)
		return err;

	for(i=0;i < n_vals;i++)
		val[i] = reference_value;

	*len = (long) n_vals;
	return err;
}
static int  unpack_double(grib_accessor* a, double* val, size_t *len)
{
  grib_accessor_data_g2shsimple_packing* self =  (grib_accessor_data_g2shsimple_packing*)a;
  int err =  GRIB_SUCCESS;

  size_t n_vals = 0;

  if((err = grib_get_size(grib_handle_of_accessor(a),self->coded_values,&n_vals)) != GRIB_SUCCESS)
    return err;

  self->dirty=0;

    /* n_vals = coded_n_vals+1; */

  if(*len < n_vals)
  {
    *len = n_vals;
    return GRIB_ARRAY_TOO_SMALL;
  }

  if((err = grib_get_double_internal(grib_handle_of_accessor(a),self->real_part,val)) != GRIB_SUCCESS)
    return err;

  val++;

  if((err = grib_get_double_array_internal(grib_handle_of_accessor(a),self->coded_values,val,&n_vals)) != GRIB_SUCCESS)
    return err;

  *len =  n_vals;

  return err;
}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
  grib_accessor_data_g2shsimple_packing* self =  (grib_accessor_data_g2shsimple_packing*)a;
  int err =  GRIB_SUCCESS;

  size_t coded_n_vals = *len-1;
  size_t n_vals = *len;

  if (*len ==0) return GRIB_NO_VALUES;

  self->dirty=1;

  if((err = grib_set_double_internal(grib_handle_of_accessor(a),self->real_part,*val)) != GRIB_SUCCESS)
    return err;
  {
    /* Make sure we can decode it again */
    double ref = 1e-100;
    grib_get_double_internal(grib_handle_of_accessor(a),self->real_part,&ref);
    Assert(ref == *val);
  }

  val++;

  if((err = grib_set_double_array_internal(grib_handle_of_accessor(a),self->coded_values,val,coded_n_vals)) != GRIB_SUCCESS)
    return err;

  *len =  n_vals;

    if((err = grib_set_long_internal(grib_handle_of_accessor(a),self->numberOfValues,(long)n_vals)) != GRIB_SUCCESS)
    return err;

  return err;
}
static int  unpack_double(grib_accessor* a, double* val, size_t *len)
{
    grib_accessor_data_g1shsimple_packing* self =  (grib_accessor_data_g1shsimple_packing*)a;
    int err =  GRIB_SUCCESS;

    size_t coded_n_vals = 0;
    size_t n_vals = 0;

    if((err = grib_get_size(a->parent->h,self->coded_values,&coded_n_vals)) != GRIB_SUCCESS)
        return err;

    n_vals = coded_n_vals + 1;

    if(*len < n_vals)
    {
        *len = n_vals;
        return GRIB_ARRAY_TOO_SMALL;
    }

    if((err = grib_get_double_internal(a->parent->h,self->real_part,val)) != GRIB_SUCCESS)
        return err;

    val++;

    if((err = grib_get_double_array_internal(a->parent->h,self->coded_values,val,&coded_n_vals)) != GRIB_SUCCESS)
        return err;

    grib_context_log(a->parent->h->context, GRIB_LOG_DEBUG,
            "grib_accessor_data_g1shsimple_packing_bitmap : unpack_double : creating %s, %d values",
            a->name, n_vals);

    *len =  n_vals;

    return err;
}
static int    unpack_double(grib_accessor* a, double* val, size_t *len)
{
    grib_accessor_round* self = (grib_accessor_round*)a;


    int ret = GRIB_SUCCESS;

    size_t replen = 0;
    double rounding_precision = 0;
    double rounded = 0;
    double toround = 0;

    const char* oval = NULL;
    oval     = grib_arguments_get_name(a->parent->h,self->arg,0);


    if( (ret = grib_get_double_internal(a->parent->h, oval, &toround)) != 0)
        return ret;

    rounding_precision = grib_arguments_get_long(a->parent->h,self->arg,1);

    rounded = floor(rounding_precision * toround + 0.5) / rounding_precision;



    *len = replen;

    *val = rounded;

    return ret;
}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
    grib_accessor_data_apply_bitmap* self =  (grib_accessor_data_apply_bitmap*)a;
    int err = 0;
    size_t bmaplen = *len;
    long coded_n_vals = 0;
    double* coded_vals = NULL;
    long i = 0;
    long j = 0;
    double missing_value = 0;

    if (*len ==0) return GRIB_NO_VALUES;

    if(!grib_find_accessor(a->parent->h,self->bitmap)){
        err = grib_set_double_array_internal(a->parent->h,self->coded_values,val,*len);
        /*printf("SETTING TOTAL number_of_data_points %s %ld\n",self->number_of_data_points,*len);*/
        if(self->number_of_data_points)
            grib_set_long_internal(a->parent->h,self->number_of_data_points,*len);
        return err;
    }

    if((err = grib_get_double_internal(a->parent->h,self->missing_value,&missing_value)) != GRIB_SUCCESS)
        return err;

    if((err = grib_set_double_array_internal(a->parent->h,self->bitmap,val,bmaplen)) != GRIB_SUCCESS)
        return err;

    coded_n_vals = *len;

    if(coded_n_vals <  1){
        err = grib_set_double_array_internal(a->parent->h,self->coded_values,NULL,0);
        return err;
    }

    coded_vals = (double*)grib_context_malloc_clear(a->parent->h->context,coded_n_vals*sizeof(double));
    if(!coded_vals) return GRIB_OUT_OF_MEMORY;

    for(i=0; i<*len ; i++)
    {
        if(val[i] != missing_value) {
            coded_vals[j++] = val[i];
        }
    }

    err = grib_set_double_array_internal(a->parent->h,self->coded_values,coded_vals,j);
    if (j==0) {
        if (self->number_of_values)
            err=grib_set_long_internal(a->parent->h,self->number_of_values,0);
        if (self->binary_scale_factor)
            err=grib_set_long_internal(a->parent->h,self->binary_scale_factor,0);
    }

    grib_context_free(a->parent->h->context,coded_vals);

    return err;
}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
    double* values=NULL;
    size_t size=0;
    double missingValue=0;
    long missingValuesPresent = 0;
    int ret=0,i=0;
    grib_accessor_offset_values* self= (grib_accessor_offset_values*)a;
    grib_context* c=a->context;
    grib_handle* h=grib_handle_of_accessor(a);

    if (*val==0) return GRIB_SUCCESS;

    if((ret = grib_get_double_internal(h,self->missingValue,&missingValue)) != GRIB_SUCCESS) {
        return ret;
    }
    if((ret=grib_get_long_internal(h,"missingValuesPresent",&missingValuesPresent)) != GRIB_SUCCESS) {
        return ret;
    }

    if ( (ret=grib_get_size(h,self->values,&size)) != GRIB_SUCCESS) return ret;

    values=(double*)grib_context_malloc(c,size*sizeof(double));
    if (!values) return GRIB_OUT_OF_MEMORY;

    if((ret = grib_get_double_array_internal(h,self->values,values,&size)) != GRIB_SUCCESS) {
        grib_context_free(c,values);
        return ret;
    }

    for (i=0;i<size;i++) {
        if (missingValuesPresent) {
            if (values[i]!=missingValue) values[i]+=*val;
        } else {
            values[i]+=*val;
        }
    }

    if((ret = grib_set_double_array_internal(h, self->values,values,size)) != GRIB_SUCCESS) return ret;

    grib_context_free(c,values);

    return GRIB_SUCCESS;
}
static int pack_double(grib_accessor* a, const double* val,size_t *len){
  grib_accessor_g1bitmap* self = (grib_accessor_g1bitmap*)a;

  size_t tlen;

  unsigned char* buf = NULL;
  long i;
  int err = 0;
  long pos = 0;
  long bmaplen = 0;
  const int bit_padding = 16;
  double miss_values = 0;
  tlen = ((*len+bit_padding-1)/bit_padding*bit_padding)/8;

  if((err = grib_get_double_internal(a->parent->h, self->missing_value, &miss_values))
      != GRIB_SUCCESS)
    return err;

  buf = grib_context_malloc_clear(a->parent->h->context,tlen);
  if(!buf) return GRIB_OUT_OF_MEMORY;
  pos=0;
  for(i=0;i<*len;i++)
  {
    if (val[i] == miss_values)
      pos++;
    else{
      bmaplen++;
      grib_set_bit_on(buf, &pos);
    }
  }

  if((err = grib_set_long_internal(a->parent->h, self->unusedBits,tlen*8 - *len ))
      != GRIB_SUCCESS)
    return err;

  grib_buffer_replace(a, buf, tlen,1,1);

  grib_context_free(a->parent->h->context,buf);

  return GRIB_SUCCESS;
}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
  double* values=NULL;
  double missingValue=0;
  size_t size=0;
  int ret=0,i=0;
  grib_accessor_scale_values* self= (grib_accessor_scale_values*)a;
  grib_context* c=a->parent->h->context;
  grib_handle* h=a->parent->h;

  if (*val==1) return GRIB_SUCCESS;

  if((ret = grib_get_double_internal(h,self->missingValue,&missingValue))
       != GRIB_SUCCESS) {
        return ret;
  }

  if ( (ret=grib_get_size(h,self->values,&size)) != GRIB_SUCCESS) return ret;

  values=(double*)grib_context_malloc(c,size*sizeof(double));
  if (!values) return GRIB_OUT_OF_MEMORY;

  if((ret = grib_get_double_array_internal(h,self->values,values,&size))
       != GRIB_SUCCESS) {
        grib_context_free(c,values);
        return ret;
  }

  for (i=0;i<size;i++)
    if (values[i]!=missingValue) values[i]*=*val;

  if((ret = grib_set_double_array_internal(h, self->values,values,size))
      != GRIB_SUCCESS) return ret;

  grib_context_free(c,values);

  return GRIB_SUCCESS;
}
static int unpack_double_element(grib_accessor* a, size_t idx,double* val)
{
    grib_accessor_data_apply_boustrophedonic_bitmap* self =  (grib_accessor_data_apply_boustrophedonic_bitmap*)a;
    int err = 0,i=0;
    size_t cidx=0;
    double missing_value = 0;
    double* bvals=NULL;
    size_t n_vals = 0;
    long nn=0;

    err=grib_value_count(a,&nn);
    n_vals=nn;
    if (err) return err;

    if(!grib_find_accessor(a->parent->h,self->bitmap))
        return grib_get_double_element_internal(a->parent->h,self->coded_values,idx,val);

    if((err = grib_get_double_internal(a->parent->h,self->missing_value,&missing_value)) != GRIB_SUCCESS)
        return err;

    if((err = grib_get_double_element_internal(a->parent->h,self->bitmap,idx,val)) != GRIB_SUCCESS)
        return err;

    if (*val == 0) {*val=missing_value;return GRIB_SUCCESS;}

    bvals = (double*)grib_context_malloc(a->parent->h->context,n_vals*sizeof(double));
    if(bvals == NULL) return GRIB_OUT_OF_MEMORY;

    if((err = grib_get_double_array_internal(a->parent->h,self->bitmap,bvals,&n_vals)) != GRIB_SUCCESS)
        return err;

    cidx=0;
    for (i=0;i<idx;i++) {cidx+=bvals[i];}

    grib_context_free(a->parent->h->context,bvals);

    return grib_get_double_element_internal(a->parent->h,self->coded_values,cidx,val);
}
static int    unpack_double   (grib_accessor* a, double* val, size_t *len) {
    grib_accessor_simple_packing_error* self = (grib_accessor_simple_packing_error*)a;
    int ret = 0;
    long binaryScaleFactor=0;
    long bitsPerValue=0;
    long decimalScaleFactor=0;
    double referenceValue=0;

    if((ret = grib_get_long_internal(a->parent->h,
                                     self->binaryScaleFactor,&binaryScaleFactor)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,
                                     self->bitsPerValue,&bitsPerValue)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,
                                     self->decimalScaleFactor,&decimalScaleFactor)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_double_internal(a->parent->h,
                                       self->referenceValue,&referenceValue)) != GRIB_SUCCESS)
        return ret;

    if (!strcmp(self->floatType,"ibm"))
        *val=grib_ibmfloat_error(referenceValue);
    else if  (!strcmp(self->floatType,"ieee"))
        *val=grib_ieeefloat_error(referenceValue);
    else Assert(1==0);

    if (bitsPerValue!=0)
        *val=(*val+grib_power(binaryScaleFactor,2))*grib_power(-decimalScaleFactor,10)*0.5;

    if (ret == GRIB_SUCCESS) *len = 1;

    return ret;
}
static int  unpack_double(grib_accessor* a, double* val, size_t *len)
{
  grib_accessor_data_sh_unpacked* self =  (grib_accessor_data_sh_unpacked*)a;

  size_t i = 0;
  int ret = GRIB_SUCCESS;
  long   hcount = 0;
  long   lcount = 0;
  long   hpos = 0;
  long   lup = 0;
  long   mmax = 0;
  long   n_vals = 0;
  double *scals  = NULL;
  /* double *pscals=NULL; */
  double dummy=0;

  double s = 0;
  double d = 0;
  double laplacianOperator = 0;
  unsigned char* buf = NULL;
  unsigned char* hres = NULL;
  unsigned char* lres = NULL;
  unsigned long packed_offset;
  long   lpos = 0;

  long   maxv = 0;
  long   GRIBEX_sh_bug_present =0;
  long ieee_floats  = 0;

  long   offsetdata           = 0;
  long   bits_per_value          = 0;
  double reference_value      = 0;
  long   binary_scale_factor         = 0;
  long   decimal_scale_factor = 0;


  long   sub_j= 0;
  long   sub_k= 0;
  long   sub_m= 0;
  long   pen_j= 0;
  long   pen_k= 0;
  long   pen_m= 0;

  double operat= 0;
  int err=0;

  decode_float_proc decode_float = NULL;

  n_vals = 0;
  err=grib_value_count(a,&n_vals);
  if (err) return err;

  if(*len < n_vals){
    *len = n_vals;
    return GRIB_ARRAY_TOO_SMALL;
  }

  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->offsetdata,&offsetdata))
      != GRIB_SUCCESS)   return ret;

  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->GRIBEX_sh_bug_present,&GRIBEX_sh_bug_present))
      != GRIB_SUCCESS)
    return ret;

  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->ieee_floats,&ieee_floats)) != GRIB_SUCCESS)
    return ret;

  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->sub_j,&sub_j)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->sub_k,&sub_k)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->sub_m,&sub_m)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->pen_j,&pen_j)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->pen_k,&pen_k)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(grib_handle_of_accessor(a),self->pen_m,&pen_m)) != GRIB_SUCCESS)
    return ret;

  self->dirty=0;

  switch (ieee_floats) {
    case 0:
      decode_float=grib_long_to_ibm;
      break;
    case 1:
      decode_float=grib_long_to_ieee;
      break;
    case 2:
      decode_float=grib_long_to_ieee64;
      break;
    default:
      return GRIB_NOT_IMPLEMENTED;
  }
  
  Assert (sub_j == sub_k);
  Assert (sub_j == sub_m);
  Assert (pen_j == pen_k);
  Assert (pen_j == pen_m);

  buf = (unsigned char*)grib_handle_of_accessor(a)->buffer->data;

  maxv = pen_j+1;

  buf  += offsetdata;
  hres = buf;
  lres = buf;

  packed_offset = offsetdata +  4*(sub_k+1)*(sub_k+2);

  lpos = 8*(packed_offset-offsetdata);

  s = grib_power(binary_scale_factor,2);
  d = grib_power(-decimal_scale_factor,10) ;

  scals   = (double*)grib_context_malloc(a->context,maxv*sizeof(double));
  Assert(scals);
  if((ret = grib_get_double_internal(grib_handle_of_accessor(a),self->laplacianOperator,&laplacianOperator))
      != GRIB_SUCCESS)
    return ret;

  scals[0] = 0;
  for(i=1;i<maxv;i++){
    operat = pow(i*(i+1),laplacianOperator);
    if(operat !=  0)
      scals[i] = (1.0/operat);
    else{
      scals[i] = 0;
    }
  }


  i=0;

  while(maxv>0)
  {
    lup=mmax;
    if(sub_k>=0)
    {
      for(hcount=0;hcount<sub_k+1;hcount++)
      {
        val[i++] =  decode_float(grib_decode_unsigned_long(hres,&hpos,32))*d;
        val[i++] =  decode_float(grib_decode_unsigned_long(hres,&hpos,32))*d;

        if (GRIBEX_sh_bug_present && hcount==sub_k){
          /*  bug in ecmwf data, last row (K+1)is scaled but should not */
          val[i-2] *= scals[lup];
          val[i-1] *= scals[lup];
        }
        lup++;
      }
      sub_k--;
    }

    /* pscals=scals+lup; */
    for(lcount=hcount; lcount < maxv ; lcount++)
    {
      dummy =  (double) ((grib_decode_unsigned_long(lres, &lpos,
                   bits_per_value)*s)+reference_value);
      dummy =  (double) ((grib_decode_unsigned_long(lres, &lpos,
                   bits_per_value)*s)+reference_value);
      lup++;
    }

    maxv--;
    hcount=0;
    mmax++;
  }

  Assert(*len >= i);
  *len = n_vals;

  if(d != 1) {
    for(i=0;i<*len;i++)
      val[i++] *= d;
  }

  (void)dummy; /* suppress gcc warning */
  grib_context_free(a->context,scals);

  return ret;

}
static int  unpack_double(grib_accessor* a, double* val, size_t *len)
{
    grib_accessor_data_complex_packing* self =  (grib_accessor_data_complex_packing*)a;

    size_t i = 0;
    int ret = GRIB_SUCCESS;
    long   hcount = 0;
    long   lcount = 0;
    long   hpos = 0;
    long   lup = 0;
    long   mmax = 0;
    long   n_vals = 0;
    double *scals  = NULL;
    double *pscals=NULL,*pval=NULL;

    double s = 0;
    double d = 0;
    double laplacianOperator = 0;
    unsigned char* buf = NULL;
    unsigned char* hres = NULL;
    unsigned char* lres = NULL;
    unsigned long packed_offset;
    long   lpos = 0;

    long   maxv = 0;
    long   GRIBEX_sh_bug_present =0;
    long ieee_floats  = 0;

    long   offsetdata           = 0;
    long   bits_per_value          = 0;
    double reference_value      = 0;
    long   binary_scale_factor         = 0;
    long   decimal_scale_factor = 0;

    long   sub_j= 0;
    long   sub_k= 0;
    long   sub_m= 0;
    long   pen_j= 0;
    long   pen_k= 0;
    long   pen_m= 0;

    double operat= 0;
    int bytes;
    int err=0;

    decode_float_proc decode_float = NULL;

    err=grib_value_count(a,&n_vals);
    if (err) return err;

    if(*len < n_vals){
        *len = n_vals;
        return GRIB_ARRAY_TOO_SMALL;
    }

    if((ret = grib_get_long_internal(a->parent->h,self->offsetdata,&offsetdata))
            != GRIB_SUCCESS)   return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->bits_per_value,&bits_per_value))
            != GRIB_SUCCESS)   return ret;
    if((ret = grib_get_double_internal(a->parent->h,self->reference_value,&reference_value))
            != GRIB_SUCCESS)   return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->binary_scale_factor,&binary_scale_factor))
            != GRIB_SUCCESS)           return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->decimal_scale_factor,&decimal_scale_factor))
            != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->GRIBEX_sh_bug_present,&GRIBEX_sh_bug_present))
            != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->ieee_floats,&ieee_floats)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_double_internal(a->parent->h,self->laplacianOperator,&laplacianOperator))
            != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->sub_j,&sub_j)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->sub_k,&sub_k)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->sub_m,&sub_m)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->pen_j,&pen_j)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->pen_k,&pen_k)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->pen_m,&pen_m)) != GRIB_SUCCESS)
        return ret;

    self->dirty=0;

    switch (ieee_floats) {
    case 0:
        decode_float=grib_long_to_ibm;
        bytes=4;
        break;
    case 1:
        decode_float=grib_long_to_ieee;
        bytes=4;
        break;
    case 2:
        decode_float=grib_long_to_ieee64;
        bytes=8;
        break;
    default:
        return GRIB_NOT_IMPLEMENTED;
    }

    Assert (sub_j == sub_k);
    Assert (sub_j == sub_m);
    Assert (pen_j == pen_k);
    Assert (pen_j == pen_m);

    buf = (unsigned char*)a->parent->h->buffer->data;

    maxv = pen_j+1;

    buf  += grib_byte_offset(a);
    hres = buf;
    lres = buf;

    if (pen_j == sub_j) {
        n_vals = (pen_j+1)*(pen_j+2);
        d = grib_power(-decimal_scale_factor,10) ;
        grib_ieee_decode_array(a->parent->h->context,buf,n_vals,bytes,val);
        if (d) {
            for (i=0;i<n_vals;i++) val[i]*=d;
        }
        return 0;
    }

    packed_offset = grib_byte_offset(a) +  4*(sub_k+1)*(sub_k+2);

    lpos = 8*(packed_offset-offsetdata);

    s = grib_power(binary_scale_factor,2);
    d = grib_power(-decimal_scale_factor,10) ;

    scals   = (double*)grib_context_malloc(a->parent->h->context,maxv*sizeof(double));
    Assert(scals);

    scals[0] = 0;
    for(i=1;i<maxv;i++){
        operat = pow(i*(i+1),laplacianOperator);
        if(operat !=  0)
            scals[i] = (1.0/operat);
        else{
            grib_context_log(a->parent->h->context,GRIB_LOG_WARNING,
                    "COMPLEX_PACKING : problem with operator div by zero at index %d of %d \n",
                    i , maxv);
            scals[i] = 0;
        }
    }

    /*
  printf("UNPACKING LAPLACE=%.20f\n",laplacianOperator);

  printf("packed offset=%ld\n",packed_offset);
  for(i=0;i<maxv;i++)
    printf("scals[%d]=%g\n",i,scals[i]);*/

    i=0;

    while(maxv>0)
    {
        lup=mmax;
        if(sub_k>=0)
        {
            for(hcount=0;hcount<sub_k+1;hcount++)
            {
                val[i++] =  decode_float(grib_decode_unsigned_long(hres,&hpos,32))*d;
                val[i++] =  decode_float(grib_decode_unsigned_long(hres,&hpos,32))*d;

                if (GRIBEX_sh_bug_present && hcount==sub_k){
                    /*  bug in ecmwf data, last row (K+1)is scaled but should not */
                    val[i-2] *= scals[lup];
                    val[i-1] *= scals[lup];
                }
                lup++;
            }
            sub_k--;
        }

        pscals=scals+lup;
        pval=val+i;
#if FAST_BIG_ENDIAN
        grib_decode_double_array_complex(lres,
                &lpos,bits_per_value,
                reference_value,s,pscals,(maxv-hcount)*2,pval);
        i+=(maxv-hcount)*2;
#else
        (void)pscals; /* suppress gcc warning */
        (void)pval;   /* suppress gcc warning */
        for(lcount=hcount; lcount < maxv ; lcount++)
        {
            val[i++] =  (double) ((grib_decode_unsigned_long(lres, &lpos,
                    bits_per_value)*s)+reference_value)*scals[lup];
            val[i++] =  (double) ((grib_decode_unsigned_long(lres, &lpos,
                    bits_per_value)*s)+reference_value)*scals[lup];
            lup++;
        }
#endif

        maxv--;
        hcount=0;
        mmax++;
    }

    Assert(*len >= i);
    *len = i;

    if(d != 1) {
        for(i=0;i<*len;i++)
            val[i++] *= d;
    }

    grib_context_free(a->parent->h->context,scals);

    return ret;
}
static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args)
{
    int i, j, ret=0;
    double *lats, *lons; /* the lat/lon arrays to be populated */
    long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning;
    double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees,
    lonFirstInDegrees, Dx, Dy, radius=0;
    double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians,
    LaDInRadians, lonDiff, lonDeg, latDeg;
    double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2;

    grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter;

    const char* sradius                  = grib_arguments_get_name(h,args,self->carg++);
    const char* snx                      = grib_arguments_get_name(h,args,self->carg++);
    const char* sny                      = grib_arguments_get_name(h,args,self->carg++);
    const char* sLoVInDegrees            = grib_arguments_get_name(h,args,self->carg++);
    const char* sLaDInDegrees            = grib_arguments_get_name(h,args,self->carg++);
    const char* sLatin1InDegrees         = grib_arguments_get_name(h,args,self->carg++);
    const char* sLatin2InDegrees         = grib_arguments_get_name(h,args,self->carg++);
    const char* slatFirstInDegrees       = grib_arguments_get_name(h,args,self->carg++);
    const char* slonFirstInDegrees       = grib_arguments_get_name(h,args,self->carg++);
    /* Dx and Dy are in Metres */
    const char* sDx                      = grib_arguments_get_name(h,args,self->carg++);
    const char* sDy                      = grib_arguments_get_name(h,args,self->carg++);
    const char* siScansNegatively        = grib_arguments_get_name(h,args,self->carg++);
    const char* sjScansPositively        = grib_arguments_get_name(h,args,self->carg++);
    const char* sjPointsAreConsecutive   = grib_arguments_get_name(h,args,self->carg++);
    const char* salternativeRowScanning  = grib_arguments_get_name(h,args,self->carg++);

    if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS)
        return ret;

    if (iter->nv!=nx*ny) {
        grib_context_log(h->context,GRIB_LOG_ERROR,"Wrong number of points (%ld!=%ldx%ld)",iter->nv,nx,ny);
        return GRIB_WRONG_GRID;
    }
    if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees))!=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees))!=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees))!=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees))!=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) !=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) !=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, sDx,&Dx)) !=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, sDy,&Dy)) !=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) !=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) !=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) !=GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS)
        return ret;

    /* See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html */
    latFirstInRadians = latFirstInDegrees * DEG2RAD;
    lonFirstInRadians = lonFirstInDegrees * DEG2RAD;
    Latin1InRadians   = Latin1InDegrees * DEG2RAD;
    Latin2InRadians   = Latin2InDegrees * DEG2RAD;
    LaDInRadians      = LaDInDegrees * DEG2RAD;
    LoVInRadians      = LoVInDegrees * DEG2RAD;

    if ( fabs(Latin1InRadians - Latin2InRadians) < 1E-09 ) {
        n = sin(Latin1InRadians);
    }
    else {
        n = log(cos(Latin1InRadians)/cos(Latin2InRadians)) /
                log(tan(M_PI_4 + Latin2InRadians/2.0) / tan(M_PI_4 + Latin1InRadians/2.0));
    }

    f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians/2.0), n)) / n;
    rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians/2.0), -n);
    rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians/2.0), -n);
    if ( n < 0 ) /* adjustment for southern hemisphere */
        rho0 = -rho0;
    lonDiff = lonFirstInRadians - LoVInRadians;

    /* Adjust longitude to range -180 to 180 */
    if (lonDiff > M_PI)  lonDiff -= 2*M_PI;
    if (lonDiff < -M_PI) lonDiff += 2*M_PI;
    angle = n * lonDiff;
    x0 = rho * sin(angle);
    y0 = rho0 - rho * cos(angle);
    Dx = iScansNegatively == 0 ? Dx : -Dx;
    /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */
    /*Dy = jScansPositively == 1 ? Dy : -Dy;*/

    /* No support (yet) for jPointsAreConsecutive */
    if (jPointsAreConsecutive) {
        grib_context_log(h->context,GRIB_LOG_ERROR,"No support for: 'Adjacent points in j (y) direction being consecutive'");
        Assert(0);
    }

    /* Allocate latitude and longitude arrays */
    self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double));
    if (!self->lats) {
        grib_context_log(h->context,GRIB_LOG_ERROR,	"unable to allocate %ld bytes",iter->nv*sizeof(double));
        return GRIB_OUT_OF_MEMORY;
    }
    self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double));
    if (!self->lats) {
        grib_context_log(h->context,GRIB_LOG_ERROR,	"unable to allocate %ld bytes",iter->nv*sizeof(double));
        return GRIB_OUT_OF_MEMORY;
    }
    lats=self->lats;
    lons=self->lons;

    /* Populate our arrays */
    for (j = 0; j < ny; j++) {
        y = y0 + j*Dy;
        if ( n < 0 ) {  /* adjustment for southern hemisphere */
            y = -y;
        }
        tmp = rho0 - y;
        tmp2 = tmp*tmp;
        for (i = 0; i < nx; i++) {
            int index =i+j*nx;
            x = x0 + i*Dx;
            if ( n < 0 ) {  /* adjustment for southern hemisphere */
                x = -x;
            }

            angle = atan(x / tmp);
            rho = sqrt(x*x + tmp2);
            if (n <= 0) rho = -rho;
            lonDeg = LoVInDegrees + (angle/n) * RAD2DEG;
            latDeg = (2.0 * atan(pow(radius * f/rho, 1.0/n)) - M_PI_2) * RAD2DEG;
            while ( lonDeg >= 360.0) lonDeg -= 360.0;
            while ( lonDeg < 0.0)    lonDeg += 360.0;
            lons[index] = lonDeg;
            lats[index] = latDeg;
        }
    }

    iter->e = -1;

    return ret;
}
static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args)
{
  int ret=GRIB_SUCCESS,j;
  double lat_first=0,lon_first=0,lat_last=0,lon_last=0,d=0;
  double* lats;
  size_t plsize=0;
  int l=0;
  long* pl;
  long nj=0,order=0,ilon_first,ilon_last,i;
  long row_count=0;
  grib_context* c=h->context;
  grib_iterator_gaussian_reduced* self = (grib_iterator_gaussian_reduced*)iter;
  const char* slat_first   = grib_arguments_get_name(h,args,self->carg++);
  const char* slon_first   = grib_arguments_get_name(h,args,self->carg++);
  const char* slat_last    = grib_arguments_get_name(h,args,self->carg++);
  const char* slon_last    = grib_arguments_get_name(h,args,self->carg++);
  const char* sorder       = grib_arguments_get_name(h,args,self->carg++);
  const char* spl          = grib_arguments_get_name(h,args,self->carg++);
  const char* snj          = grib_arguments_get_name(h,args,self->carg++);

  if((ret = grib_get_double_internal(h, slat_first,&lat_first)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_double_internal(h, slon_first,&lon_first)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_double_internal(h, slat_last,&lat_last)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_double_internal(h, slon_last,&lon_last)) != GRIB_SUCCESS)
    return ret;

  if((ret = grib_get_long_internal(h, sorder,&order)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h, snj,&nj)) != GRIB_SUCCESS)
    return ret;

  lats=(double*)grib_context_malloc(h->context,sizeof(double)*order*2);
  if((ret = grib_get_gaussian_latitudes(order, lats)) != GRIB_SUCCESS)
      return ret;

  if((ret = grib_get_size(h,spl,&plsize)) != GRIB_SUCCESS)
      return ret;

  pl=(long*)grib_context_malloc(c,sizeof(long)*plsize);
  grib_get_long_array_internal(h,spl,pl, &plsize);

  self->las = grib_context_malloc(h->context,iter->nv*sizeof(double));
  self->los = grib_context_malloc(h->context,iter->nv*sizeof(double));

  while (lon_last<0) lon_last+=360;
  while (lon_first<0) lon_first+=360;

  d=fabs(lats[0]-lats[1]);
  if ( (fabs(lat_first-lats[0]) >= d ) ||
       (fabs(lat_last+lats[0]) >= d )  ||
       lon_first != 0                 ||
       fabs(lon_last  - (360.0-90.0/order)) > 90.0/order
       ) {
    /*sub area*/
	/*find starting latitude */
	while (fabs(lat_first-lats[l]) > d ) {l++;}
    iter->e=0;
    for (j=0;j<plsize;j++) {
        row_count=0;
		/*printf("lat=%g\n",lats[j+l]);*/
		grib_get_reduced_row(pl[j],lon_first,lon_last,
                  &row_count,&ilon_first,&ilon_last);
        if (ilon_first>ilon_last) ilon_first-=pl[j];
        for (i=ilon_first;i<=ilon_last;i++) {
         self->los[iter->e]=((i)*360.0)/pl[j];
         self->las[iter->e]=lats[j+l];
         iter->e++;
        }
     }
  } else {
    /*global*/
    iter->e=0;
    for (j=0;j<plsize;j++) {
        row_count=pl[j];
        for (i=0;i<row_count;i++) {
         self->los[iter->e]=(i*360.0)/row_count;
         self->las[iter->e]=lats[j];
         iter->e++;
        }
     }
  }

  iter->e = -1;
  grib_context_free(h->context,lats);
  grib_context_free(h->context,pl);

  return ret;
}
static int    unpack_string(grib_accessor* a, char* val, size_t *len)
{
	grib_accessor_sprintf* self = (grib_accessor_sprintf*)a;

	char result[1024]  ;
	char sres[1024]  ;
	long ires = 0;
	double dres= 0;

	int  i = 0;
	size_t replen = 1024;

	int ret = GRIB_SUCCESS;

	int carg= 0;
	int is_missing = 0;
	const char* uname = NULL;
	const char* tempname = NULL;


	uname = grib_arguments_get_string(a->parent->h,self->args,carg++);
	sprintf(result,"%s",""); 

	for(i=0;i<strlen(uname);i++)
	{

		if(uname[i]=='%'){
			int precision=999;
			i++;
			if (uname[i]=='.') {
				char *theEnd=NULL,*start;
				start=(char*)&(uname[++i]);
				precision=strtol(start,&theEnd,10);
				Assert(*theEnd!=0);
				while (uname[i] != *theEnd) i++;
			} 
			switch(uname[i]){

				case 'd':
					tempname = grib_arguments_get_name(a->parent->h,self->args,carg++);

					if((ret = grib_get_long_internal(a->parent->h,tempname,&ires)) != GRIB_SUCCESS)
						return ret;
					/* Bug GRIB-56: Check to see if the key is missing */
					is_missing = grib_is_missing(a->parent->h,tempname,&ret);
					if (ret != GRIB_SUCCESS)
						return ret;
					if (is_missing) {
						sprintf(result, "%sMISSING",result);
					}
					else {
						/* Not missing so print it */
						if (precision!=999) {
							sprintf(result,"%s%.*ld",result,precision, ires); 
						} else {
							sprintf(result,"%s%ld",result, ires); 
						}
					}
					break;

				case 'g':
					tempname = grib_arguments_get_name(a->parent->h,self->args,carg++);
					if((ret = grib_get_double_internal(a->parent->h,tempname,&dres)) != GRIB_SUCCESS) 
						return ret;
					sprintf(result,"%s%g",result, dres); 


					break;

				case 's':
					tempname = grib_arguments_get_name(a->parent->h,self->args,carg++);
					if((ret = grib_get_string_internal(a->parent->h,tempname,sres, &replen )) != GRIB_SUCCESS)
						return ret;
					sprintf(result,"%s%s",result, sres); 
					replen = 1024;


			}
		}
		else
			sprintf(result,"%s%c",result, uname[i]);


	}

	replen = strlen(result)+1;

	if(*len < replen){
		*len = replen;
		return GRIB_ARRAY_TOO_SMALL;
	}
	*len = replen;

	sprintf(val,"%s",result);

	return GRIB_SUCCESS;
}
static int init(grib_iterator* i,grib_handle* h,grib_arguments* args)
{
	grib_iterator_latlon_reduced* self = (grib_iterator_latlon_reduced*)i;

	int ret = GRIB_SUCCESS;
	double laf;
	double lal;
	long nlats;
	double lof,tlof;
	double lol,dimin;
	long *pl;
	size_t plsize =0 ;
	long k,j,ii;
	long nlons,plmax;
	double jdirinc = 0;
	double idirinc = 0;
	double dlon=0;
	int islocal=0;
	long nlons2 =0; /* adjusted num of longitudes */

	const char* latofirst   = grib_arguments_get_name(h,args,self->carg++);
	const char* longoffirst = grib_arguments_get_name(h,args,self->carg++);
	const char* latoflast   = grib_arguments_get_name(h,args,self->carg++);
	const char* longoflast  = grib_arguments_get_name(h,args,self->carg++);
	const char* nlats_name    = grib_arguments_get_name(h,args,self->carg++);
	const char* jdirec      = grib_arguments_get_name(h,args,self->carg++);
	const char* plac        = grib_arguments_get_name(h,args,self->carg++);

	if(( ret = grib_get_double_internal(h,latofirst,      &laf))) return ret;
	if(( ret = grib_get_double_internal(h,longoffirst,    &lof))) return ret;

	if(( ret = grib_get_double_internal(h,latoflast,     &lal))) return ret;
	if(( ret = grib_get_double_internal(h,longoflast,    &lol))) return ret;

	if(( ret = grib_get_long_internal(h,nlats_name,&nlats))) return ret;

	if(( ret = grib_get_double_internal(h,jdirec,&jdirinc))) return ret;

	plsize = nlats;
	pl  = (long*)grib_context_malloc(h->context,plsize*sizeof(long));
	grib_get_long_array_internal(h,plac,pl, &plsize);

	self->las = (double*)grib_context_malloc(h->context,i->nv*sizeof(double));
	self->los = (double*)grib_context_malloc(h->context,i->nv*sizeof(double));

	plmax=pl[0];
	for (j=0;j<nlats;j++) if (plmax<pl[j]) plmax=pl[j];
	dimin=360.0/plmax;

	if ( 360-fabs(lol-lof) < 2 * dimin ) {dlon=360; islocal=0;}
	else if (lol < lof) {
		/* handle something like 150 to -120 to treat as 150 to 240 */
		/* so that dlon is 90 (not -270) */
		dlon=lol + 360.0 - lof;
		islocal=1;
	}
	else {dlon=lol-lof; islocal=1;}

	if (laf>lal) jdirinc=-jdirinc;
	k=0;
	for (j=0;j<nlats;j++) {
		nlons=pl[j];
		tlof=lof;
		nlons2 = nlons-islocal;
		/*Sometimes there are no points on a latitude! Protect against div by zero*/
		if (nlons2<1) nlons2=1;
		idirinc=dlon/nlons2;
		for (ii=0;ii<nlons;ii++) {
			self->las[k]=laf;
			self->los[k]=tlof;
			tlof+=idirinc;
			k++;
		}
		laf+=jdirinc;
	}

	i->e = -1;
	grib_context_free(h->context,pl);

	return ret;
}
static int unpack_double(grib_accessor* a, double* values, size_t *len)
{
  grib_accessor_data_g1second_order_constant_width_packing* self =  (grib_accessor_data_g1second_order_constant_width_packing*)a;
  int ret=0;
  long numberOfGroups,numberOfSecondOrderPackedValues;
  long groupWidth=0;
  long* firstOrderValues=0;
  long* X=0;
  long numberPerRow=0;
  long pos=0;
  long widthOfFirstOrderValues=0;
  long jPointsAreConsecutive;
  unsigned char* buf = (unsigned char*)grib_handle_of_accessor(a)->buffer->data;
  long i,n;
  double reference_value;
  long binary_scale_factor;
  long decimal_scale_factor;
  double s,d;
  long* secondaryBitmap;

  buf += grib_byte_offset(a);

  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->numberOfGroups,&numberOfGroups)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->jPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS)
         return ret;

	if (jPointsAreConsecutive) {
	  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->Ni,&numberPerRow)) != GRIB_SUCCESS)
         return ret;
	} else {
	  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->Nj,&numberPerRow)) != GRIB_SUCCESS)
         return ret;
	}

  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->widthOfFirstOrderValues,&widthOfFirstOrderValues)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->binary_scale_factor,&binary_scale_factor)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->decimal_scale_factor,&decimal_scale_factor)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_double_internal(grib_handle_of_accessor(a),self->reference_value,&reference_value)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->numberOfSecondOrderPackedValues,
  					&numberOfSecondOrderPackedValues)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(grib_handle_of_accessor(a),self->groupWidth, &groupWidth)) != GRIB_SUCCESS)
         return ret;

	secondaryBitmap=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfSecondOrderPackedValues);
	grib_decode_long_array(buf,&pos,1,numberOfSecondOrderPackedValues,secondaryBitmap);
	pos = 8 * ( (pos + 7 ) / 8);

	firstOrderValues=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfGroups);
	grib_decode_long_array(buf,&pos,widthOfFirstOrderValues,numberOfGroups,firstOrderValues);
	pos = 8 * ( (pos + 7 ) / 8);

	X=(long*)grib_context_malloc_clear(a->context,sizeof(long)*numberOfSecondOrderPackedValues);

	if (groupWidth>0) {
		grib_decode_long_array(buf,&pos,groupWidth,numberOfSecondOrderPackedValues,X);
		n=0;
		i=-1;
		while (n<numberOfSecondOrderPackedValues) {
			i+=secondaryBitmap[n];
			X[n]=firstOrderValues[i]+X[n];
			n++;
		}
	} else {
		n=0;
		i=-1;
		while (n<numberOfSecondOrderPackedValues) {
			i+=secondaryBitmap[n];
			X[n]=firstOrderValues[i];
			n++;
		}
	}


	/*
	{
	long extrabits = 16 * ( (pos + 15 ) / 16) - pos;
	printf("XXXXXXX extrabits=%ld pos=%ld\n",extrabits,pos);
	}
	*/

	s = grib_power(binary_scale_factor,2);
	d = grib_power(-decimal_scale_factor,10) ;
	for (i=0; i<numberOfSecondOrderPackedValues; i++) {
		values[i] = (double) (((X[i]*s)+reference_value)*d);
	}

	*len=numberOfSecondOrderPackedValues;
	grib_context_free(a->context,secondaryBitmap);
	grib_context_free(a->context,firstOrderValues);
	grib_context_free(a->context,X);
  
  return ret;
}
static int unpack_double(grib_accessor* a, double* val, size_t *len)
{
    grib_accessor_data_apply_boustrophedonic_bitmap* self =  (grib_accessor_data_apply_boustrophedonic_bitmap*)a;

    size_t i = 0, j = 0, n_vals = 0, irow = 0;
    long nn=0;
    int err=0;
    size_t coded_n_vals = 0;
    double* coded_vals = NULL;
    double missing_value = 0;
    long numberOfPoints, numberOfRows, numberOfColumns;

    err=grib_value_count(a,&nn);
    n_vals=nn;
    if (err) return err;

    err=grib_get_long_internal(a->parent->h,self->numberOfRows,&numberOfRows);
    if (err) return err;
    err=grib_get_long_internal(a->parent->h,self->numberOfColumns,&numberOfColumns);
    if (err) return err;
    err=grib_get_long_internal(a->parent->h,self->numberOfPoints,&numberOfPoints);
    if (err) return err;
    Assert(nn == numberOfPoints);

    if(!grib_find_accessor(a->parent->h,self->bitmap))
        return grib_get_double_array_internal(a->parent->h,self->coded_values,val,len);

    if((err = grib_get_size(a->parent->h,self->coded_values,&coded_n_vals)) != GRIB_SUCCESS)
        return err;

    if((err = grib_get_double_internal(a->parent->h,self->missing_value,&missing_value))
            != GRIB_SUCCESS)  return err;

    if(*len < n_vals) {
        *len = n_vals;
        return GRIB_ARRAY_TOO_SMALL;
    }

    if (coded_n_vals==0) {
        for(i=0;i < n_vals;i++)
            val[i] = missing_value;

        *len=n_vals;
        return GRIB_SUCCESS;
    }

    if((err = grib_get_double_array_internal(a->parent->h,self->bitmap,val,&n_vals))
            != GRIB_SUCCESS)
        return err;

    coded_vals = (double*)grib_context_malloc(a->parent->h->context,coded_n_vals*sizeof(double));
    if(coded_vals == NULL) return GRIB_OUT_OF_MEMORY;

    if((err = grib_get_double_array_internal(a->parent->h,self->coded_values,coded_vals,&coded_n_vals))
            != GRIB_SUCCESS)
    {
        grib_context_free(a->parent->h->context,coded_vals);
        return err;
    }

    grib_context_log(a->parent->h->context, GRIB_LOG_DEBUG,
            "grib_accessor_class_data_apply_boustrophedonic_bitmap: unpack_double : creating %s, %d values",
            a->name, n_vals);

    /* Boustrophedonic ordering (See GRIB-472):
     * Values on even rank lines (the initial line scanned having rank 1) are swapped
     */
    for(irow=0; irow<numberOfRows; ++irow)
    {
        if (irow%2)
        {
            /* Reverse bitmap entries */
            size_t k = 0;
            size_t start = irow*numberOfColumns;
            size_t end = start + numberOfColumns - 1;
            size_t mid = (numberOfColumns - 1)/2;
            for(k=0; k<mid; ++k)
            {
                /* Swap value at either end */
                double temp = val[start+k];
                val[start+k] = val[end-k];
                val[end-k] = temp;
            }
        }
    }

    for(i=0;i < n_vals;i++)
    {
        if(val[i] == 0 ){
            val[i] = missing_value;
        }
        else
        {
            val[i] = coded_vals[j++];
            if(j>coded_n_vals)
            {
                grib_context_free(a->parent->h->context,coded_vals);
                grib_context_log(a->parent->h->context, GRIB_LOG_ERROR,
                        "grib_accessor_class_data_apply_boustrophedonic_bitmap [%s]:"
                        " unpack_double :  number of coded values does not match bitmap %ld %ld",
                        a->name,coded_n_vals,n_vals);

                return GRIB_ARRAY_TOO_SMALL;
            }
        }
    }

    *len =  n_vals;

    grib_context_free(a->parent->h->context,coded_vals);
    return err;
}
static int pack_double(grib_accessor* a, const double* val, size_t *len) {

    grib_accessor_data_complex_packing* self =  (grib_accessor_data_complex_packing*)a;

    size_t i = 0;
    int ret = GRIB_SUCCESS;
    long   hcount = 0;
    long   lcount = 0;
    long   hpos = 0;
    long   lup = 0;
    long   mmax = 0;
    long   n_vals = 0;
    double *scals  = NULL;

    double s = 0;
    double d = 0;

    unsigned char* buf    = NULL;

    size_t         buflen = 0;
    size_t         hsize = 0;
    size_t         lsize = 0;

    unsigned char* hres = NULL;
    unsigned char* lres = NULL;

    long   lpos = 0;
    long   maxv = 0;

    long   offsetdata           = 0;
    long   bits_per_value          = 0;
    double reference_value      = 0;
    long   binary_scale_factor         = 0;
    long   decimal_scale_factor = 0;
    long   laplacianOperatorIsSet = 0;

    double laplacianOperator = 0;
    long   sub_j= 0;
    long   sub_k= 0;
    long   sub_m= 0;
    long   pen_j= 0;
    long   pen_k= 0;
    long   pen_m= 0;
    long   GRIBEX_sh_bug_present =0;
    long   ieee_floats =0;
    double min = 0;
    double max = 0;
    double current_val = 0;
    short mixmax_unset = 0;
    int bytes;

    encode_float_proc encode_float = NULL;

    if (*len ==0) return GRIB_NO_VALUES;

    if((ret = grib_get_long_internal(a->parent->h,self->offsetdata,&offsetdata)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->bits_per_value,&bits_per_value)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->decimal_scale_factor,&decimal_scale_factor)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->GRIBEX_sh_bug_present,&GRIBEX_sh_bug_present)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->ieee_floats,&ieee_floats)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->laplacianOperatorIsSet,&laplacianOperatorIsSet)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(a->parent->h,self->laplacianOperator,&laplacianOperator)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->sub_j,&sub_j)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->sub_k,&sub_k)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->sub_m,&sub_m)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->pen_j,&pen_j)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->pen_k,&pen_k)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(a->parent->h,self->pen_m,&pen_m)) != GRIB_SUCCESS)
        return ret;

    self->dirty=1;


    switch (ieee_floats) {
    case 0:
        encode_float =grib_ibm_to_long;
        bytes=4;
        break;
    case 1:
        encode_float =grib_ieee_to_long;
        bytes=4;
        break;
    case 2:
        encode_float =grib_ieee64_to_long;
        bytes=8;
        break;
    default:
        return GRIB_NOT_IMPLEMENTED;
    }

    Assert (sub_j == sub_k); Assert( sub_j == sub_m);
    Assert (pen_j == pen_k); Assert( pen_j == pen_m);

    n_vals = (pen_j+1)*(pen_j+2);
    d = grib_power(decimal_scale_factor,10) ;

    if(*len != n_vals){
        grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,"COMPLEX_PACKING : wrong number of values, expected %d - got %d",n_vals,*len);
        return GRIB_INTERNAL_ERROR;
    }

    if (pen_j == sub_j) {
        double* values;
        if (d) {
            values=(double*)grib_context_malloc_clear(a->parent->h->context,sizeof(double)*n_vals);
            for (i=0;i<n_vals;i++) values[i]=val[i]*d;
        } else {
            values=(double*)val;
        }
        buflen=n_vals*bytes;
        buf = (unsigned char*)grib_context_malloc_clear(a->parent->h->context,buflen);
        grib_ieee_encode_array(a->parent->h->context,values,n_vals,bytes,buf);
        if (d) grib_context_free(a->parent->h->context,values);
        grib_buffer_replace(a, buf, buflen,1,1);
        grib_context_free(a->parent->h->context,buf);
        return 0;
    }

    if(!laplacianOperatorIsSet) {
        laplacianOperator = calculate_pfactor(a->parent->h->context,val,pen_j,sub_j);
        if((ret = grib_set_double_internal(a->parent->h,self->laplacianOperator,laplacianOperator))
                != GRIB_SUCCESS) return ret;
        grib_get_double_internal(a->parent->h,self->laplacianOperator,&laplacianOperator);
    }

    /*
     printf("PACKING LAPLACE set=%ld value=%.20f\n",laplacianOperatorIsSet,laplacianOperator);
    */

    hsize = 4*(sub_k+1)*(sub_k+2);
    lsize = ((n_vals - ((sub_k+1)*(sub_k+2)))*bits_per_value)/8;

    buflen = hsize+lsize;

    buf  = (unsigned char*)grib_context_malloc(a->parent->h->context,buflen);
    hres = buf;
    lres = buf+hsize;

    maxv = pen_j+1;

    lpos = 0;
    hpos = 0;

    scals   = (double*) grib_context_malloc(a->parent->h->context,maxv*sizeof(double));
    Assert(scals);

    scals[0] =0;
    for(i=1;i<maxv;i++)
        scals[i] = ((double)pow(i*(i+1),laplacianOperator));


    i=0;

    mmax = 0;
    maxv = pen_j+1;
    i=0;
    lcount=0;
    hcount=0;
    sub_k = sub_j;

    while(maxv>0)
    {
        lup=mmax;

        if(sub_k>=0)
        {
            i   += 2*(sub_k+1);
            lup +=    sub_k+1 ;
            hcount += sub_k+1 ;
            sub_k--;
        }

        for(lcount=hcount; lcount < maxv ; lcount++)
        {
            current_val = ((val[i++]*d) * scals[lup]);
            if(mixmax_unset == 0){
                max = current_val;
                min = current_val;
                mixmax_unset = 1;
            }

            if(current_val > max) max = current_val;
            if(current_val < min) min = current_val;

            current_val = ((val[i++]*d) * scals[lup]);
            if(current_val > max) max = current_val;
            if(current_val < min) min = current_val;

            lup++;
        }
        maxv--;
        hcount=0;
        mmax++;
    }

    if (grib_get_nearest_smaller_value(a->parent->h,self->reference_value,min,&reference_value)
            !=GRIB_SUCCESS) {
        grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,
                "unable to find nearest_smaller_value of %g for %s",min,self->reference_value);
        exit(GRIB_INTERNAL_ERROR);
    }
    binary_scale_factor = grib_get_binary_scale_fact(max,reference_value,bits_per_value,&ret);

    if (ret==GRIB_UNDERFLOW) {
        d=0;
        binary_scale_factor = 0;
        reference_value=0;

    }
    s = grib_power(-binary_scale_factor,2);

    /* printf("D : %.30f\n",d); */

    i=0;

    mmax = 0;
    maxv = pen_j+1;
    i=0;
    lcount=0;
    hcount=0;
    sub_k = sub_j;

    while(maxv>0)
    {
        lup=mmax;

        if(sub_k>=0)
        {
            for(hcount=0;hcount<sub_k+1;hcount++)
            {
                if ( GRIBEX_sh_bug_present && hcount==sub_k ) {
                    /* _test(val[i]*d*scals[lup],1); */
                    grib_encode_unsigned_long(hres, encode_float((val[i++]*d)*scals[lup]) , &hpos, 32);
                    /* _test(val[i]*d*scals[lup],1); */
                    grib_encode_unsigned_long(hres, encode_float((val[i++]*d)*scals[lup]) , &hpos, 32);
                }else{

                    /* _test(val[i]*d,0); */

                    grib_encode_unsigned_long(hres, encode_float(val[i++]*d) , &hpos, 32);
                    /* _test(val[i]*d,0); */
                    grib_encode_unsigned_long(hres, encode_float(val[i++]*d) , &hpos, 32);
                }
                lup++;
            }
            sub_k--;
        }

#if FAST_BIG_ENDIAN
        grib_encode_double_array_complex((maxv-hcount)*2,&(val[i]),bits_per_value,reference_value,&(scals[lup]),d,s,lres,&lpos);
        i+=(maxv-hcount)*2;
#else
        if (bits_per_value % 8) {
            for(lcount=hcount; lcount < maxv ; lcount++)
            {
                current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
                if(current_val < 0)
                    grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,
                            "COMPLEX_PACKING : negative coput before packing (%g)", current_val);
                grib_encode_unsigned_longb(lres, current_val, &lpos, bits_per_value);

                current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
                if(current_val < 0)
                    grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,
                            "COMPLEX_PACKING : negative coput before packing (%g)", current_val);
                grib_encode_unsigned_longb(lres, current_val, &lpos, bits_per_value);
                lup++;
            }
        } else {
            for(lcount=hcount; lcount < maxv ; lcount++)
            {
                current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
                if(current_val < 0)
                    grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,
                            "COMPLEX_PACKING : negative coput before packing (%g)", current_val);
                grib_encode_unsigned_long(lres, current_val, &lpos, bits_per_value);

                current_val = (((((val[i++]*d) * scals[lup])-reference_value)*s)+0.5);
                if(current_val < 0)
                    grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,
                            "COMPLEX_PACKING : negative coput before packing (%g)", current_val);
                grib_encode_unsigned_long(lres, current_val, &lpos, bits_per_value);
                lup++;
            }
        }
#endif

        maxv--;
        hcount=0;
        mmax++;
    }

    if(((hpos/8) != hsize) &&((lpos/8) != lsize))
    {
        grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,
                "COMPLEX_PACKING : Mismatch in packing between high resolution and low resolution part");
        grib_context_free(a->parent->h->context,buf);
        grib_context_free(a->parent->h->context,scals);
        return GRIB_INTERNAL_ERROR;
    }

    buflen = ((hpos + lpos)/8);

    if((ret = grib_set_double_internal(a->parent->h,self->reference_value, reference_value)) != GRIB_SUCCESS)
        return ret;
    {
        /* Make sure we can decode it again */
        double ref = 1e-100;
        grib_get_double_internal(a->parent->h,self->reference_value,&ref);
        Assert(ref == reference_value);
    }

    if((ret = grib_set_long_internal(a->parent->h,self->binary_scale_factor, binary_scale_factor)) != GRIB_SUCCESS)
        return ret;

    grib_buffer_replace(a, buf, buflen,1,1);
    grib_context_free(a->parent->h->context,buf);
    grib_context_free(a->parent->h->context,scals);

    return ret;

}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
    grib_accessor_data_g2secondary_bitmap* self =  (grib_accessor_data_g2secondary_bitmap*)a;

    int err = 0;

    long primary_len = 0;
    long secondary_len = 0;
    double* primary_bitmap = NULL;
    double* secondary_bitmap = NULL;
    long i = 0;
    long j = 0;
    long on = 0;
    long k;
    long m;
    double missing_value = 0;
    double present_value = 0;
    long expand_by =0;

    if (*len ==0) return GRIB_NO_VALUES;

    if((err = grib_get_long(a->parent->h,self->expand_by,&expand_by)) != GRIB_SUCCESS)
        return err;

    if((err = grib_get_double_internal(a->parent->h,self->missing_value,&missing_value)) != GRIB_SUCCESS)
        return err;

    Assert(expand_by);

    if(*len % expand_by)
    {
        /*TODO: issue warning */
        return GRIB_ENCODING_ERROR;
    }

    primary_len = *len / expand_by;
    primary_bitmap= (double*)grib_context_malloc_clear(a->parent->h->context,primary_len*sizeof(double));
    if(!primary_bitmap) return GRIB_OUT_OF_MEMORY;

    secondary_len = *len ;
    secondary_bitmap= (double*)grib_context_malloc_clear(a->parent->h->context,secondary_len*sizeof(double));
    if(!secondary_bitmap) {
        grib_context_free(a->parent->h->context,primary_bitmap);
        return GRIB_OUT_OF_MEMORY;
    }

    if(missing_value == 0)
        present_value = 1;
    else
        present_value = 0;

    k = 0;
    m = 0;
    for(i=0; i<*len ; i += expand_by)
    {
        int cnt = 0;
        for(j = 0; j < expand_by; j++)
            if(val[i+j] == missing_value)
                cnt++;

        if(cnt == expand_by) /* all expand_by values are missing */
            primary_bitmap[k++] = missing_value;
        else {
            primary_bitmap[k++] = present_value;
            for(j = 0; j < expand_by; j++)
                secondary_bitmap[m++] = val[i+j];
            on++;
        }
    }

    *len = k;

    Assert(k == primary_len);

    err = grib_set_double_array_internal(a->parent->h,self->primary_bitmap,primary_bitmap,k);
    if(err == GRIB_SUCCESS)
        err = grib_set_double_array_internal(a->parent->h,self->secondary_bitmap,secondary_bitmap,m);

    grib_context_free(a->parent->h->context,primary_bitmap);
    grib_context_free(a->parent->h->context,secondary_bitmap);

    if(err == GRIB_SUCCESS)
        err = grib_set_long_internal(a->parent->h,self->number_of_values,*len * expand_by);

    return err;
}
static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args)
{
    int ret=GRIB_SUCCESS, j, is_global=0;
    double lat_first=0,lon_first=0,lat_last=0,lon_last=0;
    double angular_precision = 1.0/1000000.0;
    double* lats;
    size_t plsize=0;
    long* pl;
    long max_pl=0;
    long nj=0,order=0,ilon_first,ilon_last,i;
    long row_count=0;
    long editionNumber = 0;
    grib_context* c=h->context;
    grib_iterator_gaussian_reduced* self = (grib_iterator_gaussian_reduced*)iter;
    const char* slat_first   = grib_arguments_get_name(h,args,self->carg++);
    const char* slon_first   = grib_arguments_get_name(h,args,self->carg++);
    const char* slat_last    = grib_arguments_get_name(h,args,self->carg++);
    const char* slon_last    = grib_arguments_get_name(h,args,self->carg++);
    const char* sorder       = grib_arguments_get_name(h,args,self->carg++);
    const char* spl          = grib_arguments_get_name(h,args,self->carg++);
    const char* snj          = grib_arguments_get_name(h,args,self->carg++);

    if((ret = grib_get_double_internal(h, slat_first,&lat_first)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, slon_first,&lon_first)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, slat_last,&lat_last)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_double_internal(h, slon_last,&lon_last)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(h, sorder,&order)) != GRIB_SUCCESS)
        return ret;
    if((ret = grib_get_long_internal(h, snj,&nj)) != GRIB_SUCCESS)
        return ret;

    if (grib_get_long(h, "editionNumber", &editionNumber)==GRIB_SUCCESS) {
        if (editionNumber == 1) angular_precision = 1.0/1000;
    }

    lats=(double*)grib_context_malloc(h->context,sizeof(double)*order*2);
    if (!lats) return GRIB_OUT_OF_MEMORY;
    if((ret = grib_get_gaussian_latitudes(order, lats)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_size(h,spl,&plsize)) != GRIB_SUCCESS)
        return ret;

    Assert(plsize);
    pl=(long*)grib_context_malloc(c,sizeof(long)*plsize);
    if (!pl) return GRIB_OUT_OF_MEMORY;

    grib_get_long_array_internal(h,spl,pl, &plsize);

    self->las = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double));
    if (!self->las) return GRIB_OUT_OF_MEMORY;
    self->los = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double));
    if (!self->los) return GRIB_OUT_OF_MEMORY;

    while (lon_last<0) lon_last+=360;
    while (lon_first<0) lon_first+=360;

    /* Find the maximum element of "pl" array, do not assume it's 4*N! */
    /* This could be an Octahedral Gaussian Grid */
    max_pl = pl[0];
    for (j=1; j<plsize; j++) {
        if (pl[j] > max_pl) max_pl = pl[j];
    }

    is_global = is_gaussian_global(lat_first, lat_last, lon_first, lon_last, max_pl, lats, angular_precision);
    if ( !is_global ) {
        int l=0;
        /*sub area*/
        /*find starting latitude */
        const double d = fabs(lats[0] - lats[1]);
        while (fabs(lat_first-lats[l]) > d ) {l++;}
        iter->e=0;
        for (j=0;j<plsize;j++) {
            row_count=0;
            grib_get_reduced_row(pl[j],lon_first,lon_last,
                    &row_count,&ilon_first,&ilon_last);
            if (ilon_first>ilon_last) ilon_first-=pl[j];
            for (i=ilon_first;i<=ilon_last;i++) {
#ifdef DEBUG
                Assert(iter->e < iter->nv);
#endif
                self->los[iter->e]=((i)*360.0)/pl[j];
                self->las[iter->e]=lats[j+l];
                iter->e++;
            }
        }
    } else {
        /*global*/
        iter->e=0;
        for (j=0;j<plsize;j++) {
            row_count=pl[j];
            for (i=0;i<row_count;i++) {
#ifdef DEBUG
                Assert(iter->e < iter->nv);
#endif
                self->los[iter->e]=(i*360.0)/row_count;
                self->las[iter->e]=lats[j];
                iter->e++;
            }
        }
    }

    iter->e = -1;
    grib_context_free(h->context,lats);
    grib_context_free(h->context,pl);

    return ret;
}
static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args)
{
  int ret=0;
  double *lats,*lons;
  double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0;
  long nx,ny,standardParallel,centralLongitude;
  double phi1,lambda0,xFirst,yFirst,x,y,Dx,Dy;
  double kp,sinphi1,cosphi1,sinlambda0,coslambda0;
  long alternativeRowScanning,iScansNegatively;
  long jScansPositively,jPointsAreConsecutive;
  double sinphi,cosphi,sinlambda,coslambda,cosdlambda,sindlambda;
  double cosc,sinc;
  long i,j;
  
  grib_iterator_lambert_azimuthal_equal_area* self =
      (grib_iterator_lambert_azimuthal_equal_area*)iter;

  const char* sradius           = grib_arguments_get_name(h,args,self->carg++);
  const char* snx               = grib_arguments_get_name(h,args,self->carg++);
  const char* sny               = grib_arguments_get_name(h,args,self->carg++);
  const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++);
  const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++);
  const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++);
  const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++);
  const char* sDx = grib_arguments_get_name(h,args,self->carg++);
  const char* sDy = grib_arguments_get_name(h,args,self->carg++);
  const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++);
  const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++);
  const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++);
  const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++);
  double c,rho;
  double epsilon=1.0e-20;
  double d2r=acos(0.0)/90.0;
  
  if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS)
    return ret;

  if (iter->nv!=nx*ny) {
    grib_context_log(h->context,GRIB_LOG_ERROR,
                     "Wrong number of points (%ld!=%ldx%ld)",
                     iter->nv,nx,ny);
    return GRIB_WRONG_GRID;
  }
  if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees))
      != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees))
      != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel))
      != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h, scentralLongitude,&centralLongitude))
      != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h,
      sjPointsAreConsecutive,&jPointsAreConsecutive))
      != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively))
      != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively))
      != GRIB_SUCCESS)
    return ret;
  if((ret = grib_get_long_internal(h,
      salternativeRowScanning,&alternativeRowScanning))
      != GRIB_SUCCESS)
    return ret;

  lambda0=d2r*standardParallel/1000000;
  phi1=d2r*centralLongitude/1000000;
  latFirst=latFirstInDegrees*d2r;
  lonFirst=lonFirstInDegrees*d2r;

  coslambda0=cos(lambda0);
  sinlambda0=sin(lambda0);
  cosphi1=cos(phi1);
  sinphi1=sin(phi1);

  Dx = iScansNegatively == 0 ? Dx/1000 : -Dx/1000;
  Dy = jScansPositively == 1 ? Dy/1000 : -Dy/1000;
  self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double));
  if (!self->lats) {
    grib_context_log(h->context,GRIB_LOG_ERROR,
                     "unable to allocate %ld bytes",iter->nv*sizeof(double));
    return GRIB_OUT_OF_MEMORY;
  }
  self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double));
  if (!self->lats) {
    grib_context_log(h->context,GRIB_LOG_ERROR,
                     "unable to allocate %ld bytes",iter->nv*sizeof(double));
    return GRIB_OUT_OF_MEMORY;
  }
  lats=self->lats;
  lons=self->lons;

  /* compute xFirst,yFirst in metres */
  sinphi=sin(latFirst);
  cosphi=cos(latFirst);
  sinlambda=sin(lonFirst);
  coslambda=cos(lonFirst);
  cosdlambda=cos(lonFirst-lambda0);
  sindlambda=sin(lonFirst-lambda0);
  kp=radius*sqrt(2.0/(1+sinphi1*sinphi+cosphi1*cosphi*cosdlambda));
  xFirst=kp*cosphi*sindlambda;
  yFirst=kp*(cosphi1*sinphi-sinphi1*cosphi*cosdlambda);
  
  if (jPointsAreConsecutive) {
  
    x=xFirst;
    for (i=0;i<nx;i++) {
      y=yFirst;   
      for (j=0;j<ny;j++) {
        rho=sqrt(x*x+y*y);
        if (rho>epsilon) {
          c=2*asin(rho/(2.0*radius));
          cosc=cos(c);
          sinc=sin(c);
          *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r;
          *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r;
        } else {
          *lats=phi1/d2r;
          *lons=lambda0/d2r;
        }
        if (*lons<0) *lons+=360;
        lons++;
        lats++;

        y+=Dy;
      }
      x+=Dx;
    }
    
  } else {

    y=yFirst;
    for (j=0;j<ny;j++) {
      x=xFirst;
      for (i=0;i<nx;i++) {
        rho=sqrt(x*x+y*y);
        if (rho>epsilon) {
          c=2*asin(rho/(2.0*radius));
          cosc=cos(c);
          sinc=sin(c);
          *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r;
          *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r;
        } else {
          *lats=phi1/d2r;
          *lons=lambda0/d2r;
        }
        if (*lons<0) *lons+=360;
        lons++;
        lats++;

        x+=Dx;
      }
      y+=Dy;
    }

  }
  
  iter->e = -1;

  return ret;
}
static int pack_double(grib_accessor* a, const double* val, size_t *len)
{
    grib_accessor_data_apply_boustrophedonic_bitmap* self =  (grib_accessor_data_apply_boustrophedonic_bitmap*)a;
    int err = 0;
    size_t bmaplen = *len;
    size_t irow = 0;
    long coded_n_vals = 0;
    double* coded_vals = NULL;
    double *values=0;
    long i = 0;
    long j = 0;
    long numberOfPoints, numberOfRows, numberOfColumns;
    double missing_value = 0;

    if (*len ==0) return GRIB_NO_VALUES;

    if(!grib_find_accessor(a->parent->h,self->bitmap)){
        err = grib_set_double_array_internal(a->parent->h,self->coded_values,val,*len);
        /*printf("SETTING TOTAL number_of_data_points %s %ld\n",self->number_of_data_points,*len);*/
        /*if(self->number_of_data_points)
            grib_set_long_internal(a->parent->h,self->number_of_data_points,*len);*/
        return err;
    }

    if((err = grib_get_double_internal(a->parent->h,self->missing_value,&missing_value)) != GRIB_SUCCESS)
        return err;

    err=grib_get_long_internal(a->parent->h,self->numberOfRows, &numberOfRows);
    if (err) return err;
    err=grib_get_long_internal(a->parent->h,self->numberOfColumns, &numberOfColumns);
    if (err) return err;
    err=grib_get_long_internal(a->parent->h,self->numberOfPoints,&numberOfPoints);
    if (err) return err;
    Assert(numberOfPoints == bmaplen);

    /* Create a copy of the incoming 'val' array because we're going to change it */
    values = (double*)grib_context_malloc_clear(a->parent->h->context, sizeof(double)*numberOfPoints);
    if (!values) return GRIB_OUT_OF_MEMORY;
    for(i=0; i<numberOfPoints; ++i) {
        values[i] = val[i];
    }

    /* Boustrophedonic ordering must be applied to the bitmap (See GRIB-472) */
    for(irow=0; irow<numberOfRows; ++irow)
    {
        if (irow%2)
        {
            size_t k = 0;
            size_t start = irow*numberOfColumns;
            size_t end = start + numberOfColumns - 1;
            size_t mid = (numberOfColumns - 1)/2;
            for(k=0; k<mid; ++k)
            {
                double temp = values[start+k];
                values[start+k] = values[end-k];
                values[end-k] = temp;
            }
        }
    }
    /* Now set the bitmap based on the array with the boustrophedonic ordering */
    if((err = grib_set_double_array_internal(a->parent->h,self->bitmap,values,bmaplen)) != GRIB_SUCCESS)
        return err;

    grib_context_free(a->parent->h->context,values);

    coded_n_vals = *len;

    if(coded_n_vals < 1){
        err = grib_set_double_array_internal(a->parent->h,self->coded_values,NULL,0);
        return err;
    }

    coded_vals = (double*)grib_context_malloc_clear(a->parent->h->context,coded_n_vals*sizeof(double));
    if(!coded_vals) return GRIB_OUT_OF_MEMORY;

    for(i=0; i<*len ; i++)
    {
        /* To set the coded values, look at 'val' (the original array) */
        /* NOT 'values' (bitmap) which we swapped about */
        if(val[i] != missing_value) {
            coded_vals[j++] = val[i];
        }
    }

    err = grib_set_double_array_internal(a->parent->h,self->coded_values,coded_vals,j);
    if (j==0) {
        /*if (self->number_of_values)
            err=grib_set_long_internal(a->parent->h,self->number_of_values,0);*/
        if (self->binary_scale_factor)
            err=grib_set_long_internal(a->parent->h,self->binary_scale_factor,0);
    }

    grib_context_free(a->parent->h->context,coded_vals);

    return err;
}
static int pack_double(grib_accessor* a, const double* cval, size_t *len)
{
    grib_accessor_data_g1simple_packing* self =  (grib_accessor_data_g1simple_packing*)a;
    grib_accessor_class* super = *(a->cclass->super);

    size_t n_vals = *len;
    long half_byte = 0;
    int ret = 0;
    long offsetdata = 0;
    long offsetsection = 0;
    double reference_value = 0;
    long   binary_scale_factor = 0;
    long   bits_per_value = 0;
    long   decimal_scale_factor = 0;
    double decimal = 1;
    size_t buflen = 0;
    unsigned char*  buf = NULL;
    unsigned char*  encoded = NULL;
    double divisor = 1;
    int i;
    long off = 0;
    grib_context* c=a->parent->h->context;
    grib_handle* h=a->parent->h;
    char* ieee_packing_s=NULL;
    char* packingType_s=NULL;
    char* precision_s=NULL;
    double units_factor=1.0;
    double units_bias=0.0;
    double* val=(double*)cval;
    double missingValue=9999.0;
    long constantFieldHalfByte=0;
    int err=0;

    if(*len != 0) {
        if(self->units_factor &&
                (grib_get_double_internal(a->parent->h,self->units_factor,&units_factor)== GRIB_SUCCESS)) {
            grib_set_double_internal(a->parent->h,self->units_factor,1.0);
        }

        if(self->units_bias &&
                (grib_get_double_internal(a->parent->h,self->units_bias,&units_bias)== GRIB_SUCCESS)) {
            grib_set_double_internal(a->parent->h,self->units_bias,0.0);
        }

        if (units_factor != 1.0) {
            if (units_bias != 0.0)
                for (i=0;i<n_vals;i++) val[i]=val[i]*units_factor+units_bias;
            else
                for (i=0;i<n_vals;i++) val[i]*=units_factor;
        } else if (units_bias != 0.0)
            for (i=0;i<n_vals;i++) val[i]+=units_bias;

        if (c->ieee_packing && self->ieee_packing) {
            long precision=c->ieee_packing==32 ? 1 : 2;
            size_t lenstr=strlen(self->ieee_packing);

            packingType_s=grib_context_strdup(c,self->packingType);
            ieee_packing_s=grib_context_strdup(c,self->ieee_packing);
            precision_s=grib_context_strdup(c,self->precision);

            grib_set_string(h,packingType_s,ieee_packing_s,&lenstr);
            grib_set_long(h,precision_s,precision);

            grib_context_free(c,packingType_s);
            grib_context_free(c,ieee_packing_s);
            grib_context_free(c,precision_s);
            return grib_set_double_array(h,"values",val,*len);
        }
    }

    ret = super->pack_double(a,val,len);
    switch (ret) {
    case GRIB_CONSTANT_FIELD:
        ret=grib_get_long(a->parent->h,"constantFieldHalfByte",&constantFieldHalfByte);
        if (ret) constantFieldHalfByte=0;
        if((ret = grib_set_long_internal(a->parent->h,self->half_byte, constantFieldHalfByte))
                != GRIB_SUCCESS)
            return ret;
        grib_buffer_replace(a, NULL, 0,1,1);
        return GRIB_SUCCESS;
        break;
    case GRIB_NO_VALUES:
        ret=grib_get_long(a->parent->h,"constantFieldHalfByte",&constantFieldHalfByte);
        if (ret) constantFieldHalfByte=0;
        /* TODO move to def file */
        grib_get_double(a->parent->h,"missingValue", &missingValue);
        if((err = grib_set_double_internal(a->parent->h,self->reference_value, missingValue)) !=
                GRIB_SUCCESS)
            return err;
        if((ret = grib_set_long_internal(a->parent->h,self->binary_scale_factor, binary_scale_factor))
                != GRIB_SUCCESS)
            return ret;
        if((ret = grib_set_long_internal(a->parent->h,self->half_byte, constantFieldHalfByte))
                != GRIB_SUCCESS)
            return ret;
        grib_buffer_replace(a, NULL, 0,1,1);
        return GRIB_SUCCESS;
        break;
    case GRIB_INVALID_BPV:
        grib_context_log(a->parent->h->context,GRIB_LOG_ERROR,"unable to compute packing parameters\n");
        return ret;
    case GRIB_SUCCESS:
        break;
    default:
        grib_context_log(a->parent->h->context,GRIB_LOG_FATAL,"unable to compute packing parameters\n");
        return ret;
    }

    if((ret = grib_get_double_internal(a->parent->h,self->reference_value, &reference_value))
            != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->binary_scale_factor, &binary_scale_factor))
            != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->bits_per_value,&bits_per_value)) !=
            GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->decimal_scale_factor, &decimal_scale_factor))
            != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->offsetdata,&offsetdata)) != GRIB_SUCCESS)
        return ret;

    if((ret = grib_get_long_internal(a->parent->h,self->offsetsection,&offsetsection)) != GRIB_SUCCESS)
        return ret;

    decimal = grib_power(decimal_scale_factor,10) ;
    divisor = grib_power(-binary_scale_factor,2);

    buflen = (((bits_per_value*n_vals)+7)/8)*sizeof(unsigned char);
    if((buflen + (offsetdata-offsetsection)) %2) {
        buflen++;
        /*
    a->length++;
    a->parent->h->buffer->ulength++;
         */
    }
    half_byte = (buflen*8)-((*len)*bits_per_value);
    grib_context_log(a->parent->h->context,GRIB_LOG_DEBUG,
            "HALF byte: buflen=%d bits_per_value=%ld len=%d half_byte=%ld\n",
            buflen,bits_per_value,*len,half_byte);

    Assert(half_byte <= 0x0f);

    if((ret = grib_set_long_internal(a->parent->h,self->half_byte, half_byte))
            != GRIB_SUCCESS)
        return ret;

    buf = (unsigned char*)grib_context_buffer_malloc_clear(a->parent->h->context,buflen);
    encoded = buf;

    grib_encode_double_array(n_vals,val,bits_per_value,reference_value,decimal,divisor,encoded,&off);

    grib_context_log(a->parent->h->context, GRIB_LOG_DEBUG,
            "grib_accessor_data_g1simple_packing : pack_double : packing %s, %d values", a->name, n_vals);

    grib_buffer_replace(a, buf, buflen,1,1);

    grib_context_buffer_free(a->parent->h->context,buf);

    return GRIB_SUCCESS;
}
static int unpack_double(grib_accessor* a, double* values, size_t *len)
{
  grib_accessor_data_g1second_order_row_by_row_packing* self =  (grib_accessor_data_g1second_order_row_by_row_packing*)a;
  int ret=0;
  long numberOfGroups,numberOfSecondOrderPackedValues;
  long* groupWidths=0;
  long* firstOrderValues=0;
  long* X=0;
  long numberOfRows,numberOfColumns;
  long *numbersPerRow;
  long pos=0;
  long widthOfFirstOrderValues=0;
  long jPointsAreConsecutive;
  unsigned char* buf = (unsigned char*)a->parent->h->buffer->data;
  long k,i,j,n,Ni,Nj;
  double reference_value;
  long binary_scale_factor;
  long decimal_scale_factor;
  double s,d;
  size_t groupWidthsSize=0;
  int bitmapPresent=0;
  size_t plSize=0;
  long* pl=0;

  buf += grib_byte_offset(a);

  if((ret=grib_get_long_internal(a->parent->h,self->numberOfGroups,&numberOfGroups)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(a->parent->h,self->jPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS)
         return ret;

  if (self->bitmap) bitmapPresent=1;
  ret=grib_get_size(a->parent->h,self->pl,&plSize);
  if (ret==GRIB_SUCCESS) {
	  pl=grib_context_malloc_clear(a->parent->h->context,sizeof(long)*plSize);
	  if((ret=grib_get_long_array(a->parent->h,self->pl,pl,&plSize)) != GRIB_SUCCESS)
         return ret;
  }

  if((ret=grib_get_long_internal(a->parent->h,self->Ni,&Ni)) != GRIB_SUCCESS)
         return ret;
  if((ret=grib_get_long_internal(a->parent->h,self->Nj,&Nj)) != GRIB_SUCCESS)
         return ret;
  if (jPointsAreConsecutive) {
  	numberOfRows=Ni;
	numberOfColumns=Nj;
  } else {
  	numberOfRows=Nj;
	numberOfColumns=Ni;
  }

  numbersPerRow=grib_context_malloc_clear(a->parent->h->context,sizeof(long)*numberOfRows);
  if (bitmapPresent) {
	long *bitmap,*pbitmap;
	size_t numberOfPoints=Ni*Nj;

  	if (plSize) {
		numberOfPoints=0;
		for (i=0;i<numberOfRows;i++) numberOfPoints+=pl[i];
	} 
	bitmap=grib_context_malloc_clear(a->parent->h->context,sizeof(long)*numberOfPoints);
	pbitmap=bitmap;
	grib_get_long_array(a->parent->h,self->bitmap,bitmap,&numberOfPoints);
  	if (plSize) {
		for (i=0;i<numberOfRows;i++) {
			for (j=0;j<pl[i];j++) {
				numbersPerRow[i]+=*(bitmap++);
			}
		}
	} else {
		for (i=0;i<numberOfRows;i++) {
			numbersPerRow[i]=0;
			for (j=0;j<Ni;j++) {
				numbersPerRow[i]+=*(bitmap++);
			}
		}
	}

	grib_context_free(a->parent->h->context,pbitmap);
  } else {
  	if (plSize) {
		for (i=0;i<numberOfRows;i++) numbersPerRow[i]=pl[i];
	} else {
		for (i=0;i<numberOfRows;i++) 
			numbersPerRow[i]=numberOfColumns;
	}
  }

  if((ret=grib_get_long_internal(a->parent->h,self->widthOfFirstOrderValues,&widthOfFirstOrderValues)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(a->parent->h,self->binary_scale_factor,&binary_scale_factor)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(a->parent->h,self->decimal_scale_factor,&decimal_scale_factor)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_double_internal(a->parent->h,self->reference_value,&reference_value)) != GRIB_SUCCESS)
         return ret;

  if((ret=grib_get_long_internal(a->parent->h,self->numberOfSecondOrderPackedValues,
  					&numberOfSecondOrderPackedValues)) != GRIB_SUCCESS)
         return ret;

  groupWidths=grib_context_malloc_clear(a->parent->h->context,sizeof(long)*numberOfGroups);
  groupWidthsSize=numberOfGroups;
  if((ret=grib_get_long_array_internal(a->parent->h,self->groupWidths, groupWidths,&groupWidthsSize)) != GRIB_SUCCESS)
         return ret;

	firstOrderValues=grib_context_malloc_clear(a->parent->h->context,sizeof(long)*numberOfGroups);
	grib_decode_long_array(buf,&pos,widthOfFirstOrderValues,numberOfGroups,firstOrderValues);
	pos = 8 * ( (pos + 7 ) / 8);

	X=grib_context_malloc_clear(a->parent->h->context,sizeof(long)*numberOfSecondOrderPackedValues);
	n=0;
	k=0;
	for (i=0; i<numberOfGroups; i++) {
		if (groupWidths[i]>0) {
				for (j=0;j<numbersPerRow[k];j++) {
					X[n]=grib_decode_unsigned_long(buf,&pos,groupWidths[i]);
					X[n]+=firstOrderValues[i];
					n++;
				}
		} else {
				for (j=0;j<numbersPerRow[k];j++) {
					X[n]=firstOrderValues[i];
					n++;
				}
		}
		k++;
	}

	s = grib_power(binary_scale_factor,2);
	d = grib_power(-decimal_scale_factor,10) ;
	for (i=0; i<n; i++) {
		values[i] = (double) (((X[i]*s)+reference_value)*d);
	}
	grib_context_free(a->parent->h->context,firstOrderValues);
	grib_context_free(a->parent->h->context,X);
	grib_context_free(a->parent->h->context,groupWidths);
	if (plSize) grib_context_free(a->parent->h->context,pl);
  
  return ret;
}