/**********************************************************************
 * convert_minicbf -- convert a minimal cbf to a full cbf file        *
 *                                                                    *
 * Version 0.9.6 29 November 2012                                      *
 *                                                                    *
 *                          Paul Ellis and                            *
 *         Herbert J. Bernstein (yaya@bernstein-plus-sons.com)        *
 *                                                                    *
 * (C) Copyright 2006, 2007, 2012 Herbert J. Bernstein                *
 *                                                                    *
 **********************************************************************/

/**********************************************************************
 *                                                                    *
 * YOU MAY REDISTRIBUTE THE CBFLIB PACKAGE UNDER THE TERMS OF THE GPL *
 * WHILE YOU MAY ALTERNATIVELY DISTRIBUTE THE API UNDER THE LGPL      *
 * YOU MAY ***NOT*** DISTRIBUTE THIS PROGRAM UNDER THE LGPL           *
 *                                                                    *                                                                    *
 **********************************************************************/

/*************************** GPL NOTICES ******************************
 *                                                                    *
 * This program is free software; you can redistribute it and/or      *
 * modify it under the terms of the GNU General Public License as     *
 * published by the Free Software Foundation; either version 2 of     *
 * (the License, or (at your option) any later version.               *
 *                                                                    *
 * This program is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
 * GNU General Public License for more details.                       *
 *                                                                    *
 * You should have received a copy of the GNU General Public License  *
 * along with this program; if not, write to the Free Software        *
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA           *
 * 02111-1307  USA                                                    *
 *                                                                    *
 **********************************************************************/


/**********************************************************************
 *                                                                    *
 *                    Stanford University Notices                     *
 *  for the CBFlib software package that incorporates SLAC software   *
 *                 on which copyright is disclaimed                   *
 *                                                                    *
 * This software                                                      *
 * -------------                                                      *
 * The term 'this software', as used in these Notices, refers to      *
 * those portions of the software package CBFlib that were created by *
 * employees of the Stanford Linear Accelerator Center, Stanford      *
 * University.                                                        *
 *                                                                    *
 * Stanford disclaimer of copyright                                   *
 * --------------------------------                                   *
 * Stanford University, owner of the copyright, hereby disclaims its  *
 * copyright and all other rights in this software.  Hence, anyone    *
 * may freely use it for any purpose without restriction.             *
 *                                                                    *
 * Acknowledgement of sponsorship                                     *
 * ------------------------------                                     *
 * This software was produced by the Stanford Linear Accelerator      *
 * Center, Stanford University, under Contract DE-AC03-76SFO0515 with *
 * the Department of Energy.                                          *
 *                                                                    *
 * Government disclaimer of liability                                 *
 * ----------------------------------                                 *
 * Neither the United States nor the United States Department of      *
 * Energy, nor any of their employees, makes any warranty, express or *
 * implied, or assumes any legal liability or responsibility for the  *
 * accuracy, completeness, or usefulness of any data, apparatus,      *
 * product, or process disclosed, or represents that its use would    *
 * not infringe privately owned rights.                               *
 *                                                                    *
 * Stanford disclaimer of liability                                   *
 * --------------------------------                                   *
 * Stanford University makes no representations or warranties,        *
 * express or implied, nor assumes any liability for the use of this  *
 * software.                                                          *
 *                                                                    *
 * Maintenance of notices                                             *
 * ----------------------                                             *
 * In the interest of clarity regarding the origin and status of this *
 * software, this and all the preceding Stanford University notices   *
 * are to remain affixed to any copy or derivative of this software   *
 * made or distributed by the recipient and are to be affixed to any  *
 * copy of software made or distributed by the recipient that         *
 * contains a copy or derivative of this software.                    *
 *                                                                    *
 * Based on SLAC Software Notices, Set 4                              *
 * OTT.002a, 2004 FEB 03                                              *
 **********************************************************************/


/**********************************************************************
 *                                 NOTICE                             *
 * Creative endeavors depend on the lively exchange of ideas. There   *
 * are laws and customs which establish rights and responsibilities   *
 * for authors and the users of what authors create.  This notice     *
 * is not intended to prevent you from using the software and         *
 * documents in this package, but to ensure that there are no         *
 * misunderstandings about terms and conditions of such use.          *
 *                                                                    *
 * Please read the following notice carefully.  If you do not         *
 * understand any portion of this notice, please seek appropriate     *
 * professional legal advice before making use of the software and    *
 * documents included in this software package.  In addition to       *
 * whatever other steps you may be obliged to take to respect the     *
 * intellectual property rights of the various parties involved, if   *
 * you do make use of the software and documents in this package,     *
 * please give credit where credit is due by citing this package,     *
 * its authors and the URL or other source from which you obtained    *
 * it, or equivalent primary references in the literature with the    *
 * same authors.                                                      *
 *                                                                    *
 * Some of the software and documents included within this software   *
 * package are the intellectual property of various parties, and      *
 * placement in this package does not in any way imply that any       *
 * such rights have in any way been waived or diminished.             *
 *                                                                    *
 * With respect to any software or documents for which a copyright    *
 * exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT.   *
 *                                                                    *
 * Even though the authors of the various documents and software      *
 * found here have made a good faith effort to ensure that the        *
 * documents are correct and that the software performs according     *
 * to its documentation, and we would greatly appreciate hearing of   *
 * any problems you may encounter, the programs and documents any     *
 * files created by the programs are provided **AS IS** without any   *
 * warranty as to correctness, merchantability or fitness for any     *
 * particular or general use.                                         *
 *                                                                    *
 * THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF    *
 * PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE   *
 * PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS   *
 * OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE          *
 * PROGRAMS OR DOCUMENTS.                                             *
 **********************************************************************/

/**********************************************************************
 *                                                                    *
 *                           The IUCr Policy                          *
 *      for the Protection and the Promotion of the STAR File and     *
 *     CIF Standards for Exchanging and Archiving Electronic Data     *
 *                                                                    *
 * Overview                                                           *
 *                                                                    *
 * The Crystallographic Information File (CIF)[1] is a standard for   *
 * information interchange promulgated by the International Union of  *
 * Crystallography (IUCr). CIF (Hall, Allen & Brown, 1991) is the     *
 * recommended method for submitting publications to Acta             *
 * Crystallographica Section C and reports of crystal structure       *
 * determinations to other sections of Acta Crystallographica         *
 * and many other journals. The syntax of a CIF is a subset of the    *
 * more general STAR File[2] format. The CIF and STAR File approaches *
 * are used increasingly in the structural sciences for data exchange *
 * and archiving, and are having a significant influence on these     *
 * activities in other fields.                                        *
 *                                                                    *
 * Statement of intent                                                *
 *                                                                    *
 * The IUCr's interest in the STAR File is as a general data          *
 * interchange standard for science, and its interest in the CIF,     *
 * a conformant derivative of the STAR File, is as a concise data     *
 * exchange and archival standard for crystallography and structural  *
 * science.                                                           *
 *                                                                    *
 * Protection of the standards                                        *
 *                                                                    *
 * To protect the STAR File and the CIF as standards for              *
 * interchanging and archiving electronic data, the IUCr, on behalf   *
 * of the scientific community,                                       *
 *                                                                    *
 * * holds the copyrights on the standards themselves,                *
 *                                                                    *
 * * owns the associated trademarks and service marks, and            *
 *                                                                    *
 * * holds a patent on the STAR File.                                 *
 *                                                                    *
 * These intellectual property rights relate solely to the            *
 * interchange formats, not to the data contained therein, nor to     *
 * the software used in the generation, access or manipulation of     *
 * the data.                                                          *
 *                                                                    *
 * Promotion of the standards                                         *
 *                                                                    *
 * The sole requirement that the IUCr, in its protective role,        *
 * imposes on software purporting to process STAR File or CIF data    *
 * is that the following conditions be met prior to sale or           *
 * distribution.                                                      *
 *                                                                    *
 * * Software claiming to read files written to either the STAR       *
 * File or the CIF standard must be able to extract the pertinent     *
 * data from a file conformant to the STAR File syntax, or the CIF    *
 * syntax, respectively.                                              *
 *                                                                    *
 * * Software claiming to write files in either the STAR File, or     *
 * the CIF, standard must produce files that are conformant to the    *
 * STAR File syntax, or the CIF syntax, respectively.                 *
 *                                                                    *
 * * Software claiming to read definitions from a specific data       *
 * dictionary approved by the IUCr must be able to extract any        *
 * pertinent definition which is conformant to the dictionary         *
 * definition language (DDL)[3] associated with that dictionary.      *
 *                                                                    *
 * The IUCr, through its Committee on CIF Standards, will assist      *
 * any developer to verify that software meets these conformance      *
 * conditions.                                                        *
 *                                                                    *
 * Glossary of terms                                                  *
 *                                                                    *
 * [1] CIF:  is a data file conformant to the file syntax defined     *
 * at http://www.iucr.org/iucr-top/cif/spec/index.html                *
 *                                                                    *
 * [2] STAR File:  is a data file conformant to the file syntax       *
 * defined at http://www.iucr.org/iucr-top/cif/spec/star/index.html   *
 *                                                                    *
 * [3] DDL:  is a language used in a data dictionary to define data   *
 * items in terms of "attributes". Dictionaries currently approved    *
 * by the IUCr, and the DDL versions used to construct these          *
 * dictionaries, are listed at                                        *
 * http://www.iucr.org/iucr-top/cif/spec/ddl/index.html               *
 *                                                                    *
 * Last modified: 30 September 2000                                   *
 *                                                                    *
 * IUCr Policy Copyright (C) 2000 International Union of              *
 * Crystallography                                                    *
 **********************************************************************/

/**********************************************************************
 *                            SYNOPSIS                                *
 *                                                                    *
 *  convert_minicbf [-i input_cbf] [-o output_cbf] [-p template_cbf]\ *
 *    [-q] [-C convention]                                        \   *
 *    [-d detector name]  -m [x|y|x=y] [-z distance]              \   *
 *    [-c category_alias=category_root]*                          \   *
 *    [-t tag_alias=tag_root]* [-F] [-R]                          \   *
 *    [input_cbf] [output_cbf]                                        *
 *                                                                    *
 *  the options are:                                                  *
 *                                                                    *
 *  -i input_cbf (default: stdin)                                     *
 *    the input file as a CBF with at least an image.                 *
 *                                                                    *
 *  -p template_cbf                                                   *
 *    the template for the final cbf to be produced.  If template_cbf *
 *    is not specified the name is constructed from the first token   *
 *    of the detector name and the image size as                      *
 *       template_<type>_<columns>x<rows>.cbf                         *
 *                                                                    *
 *  -o output_cbf (default: stdout )                                  *
 *    the output cbf combining the image and the template.  If the    *
 *    output_cbf is not specified or is given as "-", it is written   *
 *    to stdout.                                                      *
 *                                                                    *
 *  -q                                                                *
 *    exit quickly with just the miniheader expanded                  *
 *    after the data.  No template is used.                           *
 *                                                                    *
 *  -Q                                                                *
 *    exit quickly with just the miniheader unexpanded                *
 *    before the data.  No template is used.                          *
 *                                                                    *
 *  -C convention                                                     *
 *    convert the comment form of miniheader into the                 *
 *        _array_data.header_convention convention                    *
 *        _array_data.header_contents                                 *
 *    overriding any existing values                                  *
 *                                                                    *
 *  -d detectorname                                                   *
 *    a detector name to be used if none is provided in the image     *
 *    header.                                                         *
 *                                                                    *
 *  -F                                                                *
 *    when writing packed compression, treat the entire image as      *
 *    one line with no averaging                                      *
 *                                                                    *
 *  -m [x|y|x=y] (default x=y, square arrays only)                    *
 *    mirror the array in the x-axis (y -> -y)                        *
 *                     in the y-axis (x -> -x)                        *
 *                  or in x=y ( x -> y, y-> x)                        *
 *                                                                    *
 *  -r n                                                              *
 *    rotate the array n times 90 degrees counter clockwise           *
 *    x -> y, y -> -x for each rotation, n = 1, 2 or 3                *
 *                                                                    *
 *  -R                                                                *
 *    if setting a beam center, set reference values of               *
 *    axis settings as well as standard settings                      *
 *                                                                    *
 *  -v version_number \n");                                           *
 *    set the output version to version_number (default 2).\n");      *
 *                                                                    *
 *  -z distance                                                       *
 *    detector distance along Z-axis                                  *
 *                                                                    *
 *  -c category_alias=category_root                                   *
 *  -t tag_alias=tagroot                                              *
 *    map the given alias to the given root, so that instead          *
 *    of outputting the alias, the root will be presented in the      *
 *    output cbf instead.  These options may be repeated as many      *
 *    times as needed.                                                *
 *                                                                    *
 **********************************************************************/


#include "cbf.h"
#include "cbf_simple.h"
#include "cbf_string.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <errno.h>
#include "cbf_getopt.h"
#include <unistd.h>

#define CVTBUFSIZ 8192

#ifdef __MINGW32__
#define NOMKSTEMP
#define NOTMPDIR
#endif

int outusage ( void );
double rint(double);
int local_exit (int status);
int outerror(int err);

int version_number;
char slsbuf[2049];  /* The currently active header string */
int lineno;         /* The current header line number */


/* parse a string from an sls comment style header and
 add it to cbf
 
 The strings specified by E. Eikenberry as of 13 June 2007
 are:
 
 # Detector: PILATUS 6M SN01
 # 2007/Jun/13 13:13:16.286
 # Pixel_size 172e-6 m x 172e-6 m
 # Silicon sensor, thickness 0.000320 m
 # Exposure_time 0.095000 s
 # Exposure_period 0.100000 s
 # Tau = 0 s
 # Count_cutoff 1048575 counts
 # Threshold_setting 0 eV
 # Wavelength 0.7085 A
 # Energy_range (0, 0) eV
 # Detector_distance 0.79988 m
 # Detector_Voffset -0.00002 m
 # Beam_xy (1231.50, 1263.50) pixels
 # Flux 0 ph/s
 # Filter_transmission 1.0000
 # Start_angle 0.0900 deg.
 # Angle_increment 0.0100 deg.
 # Detector_2theta 0.0000 deg.
 # Polarization 0.950
 # Alpha 0.0000 deg.
 # Kappa 0.0000 deg.
 # Phi 0.0000 deg.
 # Chi 0.0000 deg.
 # Oscillation_axis  X, CW
 # N_oscillations 1
 
 Those strings were modified in subsequent Pilatus
 software.  As of 13 October 2012, the units of Flux
 may not appear.  In addition, the date format has
 changed to 2011-­‐07-­‐22T17:33:22.529, and the
 following strings have been added:
 
 # Gain_setting: low gain (vrf = -0.300)
 # N_excluded_pixels = 293
 # Excluded_pixels: badpix_mask.tif
 # Flat_field: FF_p2m0109_E15000_T7500_vrf_m0p30.tif
 # Trim_file: p2m0109_E15000_T7500_vrf_m0p30.bin
 # Image_path: /ramdisk/e13295/20120404/6D/BCW/1947_9_3/short/15kev/
 # Phi_increment 0.0000 deg.
 # Chi_increment 0.0000 deg.
 # Start_position 0.0000 mm
 # Position_increment 0.0000 mm
 # Shutter_time 0.095000 s
 
 */


#undef cbf_failnez
#define cbf_failnez(x) \
{int err; \
err = (x); \
if (err) { \
fprintf(stderr," convert_minicbf: CBFlib fatal error %d\n",err); \
outerror(err);   \
outusage();      \
local_exit (-1); \
} \
}


void cnvminicbf_warn( char * s ) {
    
    fprintf(stderr," convert_minicbf: warning (header line %d) %s\n\"%s\"\n",
            lineno,s,slsbuf);
    
    return;
    
}


    
#define cbf_set_value_from_string(cbf,cbfstring,cbfcat,cbfcol)   \
\
cbf_failnez(cbf_require_category((cbf),(cbfcat)))            \
\
while (*(cbfstring) && isspace(*(cbfstring))) (cbfstring)++; \
\
cbf_failnez(cbf_require_column((cbf),(cbfcol)))              \
\
if (!cbf_get_value((cbf),(const char **)&valstr) && valstr && *valstr){\
\
if (strlen(valstr)+strlen((cbfstring))<4095) {             \
\
if (*valstr != '\n') {                                   \
\
strcpy(valbuf,"\n"); strcat(valbuf,valstr);            \
\
} else {                                                 \
\
strcpy(valbuf,valstr);                                 \
\
}                                                        \
\
strcat(valbuf,"\n"); strcat(valbuf,cbfstring);           \
\
cbf_failnez(cbf_set_value((cbf),valbuf))                 \
\
} else {                                                   \
\
return CBF_FORMAT;                                       \
\
}                                                          \
\
\
} else {                                                     \
\
cbf_failnez(cbf_set_value((cbf),(cbfstring)))              \
\
}                                                            \

#define cbf_set_doublevalue_from_string(cbf,cbfstring,cbfcat,cbfcol,unit)   \
\
  cbf_failnez(cbf_require_category((cbf),(cbfcat)))          \
\
  while (*(cbfstring) && isspace(*(cbfstring))) (cbfstring)++;\
\
  tempdouble = strtod(cbfstring,&tempendptr);                \
\
  cbfstring = tempendptr;                                    \
\
  while (*(cbfstring) && isspace(*(cbfstring))) (cbfstring)++;\
\
  if (cbfstring && *cbfstring) {                             \
\
    if (! cbf_scale_units(cbfstring, unit, &unitsratio)) { \
\
      tempdouble *= unitsratio;                            \
\
    } else {                                               \
\
      cnvminicbf_warn("specified units not recognized and not used"); \
\
    }                                                      \
\
  }                                                        \
\
  cbf_failnez(cbf_require_column((cbf),(cbfcol)))          \
\
  cbf_failnez(cbf_set_doublevalue((cbf),"%-15g",tempdouble))



int cbf_parse_sls_header(cbf_handle cbf, const char * buffer,
                         int commentflg) {
    
    double pscalex=1., pscaley=1.;
    
    double bcx, bcy, bcscalex, bcscaley, erlow, erhigh;
    
    double tempdouble, unitsratio;
    
    char * tempendptr;
    
    char * slsstr;
    
    const char * valstr;
        
    char valbuf[4097];
    
    char mxunits[33], myunits[33];
    
    static const char *monthname [] =
    
    { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    
    
    lineno = 0;
    
    while(*buffer) {
        
        slsstr = (char *)slsbuf;
        
        while(*buffer && (*buffer!='\r') && (*buffer!='\n') && (slsstr-slsbuf)<2047) *slsstr++=*buffer++;
        
        if (*buffer=='\r' && buffer[1] == '\n' ) buffer++;
        
        if (*buffer=='\r' || *buffer=='\n') buffer++;
        
        lineno++;
        
        while(slsstr != slsbuf && isspace(*(slsstr-1))) slsstr--;
        
        *slsstr='\0';
        
        slsstr = (char *)slsbuf;
        
        /* skip all initial whitespace */
        
        while (*slsstr && isspace(*slsstr)) slsstr++;
        
        if (strlen(slsstr) == 0) {
            
            while (*buffer && ((*buffer=='\r') || (*buffer=='\n'))) buffer++;
            
            continue;
            
        }
        
#ifdef DEBUG
        fprintf(stderr,"Processing %s\n",slsstr);
#endif
        
        /* if we have specified that this must be a comment
         require a leading "# " abort if not                        */
        
        if (commentflg) {
            if (strlen(slsstr) < 2
                || slsstr[0] != '#'
                || !isspace(slsstr[1])) {
                cnvminicbf_warn(" line fails to start with \"# \"");
            }  else {
              slsstr += 2;
            }
        }
        
        
        while (*slsstr && isspace(*slsstr)) slsstr++;
        
        if (slsstr[0] == '#') {
            
            slsstr++;
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
        }
        
        /* check for   Detector: PILATUS 6M SN01 */
        
        if (!cbf_cistrncmp(slsstr,"Detector: ",strlen("Detector: "))) {
            
            char * ptr;
            
            slsstr += strlen("Detector: ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            ptr = slsstr;
            
            while (*ptr && (cbf_cistrncmp(ptr," SN",3))&&(cbf_cistrncmp(ptr," S/N",4))) ptr++;
            
            if (ptr!= slsstr && ptr[-1] == ',') ptr[-1] = 0;
            
            if (*ptr) *ptr++ = 0;
            
            while (*ptr && isspace(*ptr)) ptr++;
            
            if (version_number != 1) {
                  
              cbf_set_value_from_string(cbf,slsstr,"diffrn_detector","type")
            
            }
            
            cbf_set_value_from_string(cbf,ptr,"diffrn_detector","details")
            
            
        } else
            
        /* check for 2007/Jun/13 13:13:16.286 */
            
        if (strlen(slsstr)>=11
            && (slsstr[4]=='/' || slsstr[4]=='-' )
            && (slsstr[7]=='/' || slsstr[7]=='-' ||
            slsstr[8]=='/' || slsstr[8]=='-') ){
            
            char *endptr;
            
            int errflg;
            
            int notime;
            
            int yyyy,mm,dd,hr,mn;
            
            double ss;
            
            errflg = 0;
            
            yyyy = strtol(slsstr,&endptr,10);
            
            if (*endptr == '/' || *endptr == '-') {
                
                slsstr = endptr+1;
                
                if (isdigit(slsstr[0])&&isdigit(slsstr[1]) &&
                    (slsstr[2]=='/'||slsstr[2]=='-')) {
                    
                    mm = strtol(slsstr,&endptr,10);
                    
                } else {
                    
                    for (mm = 1; mm < 13; mm++) {
                        
                        if (!cbf_cistrncmp(monthname[mm-1],slsstr,3)) break;
                        
                    }
                    
                    endptr = slsstr+3;
                    
                }
                
                if (mm > 12) errflg++;
                
                else {
                    
                    slsstr = endptr+1;
                    
                    dd = strtol(slsstr,&endptr,10);
                    
                    hr = mn = ss =  0; notime=1;
                    
                    if (*endptr && (isspace(*endptr)||*endptr=='T'||*endptr=='t'||*endptr==':')) {
                        
                        slsstr = endptr+1;
                        
                        hr = strtol(slsstr,&endptr,10);
                        
                        if (*endptr == ':') {
                            
                            notime = 0;
                            
                            slsstr = endptr+1;
                            
                            mn = strtol(slsstr,&endptr,10);
                            
                            if (*endptr==':') {
                                
                                slsstr = endptr+1;
                                
                                ss = strtod(slsstr,&endptr);
                                
                            }
                            
                        }
                        
                    }
                    
                }
                
            } else errflg++;
            
            if (!errflg) {
                
                cbf_failnez (cbf_set_datestamp (cbf, 0, yyyy, mm, dd,
                                                hr, mn, ss,
                                                CBF_NOTIMEZONE,.001))
                
            }
            
        } else
                    
                /* check for Pixel_size 172e-6 m x 172e-6 m */
                    
        if (!cbf_cistrncmp(slsstr,"Pixel_size ",strlen("Pixel_size "))) {
            
            char *endptr;
            
            double psx, psy;
            
            slsstr += strlen("Pixel_size ");
            
            pscalex = pscaley = 1.;
            
            psy = psx = strtod (slsstr, &endptr);
            
            if (endptr && *endptr) {
                
                slsstr = endptr;
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                if (!cbf_cistrncmp("m ",slsstr,2))  slsstr += 2;
                
                else if (!cbf_cistrncmp("mm ",slsstr,2) || !cbf_cistrcmp("mm",slsstr)) {
                    
                    slsstr +=2;
                    
                    pscaley = pscalex = 1.e-3;
                    
                } else  {
                    
                    pscaley = pscalex = 1.e-6;
                    
                }
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                if (*slsstr == 'x' || *slsstr == 'X' || *slsstr==',') {
                    
                    slsstr++;
                    
                    while (*slsstr && isspace(*slsstr)) slsstr++;
                    
                }
                
                if (*slsstr) {
                    
                    psy = strtod (slsstr, &endptr);
                    
                    if (endptr && *endptr) {
                        
                        slsstr = endptr;
                        
                        while (*slsstr && isspace(*slsstr)) slsstr++;
                        
                        if (!cbf_cistrncmp("m ",slsstr,2)|| !cbf_cistrcmp("m",slsstr))  slsstr ++;
                        
                        else if ( !cbf_cistrncmp("mm ",slsstr,2) || !cbf_cistrcmp("mm",slsstr) ) {
                            
                            slsstr +=2;
                            
                            pscaley = 1.e-3;
                            
                        } else  {
                            
                            pscaley = 1.e-6;
                            
                        }
                        
                    }
                    
                }
                
            }
            
            psx *= pscalex;
            
            psy *= pscaley;
            
            cbf_failnez(cbf_require_category(cbf,"array_element_size"))
            
            cbf_failnez(cbf_require_column(cbf,"index"))
            
            cbf_failnez(cbf_set_integervalue(cbf,1))
            
            cbf_failnez(cbf_require_column(cbf,"size"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",psx))
            
            cbf_failnez(cbf_next_row(cbf))
            
            cbf_failnez(cbf_require_column(cbf,"index"))
            
            cbf_failnez(cbf_set_integervalue(cbf,2))
            
            cbf_failnez(cbf_require_column(cbf,"size"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",psy))
            
        } else
                        
                /* Check for Silicon sensor, thickness 0.000320 m */
                    
        if  (!cbf_cistrncmp(slsstr,"Silicon sensor, thickness ",strlen("Silicon sensor, thickness "))) {
            
            if (version_number==1) {
            
              cbf_set_value_from_string(cbf,slsstr,"diffrn_detector","details")
                
            } else {
                
              slsstr += strlen("Silicon sensor, thickness ");
                
              cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_detector","layer_thickness","mm")
                
            }
            
        } else
 
            
        /* N_excluded_pixels = 293 */
            
        if  (version_number != 1 && !cbf_cistrncmp(slsstr,"N_excluded_pixels",strlen("N_excluded_pixels"))) {
            
            cbf_set_value_from_string(cbf,slsstr,"diffrn_detector","details")
                
        } else
            
        /* Excluded_pixels: badpix_mask.tif */
            
        if  (version_number != 1 && !cbf_cistrncmp(slsstr,"Excluded_pixels",strlen("Excluded_pixels"))) {
            
            cbf_set_value_from_string(cbf,slsstr,"diffrn_detector","details")
                
        } else

        /* Flat_field: FF_p2m0109_E15000_T7500_vrf_m0p30.tif */
            
        if  (version_number != 1 && !cbf_cistrncmp(slsstr,"Flat_field",strlen("Flat_field"))) {
            
            cbf_set_value_from_string(cbf,slsstr,"diffrn_detector","details")
                
        } else

        /* Trim_file: p2m0109_E15000_T7500_vrf_m0p30.bin */
            
        if  (version_number != 1 && !cbf_cistrncmp(slsstr,"Trim_file",strlen("Trim_file"))) {
            
            cbf_set_value_from_string(cbf,slsstr,"diffrn_detector","details")
                
        } else

        /* Image_path: /ramdisk/e13295/20120404/6D/BCW/1947_9_3/short/15kev/ */
            
        if  (version_number != 1 && !cbf_cistrncmp(slsstr,"Image_path",strlen("Image_path"))) {
                
            cbf_set_value_from_string(cbf,slsstr,"diffrn_detector","details")
                
        } else

        /* check for Exposure_time 0.095000 s */
                            
        if (!cbf_cistrncmp(slsstr,"Exposure_time ",strlen("Exposure time "))) {
            
            slsstr += strlen("Exposure time: ");
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_scan_frame","integration_time","s")
            
        } else
                                
        /* check for Exposure_period 0.100000 s */
            
        if (version_number !=1 && !cbf_cistrncmp(slsstr,"Exposure_period ",strlen("Exposure_period "))) {
            
            slsstr += strlen("Exposure_period ");
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_scan_frame","integration_period","s")
            
        }  else
                                    
        /* check for Tau = 0 s */
                    
        if (!cbf_cistrncmp(slsstr,"Tau = ",strlen("Tau = "))) {
            
            slsstr += strlen("Tau = ");
            
            if (version_number == 1) {
            
              cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_radiation","tau","s")
                
            } else {
                
              cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_detector","dtime","us")
                
            }
            
        } else
                                        
        /* check for Count_cutoff 1048575 counts */
            
        if (!cbf_cistrncmp(slsstr,"Count_cutoff ",
                           
                           strlen("Count_cutoff "))) {
            
            slsstr += strlen("Count_cutoff ");
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"array_intensities","overload","counts")
            
        } else

        /* check for Gain_setting: low gain (vrf = -0.300) */
            
            if (!cbf_cistrncmp(slsstr,"Gain_setting",
                               
                               strlen("Gain_setting"))) {
                
                 
                cbf_set_value_from_string(cbf,slsstr,"array_intensities","details")
                
            } else

        /* check for Threshold_setting 0 eV */
        
        if (version_number !=1 && (!cbf_cistrncmp(slsstr,"Threshold_setting ",
                           
                           strlen("Threshold_setting "))
            
            || !cbf_cistrncmp(slsstr,"Threshold_setting:",
                              
                              strlen("Threshold_setting:")))) {
            
            slsstr += strlen("Threshold_setting ");
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_detector","threshold","eV")
            
        } else
                                                
        /* check for Wavelength 0.7085 A */
        
        if (!cbf_cistrncmp(slsstr,"wavelength ",strlen("wavelength "))) {
            
            slsstr += strlen("wavelength ");
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_radiation_wavelength","wavelength","A")
            
        } else
                                                    
        /* check for Energy_range (0, 0) eV */
            
        if (version_number !=1 && !cbf_cistrncmp(slsstr,"Energy_range ",
           strlen("Energy_range "))) {
            
            char *endptr;
            
            slsstr += strlen("Energy_range ");
            
            erlow = erhigh = 0.;
            
            if (*slsstr == '(' || *slsstr == '[' || *slsstr == '{') slsstr++;
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            erlow = erhigh = strtod (slsstr, &endptr);
            
            if (endptr && *endptr) {
                
                slsstr = endptr;
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                if (*slsstr == ',' ) slsstr++;
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                if (*slsstr) {
                    
                    erhigh = strtod (slsstr, &endptr);
                    
                    if (endptr && *endptr) slsstr = endptr;
                    
                    while (*slsstr && isspace(*slsstr)) slsstr++;
                    
                }
                
            }
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            if (*slsstr == ')' || *slsstr == ']' || *slsstr == '}') slsstr++;
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            if (!cbf_cistrncmp("eV",slsstr,2)) {
                
                cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
                
                cbf_failnez(cbf_require_column(cbf,"energy_range_low"))
                
                cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",erlow))
                
                cbf_failnez(cbf_require_column(cbf,"energy_range_high"))

                cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",erhigh))
                
            } else {
                
                cbf_failnez(CBF_FORMAT);
                
            }
            
        }  else
        
        /* check for Detector_distance 0.79988 m */
        
        if (!cbf_cistrncmp(slsstr,"Detector_distance ",
                           strlen("Detector_distance "))) {
            
            slsstr += strlen("Detector_distance ");
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_measurement",
                                            "sample_detector_distance", "mm");
            
        }  else
                                                            
        /* check for Detector_Voffset -0.00002 m */
        
        if (!cbf_cistrncmp(slsstr,"Detector_Voffset ",
                           strlen("Detector_Voffset "))) {
            
            slsstr += strlen("Detector_Voffset ");
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_measurement",
                                            "sample_detector_voffset", "mm");
            
        }  else
                                                                
        /* check for Beam_xy (1231.50, 1263.50) pixels */
            
        if (!cbf_cistrncmp(slsstr,"beam_xy ",
                           strlen("beam_xy "))) {
            
            char *endptr;
            
            char *bcunits;
            
            slsstr += strlen("beam_xy ");
            
            bcscalex = bcscaley = 1.;
            
            bcunits = "unknown";
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            if (*slsstr == '(' || *slsstr == '[' || *slsstr == '{') slsstr++;
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            bcy = bcx = strtod (slsstr, &endptr);
            
            if (endptr && *endptr) {
                
                slsstr = endptr;
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                endptr = mxunits;
                
                while ((endptr-mxunits)<32
                       && *slsstr
                       && *slsstr!=','
                       && *slsstr!=')'
                       && *slsstr!=']'
                       && *slsstr!='}'
                       && !(isspace(*slsstr))
                       && !(isdigit(*slsstr))) *endptr++=*slsstr++;
                
                *endptr='\0';
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                if (!cbf_scale_units(mxunits, "mm",&bcscalex)) {
                    
                    bcscaley = bcscalex;
                    
                    bcunits = "mm";
                    
                } else if (!cbf_scale_units(mxunits, "pixels",&bcscalex)) {
                    
                    bcscaley = bcscalex;
                    
                    bcunits = "pixels";
                    
                } else if (!cbf_scale_units(mxunits, "bins",&bcscalex)) {
                    
                    bcscaley = bcscalex;
                    
                    bcunits = "bins";
                    
                } else {
                    
                    bcscaley = bcscalex = 1.;
                    
                    bcunits = mxunits;
                    
                }
                
                if (*slsstr == ',' ) slsstr++;
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                if (*slsstr) {
                    
                    bcy = strtod (slsstr, &endptr);
                    
                    while (*slsstr && isspace(*slsstr)) slsstr++;
                    
                    endptr = myunits;
                    
                    while ((endptr-myunits)<32
                           && *slsstr
                           && *slsstr!=','
                           && *slsstr!=')'
                           && *slsstr!=']'
                           && *slsstr!='}'
                           && !(isspace(*slsstr))
                           && !(isdigit(*slsstr))) *endptr++=*slsstr++;
                    
                    *endptr='\0';
                    
                    while (*slsstr && isspace(*slsstr)) slsstr++;
                    
                    if (!cbf_cistrcmp(bcunits,"unknown") || !*bcunits) {
                        
                        if (!cbf_scale_units(myunits, "mm",&bcscalex)) {
                            
                            bcscaley = bcscalex;
                            
                            bcunits = "mm";
                            
                        } else if (!cbf_scale_units(myunits, "pixels",&bcscalex)) {
                            
                            bcscaley = bcscalex;
                            
                            bcunits = "pixels";
                            
                        } else if (!cbf_scale_units(myunits, "bins",&bcscalex)) {
                            
                            bcscaley = bcscalex;
                            
                            bcunits = "bins";
                            
                        } else {
                            
                            bcscaley = bcscalex = 1.;
                            
                            bcunits = myunits;
                            
                        }
                        
                    } else {
                        
                        if (!cbf_scale_units(myunits, "mm",&bcscaley)) {
                            
                            if (cbf_cistrcmp(bcunits,"mm")) return CBF_FORMAT;
                            
                        } else if (!cbf_scale_units(myunits, "pixels",&bcscaley)) {
                            
                            if (cbf_cistrcmp(bcunits,"pixels")) return CBF_FORMAT;
                            
                        } else if (!cbf_scale_units(myunits, "bins",&bcscaley)) {
                            
                            if (cbf_cistrcmp(bcunits,"bins")) return CBF_FORMAT;
                            
                        } else {
                            
                            bcscaley = 1.;
                            
                            if (cbf_cistrcmp(bcunits,myunits)) return CBF_FORMAT;
                            
                        }
                        
                        
                    }
                    
                } else {
                    
                    if (*slsstr == ')' || *slsstr == ']' || *slsstr != ']') slsstr++;
                    
                }
                
            }
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            if (*slsstr == ')' || *slsstr == ']' || *slsstr == '}') slsstr++;
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            if (*bcunits || !cbf_cistrcmp(bcunits,"unknown") ){
                
                endptr = mxunits;
                
                while ((endptr-myunits)<32
                       && *slsstr
                       && *slsstr!=','
                       && *slsstr!=')'
                       && *slsstr!=']'
                       && *slsstr!='}'
                       && !(isspace(*slsstr))
                       && !(isdigit(*slsstr))) *endptr++=*slsstr++;
                
                *endptr='\0';
                
                while (*slsstr && isspace(*slsstr)) slsstr++;
                
                if (!cbf_scale_units(mxunits, "mm",&bcscalex)) {
                    
                    bcscaley = bcscalex;
                    
                    bcunits = "mm";
                    
                } else if (!cbf_scale_units(mxunits, "pixels",&bcscalex)) {
                    
                    bcscaley = bcscalex;
                    
                    bcunits = "pixels";
                    
                } else if (!cbf_scale_units(mxunits, "bins",&bcscalex)) {
                    
                    bcscaley = bcscalex;
                    
                    bcunits = "bins";
                    
                } else {
                    
                    bcscaley = bcscalex = 1.;
                    
                    bcunits = mxunits;
                    
                }
                
            }
            
            
            if (!*bcunits || !cbf_cistrcmp(bcunits,"unknown") ) {
                
                bcunits = "pixels";
                
                bcscaley = bcscalex = 1.;
                
            }
            
            
            bcx *= bcscalex;
            
            bcy *= bcscaley;
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector_element"))
            
            cbf_failnez(cbf_require_column(cbf,"reference_center_fast"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",bcx))
            
            cbf_failnez(cbf_require_column(cbf,"reference_center_slow"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",bcy))
            
            cbf_failnez(cbf_require_column(cbf,"reference_center_units"))
            
            cbf_failnez(cbf_set_value(cbf,bcunits))
            
        } else
        
        /* check for Flux 0 ph/s */
        
        if (!cbf_cistrncmp(slsstr,"Flux ",
                           strlen("Flux "))) {
            
            slsstr += strlen("Flux ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_radiation","flux","ph/s");
            
        } else
                                                                        
        /* check for Filter_transmission 1.0000 */
        
        if (!cbf_cistrncmp(slsstr,"Filter_transmission ",
                           strlen("Filter_transmission "))) {
            
            slsstr += strlen("Filter_transmission ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_radiation","filter_transmission",NULL);
            
            
        } else
            
        /* check for Start_angle 0.0900 deg. */
            
        if (!cbf_cistrncmp(slsstr,"Start_angle ",
                           strlen("Start_angle "))) {
            
            double scan;
            
            char *endptr;
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_SCAN"))
            
            cbf_failnez(cbf_require_column(cbf,"angle"))
            
            slsstr += strlen("Start_angle ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            scan = strtod(slsstr,&endptr);
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",scan))
            
        } else
                                                                                
        /* check for Oscillation_axis  X, CW */
        
        if (!cbf_cistrncmp(slsstr,"Oscillation_axis ",
                           strlen("Oscillation_axis "))) {
            
            slsstr += strlen("Oscillation_axis ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_SCAN"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_description"))
            
            cbf_failnez(cbf_set_value(cbf,slsstr))
            
        } else
            
        /* check for Angle_increment 0.0100 deg. */
            
        if (!cbf_cistrncmp(slsstr,"Angle_increment ",
                           strlen("Angle_increment "))) {
            
            double scan;
            
            char * endptr;
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_SCAN"))
            
            cbf_failnez(cbf_require_column(cbf,"angle_increment"))
            
            slsstr += strlen("Angle_increment ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            scan = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",scan))
            
        } else


        /* check for Detector_2theta 0.0000 deg. */
        
        if (!cbf_cistrncmp(slsstr,"Detector_2theta ",
                           strlen("Detector_2theta "))) {
            
            double twotheta;
            
            char *endptr;
            
            slsstr += strlen("Detector_2theta ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            twotheta = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"DETECTOR_TWOTHETA"))
            
            cbf_failnez(cbf_require_column(cbf,"angle"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",twotheta))
            
        } else
                    
        /* check for Polarization 0.950 */
        
        if (!cbf_cistrncmp(slsstr,"Polarization ",
                           strlen("Polarization "))) {
            
            slsstr += strlen("Polarization ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_radiation","polarizn_source_ratio",NULL);
            
        } else
                        
        /* check for Alpha 0.0000 deg. */
        
        if (!cbf_cistrncmp(slsstr,"Alpha ",
                           strlen("Alpha "))) {
            
            double alpha;
            
            char *endptr;
            
            slsstr += strlen("Alpha ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            alpha = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_ALPHA"))
            
            cbf_failnez(cbf_require_column(cbf,"angle"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",alpha))
            
        } else
                            
        /* check for Omega 0.0000 deg. */
        
        if (!cbf_cistrncmp(slsstr,"Omega ",
                           strlen("Omega "))) {
            
            double omega;
            
            char *endptr;
            
            slsstr += strlen("Omega ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            omega = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_OMEGA"))
            
            cbf_failnez(cbf_require_column(cbf,"angle"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",omega))
            
        } else
                                
        /* check for Kappa 0.0000 deg. */
        
        if (!cbf_cistrncmp(slsstr,"Kappa ",
                           strlen("Kappa "))) {
            
            double kappa;
            
            char *endptr;
            
            slsstr += strlen("Kappa ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            kappa = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_KAPPA"))
            
            cbf_failnez(cbf_require_column(cbf,"angle"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",kappa))
            
        } else if (!cbf_cistrncmp(slsstr,"Chi ",
                                  strlen("Chi "))) {
                                    
            double chi;
            
            char *endptr;
            
            slsstr += strlen("Chi ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            chi = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_CHI"))
            
            cbf_failnez(cbf_require_column(cbf,"angle"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",chi))
            
        } else
            
        /* check for Chi_increment 0.0100 deg. */
            
        if (!cbf_cistrncmp(slsstr,"Chi_increment ",
                           strlen("Chi_increment "))) {
            
            double scan;
            
            char * endptr;
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_CHI"))
            
            cbf_failnez(cbf_require_column(cbf,"angle_increment"))
            
            slsstr += strlen("Chi_increment ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            scan = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",scan))
            
        } else if (!cbf_cistrncmp(slsstr,"Phi ",
                                  strlen("Phi "))) {
                
            double phi;
            
            char *endptr;
            
            slsstr += strlen("Phi ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            phi = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_PHI"))
            
            cbf_failnez(cbf_require_column(cbf,"angle"))
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",phi))
                                
        } else
                                    
        /* check for Phi_increment 0.0100 deg. */
            
        if (!cbf_cistrncmp(slsstr,"Phi_increment ",
                           strlen("Phi_increment "))) {
            
            double scan;
            
            char * endptr;
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame_axis"))
            
            cbf_failnez(cbf_require_column(cbf,"axis_id"))
            
            cbf_failnez(cbf_require_row(cbf,"GONIOMETER_PHI"))
            
            cbf_failnez(cbf_require_column(cbf,"angle_increment"))
            
            slsstr += strlen("Phi_increment ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            scan = strtod(slsstr, &endptr);
            
            cbf_failnez(cbf_set_doublevalue(cbf,"%-15g",scan))
            
        } else

        /* check for N_oscillations 1 */
            
        if (!cbf_cistrncmp(slsstr,"N_oscillations ",
                           strlen("N_oscillations "))) {
            
            slsstr += strlen("N_oscillations ");
            
            while (*slsstr && isspace(*slsstr)) slsstr++;
            
            cbf_set_doublevalue_from_string(cbf,slsstr,"diffrn_scan_frame","oscillations",NULL);
            
        } else {
            
            cnvminicbf_warn("did not recognize miniheader string");
            
        }

        
        while (*buffer && ((*buffer=='\r') || (*buffer=='\n'))) {
            
            buffer++;
            
            if (*buffer=='\r' && buffer[1]=='\n') buffer++;
            
            lineno++;
            
        }
        
    }
    
    return 0;
}



int outerror(int err)
{
	
    if ((err&CBF_FORMAT)==CBF_FORMAT)
        fprintf(stderr, " convert_minicbf: The file format is invalid.\n");
    if ((err&CBF_ALLOC)==CBF_ALLOC)
        fprintf(stderr, " convert_minicbf Memory allocation failed.\n");
    if ((err&CBF_ARGUMENT)==CBF_ARGUMENT)
        fprintf(stderr, " convert_minicbf: Invalid function argument.\n");
    if ((err&CBF_ASCII)==CBF_ASCII)
        fprintf(stderr, " convert_minicbf: The value is ASCII (not binary).\n");
    if ((err&CBF_BINARY)==CBF_BINARY)
        fprintf(stderr, " convert_minicbf: The value is binary (not ASCII).\n");
    if ((err&CBF_BITCOUNT)==CBF_BITCOUNT)
        fprintf(stderr, " convert_minicbf: The expected number of bits does"
                " not match the actual number written.\n");
    if ((err&CBF_ENDOFDATA)==CBF_ENDOFDATA)
        fprintf(stderr, " convert_minicbf: The end of the data was reached"
                " before the end of the array.\n");
    if ((err&CBF_FILECLOSE)==CBF_FILECLOSE)
        fprintf(stderr, " convert_minicbf: File close error.\n");
    if ((err&CBF_FILEOPEN)==CBF_FILEOPEN)
        fprintf(stderr, " convert_minicbf: File open error.\n");
    if ((err&CBF_FILEREAD)==CBF_FILEREAD)
        fprintf(stderr, " convert_minicbf: File read error.\n");
    if ((err&CBF_FILESEEK)==CBF_FILESEEK)
        fprintf(stderr, " convert_minicbf: File seek error.\n");
    if ((err&CBF_FILETELL)==CBF_FILETELL)
        fprintf(stderr, " convert_minicbf: File tell error.\n");
    if ((err&CBF_FILEWRITE)==CBF_FILEWRITE)
        fprintf(stderr, " convert_minicbf: File write error.\n");
    if ((err&CBF_IDENTICAL)==CBF_IDENTICAL)
        fprintf(stderr, " convert_minicbf: A data block with the new name already exists.\n");
    if ((err&CBF_NOTFOUND)==CBF_NOTFOUND)
        fprintf(stderr, " convert_minicbf: The data block, category, column or"
                " row does not exist.\n");
    if ((err&CBF_OVERFLOW)==CBF_OVERFLOW)
        fprintf(stderr, " convert_minicbf: The number read cannot fit into the"
                "destination argument.\n        The destination has been set to the nearest value.\n");
    if ((err& CBF_UNDEFINED)==CBF_UNDEFINED)
        fprintf(stderr, " convert_minicbf: The requested number is not defined (e.g. 0/0).\n");
    if ((err&CBF_NOTIMPLEMENTED)==CBF_NOTIMPLEMENTED)
        fprintf(stderr, " convert_minicbf: The requested functionality is not yet implemented.\n");
    return 0;
    
}


#undef cbf_failnez
#define cbf_failnez(x) \
{int err; \
err = (x); \
if (err) { \
fprintf(stderr," convert_minicbf: CBFlib fatal error %d\n",err); \
outerror(err);   \
outusage();      \
local_exit (-1); \
} \
}

typedef enum {  posx=1, posy=2, negx=-1, negy=-2 } axes;

typedef struct
{
    axes posxtarg, posytarg;
} axisxform;



int outusage ( void ) {
    
    fprintf(stderr," \n Usage:\n");
    fprintf(stderr,"  convert_minicbf [-i input_cbf] [-o output_cbf] [-p template_cbf]\\\n");
    fprintf(stderr,"    [-q] [-C convention]  \\\n");
    fprintf(stderr,"    [-d detector name] -m [x|y|x=y] [-z distance] \\\n");
    fprintf(stderr,"    [-c category_alias=category_root]* \\\n");
    fprintf(stderr,"    [-t tag_alias=tag_root]* [-F] [-R]\\\n");
    fprintf(stderr,"    [input_cbf] [output_cbf]\n");
    
    fprintf(stderr,"  the options are:\n");
    
    fprintf(stderr,"  -i input_cbf (default: stdin)\n");
    fprintf(stderr,"    the input file as a CBF with at least an image.\n");
    
    fprintf(stderr,"  -p template_cbf\n");
    fprintf(stderr,"    the template for the final cbf to be produced.  If template_cbf\n");
    fprintf(stderr,"    is not specified the name is constructed from the first token\n");
    fprintf(stderr,"    of the detector name and the image size as\n");
    fprintf(stderr,"       template_<type>_<columns>x<rows>.cbf\n");
    
    fprintf(stderr,"  -o output_cbf (default: stdout )\n");
    fprintf(stderr,"    the output cbf combining the image and the template.  If the\n");
    fprintf(stderr,"    output_cbf is not specified or is given as \"-\", it is written\n");
    fprintf(stderr,"    to stdout.\n");
    
    fprintf(stderr,"  -q\n");
    fprintf(stderr,"    exit quickly with just the miniheader expanded\n");
    fprintf(stderr,"    after the data.  No template is used.\n");
    
    fprintf(stderr,"  -Q\n");
    fprintf(stderr,"    exit quickly with just the miniheader unexpanded\n");
    fprintf(stderr,"    before the data.  No template is used.\n");
    
    fprintf(stderr,"  -C convention\n");
    fprintf(stderr,"    convert the comment form of miniheader into the\n");
    fprintf(stderr,"        _array_data.header_convention convention\n");
    fprintf(stderr,"        _array_data.header_contents\n");
    fprintf(stderr,"    overriding any existing values\n");
    
    
    fprintf(stderr,"  -d detectorname\n");
    fprintf(stderr,"    a detector name to be used if none is provided in the image\n");
    fprintf(stderr,"    header.\n");
    
    fprintf(stderr,"  -F\n");
    fprintf(stderr,"    when writing packed compression, treat the entire image as\n");
    fprintf(stderr,"    one line with no averaging  \n");
    
    fprintf(stderr,"  -m [x|y|x=y] (default x=y, square arrays only)\n");
    fprintf(stderr,"    mirror the array in the x-axis (y -> -y)\n");
    fprintf(stderr,"                     in the y-axis (x -> -x)\n");
    fprintf(stderr,"                  or in x=y ( x -> y, y-> x)\n");
    
    fprintf(stderr,"  -r n\n");
    fprintf(stderr,"    rotate the array n times 90 degrees counter clockwise\n");
    fprintf(stderr,"    x -> y, y -> -x for each rotation, n = 1, 2 or 3\n");
    
    fprintf(stderr,"  -R \n");
    fprintf(stderr,"    if setting a beam center, set reference values of\n");
    fprintf(stderr,"    axis settings as well as standard settings\n");
    
    fprintf(stderr,"  -u \n");
    fprintf(stderr,"    write the image as unsigned short.\n");

    fprintf(stderr,"  -v version_number \n");
    fprintf(stderr,"    set the output version to version_number (default 2).\n");

    fprintf(stderr,"  -z distance\n");
    fprintf(stderr,"    detector distance along Z-axis.\n");
    
    fprintf(stderr,"  -c category_alias=category_root\n");
    fprintf(stderr,"  -t tag_alias=tagroot\n");
    fprintf(stderr,"    map the given alias to the given root, so that instead\n");
    fprintf(stderr,"    of outputting the alias, the root will be presented in the\n");
    fprintf(stderr,"    output cbf instead.  These options may be repeated as many\n");
    fprintf(stderr,"    times as needed.\n");
    
    return -1;
    
}

void applyxform(axisxform * current, axisxform * xform) {
    
    switch (current->posxtarg) {
        case (posx): current->posxtarg = xform->posxtarg; break;
        case (posy): current->posxtarg = xform->posytarg; break;
        case (negx): current->posxtarg = xform->posxtarg==posx?negx:
            (xform->posxtarg==negx?posx:
             (xform->posxtarg==posy?negy:
              (xform->posxtarg==negy?posy:0)));
            break;
        case (negy): current->posxtarg = xform->posytarg==posx?negx:
            (xform->posytarg==negx?posx:
             (xform->posytarg==posy?negy:
              (xform->posytarg==negy?posy:0)));
            break;
    }
    switch (current->posytarg) {
        case (posx): current->posytarg = xform->posxtarg; break;
        case (posy): current->posytarg = xform->posytarg; break;
        case (negx): current->posytarg = xform->posxtarg==posx?negx:
            (xform->posxtarg==negx?posx:
             (xform->posxtarg==posy?negy:
              (xform->posxtarg==negy?posy:0)));
            break;
        case (negy): current->posytarg = xform->posytarg==posx?negx:
            (xform->posytarg==negx?posx:
             (xform->posytarg==posy?negy:
              (xform->posytarg==negy?posy:0)));
            break;
    }
    return;
}

int main (int argc, char *argv [])
{
    FILE *in, *out, *file;
    
    cbf_handle minicbf;
    
    cbf_handle cbf;
    
    char detector_type [64], template_name [256], *c;
    
    const char *detector_name, *detector_opt, *detector_temp,
    *array_id;
    
    const char *datablockname;
    
    char *header_info;
    
    char *header_info_copy = NULL;
    
    size_t header_info_size;
    
    size_t header_info_cap;
    
    int dorefs;
    
    axisxform overall  = { posx, posy };
    axisxform mirrorx  = { posx, negy };
    axisxform mirrory  = { negx, posy };
    axisxform mirrorxy = { posy, posx };
    axisxform rotate1  = { posy, negx };
    axisxform rotate2  = { negx, negy };
    axisxform rotate3  = { negy, posx };
    axisxform * currentxform;
    
    int copt;
    int errflg = 0;
    char cbfintmp[19];
#ifndef NOMKSTEMP
    int cbfintmpfd;
#endif
    int cbfintmpused = 0;
    char buf[CVTBUFSIZ];
    const char *cbfin, *cbfout, *template, *distancestr, *alias;
    const char *convention;
    char *root;
    char xalias[81];
    int transpose;
    int fastlen, slowlen;
    int flat;
    int quick;
    int unshort;
    unsigned int compression;
    int binary_id;
    size_t elsize;
    int elsigned;
    int elunsigned;
    size_t elements, elements_read;
    int minelement;
    int maxelement;
    char *byteorder ="little_endian";
    size_t dim1;
    size_t dim2;
    size_t dim3;
    size_t padding;
    unsigned char *image = NULL;
    size_t nbytes;
    const char * optarg;
    cbf_getopt_handle opts;
    
    
    /* Usage */
    
    cbfin = NULL;
    cbfout = NULL;
    template = NULL;
    detector_opt = NULL;
    transpose = 0;
    distancestr = NULL;
    convention = NULL;
    dorefs = 0;
    flat = 0;
    quick = 0;
    unshort = 0;
    
    cbf_failnez (cbf_make_handle (&cbf))
    
    cbf_failnez(cbf_make_getopt_handle(&opts))
    
    cbf_failnez(cbf_getopt_parse(opts, argc, argv, "FRQqui:o:p:C:d:m:r:z:c:t:v:"))
    
    if (!cbf_rewind_getopt_option(opts))
        for(;!cbf_get_getopt_data(opts,&copt,NULL,NULL,&optarg);cbf_next_getopt_option(opts)) {
            if (!copt) break;
            switch(copt) {
                case 'i':
                    if (cbfin) errflg++;
                    else cbfin = optarg;
                    break;
                    
                case 'o':
                    if (cbfout) errflg++;
                    else cbfout = optarg;
                    break;
                    
                case 'q':
                    if (quick) errflg++;
                    else quick=1;
                    break;
                    
                case 'Q':
                    if (quick) errflg++;
                    else quick=-1;
                    break;
                    
                case 'p':
                    if (template) errflg++;
                    else template = optarg;
                    break;
                    
                case 'F':
                    flat = 1;
                    break;
                    
                case 'C':
                    if (convention) errflg++;
                    else convention = optarg;
                    break;
                    
                case 'm':
                    currentxform = (axisxform *)NULL;
                    if (!strcmp(optarg,"x")) currentxform = &mirrorx;
                    if (!strcmp(optarg,"y")) currentxform = &mirrory;
                    if (!strcmp(optarg,"x=y")) currentxform = &mirrorxy;
                    if (!currentxform) errflg++;
                    else applyxform(&overall,currentxform);
                    break;
                    
                case 'r':
                    currentxform = (axisxform *)NULL;
                    if (!strcmp(optarg,"1")) currentxform = &rotate1;
                    if (!strcmp(optarg,"2")) currentxform = &rotate2;
                    if (!strcmp(optarg,"3")) currentxform = &rotate3;
                    if (!currentxform) errflg++;
                    else applyxform(&overall,currentxform);
                    break;
                    
                case 'R':
                    dorefs = 1;
                    break;
                    
                case 'u':
                    unshort = 1;
                    break;
                    
                case 'd':
                    if (detector_opt) errflg++;
                    else detector_opt = optarg;
                    break;

                case 'v':
                    if (version_number) errflg++;
                    else version_number = atol(optarg);
                    break;

                case 'z':
                    if (distancestr) errflg++;
                    else distancestr = optarg;
                    break;
                    
                case 'c':
                case 't':
                    alias = optarg;
                    if (alias == NULL || *alias == '\0') {
                        errflg++; break;
                    }
                    root = strchr(alias,'=');
                    if (root == NULL || root-alias > 80 || root-alias < 2 || *(root+1) =='\0') {
                        errflg++; break;
                    }
                    strncpy(xalias,optarg,root-alias);
                    xalias[root-alias] = '\0';
                    root++;
                    if(copt == 'c')
                    {
                        cbf_failnez (cbf_set_category_root(cbf, (const char *)xalias, (const char *) root))
                    }
                    else {
                        cbf_failnez (cbf_set_tag_root(cbf, (const char *)xalias, (const char *) root))
                    }
                    break;
                    
                default:
                    errflg++;
                    break;
                    
            }
            
        }
    
    for(;!cbf_get_getopt_data(opts,&copt,NULL,NULL,&optarg);cbf_next_getopt_option(opts)) {
        if (!cbfin) {
            cbfin = optarg;
        } else {
            if (!cbfout) {
                cbfout = optarg;
            } else {
                errflg++;
            }
        }
    }
    
    if (errflg) {
        outusage();
        exit(-1);
    }
    
    
    if (!cbfin || strcmp(cbfin?cbfin:"","-") == 0) {
#ifdef NOTMPDIR
        strcpy(cbfintmp, "cif2cbfXXXXXX");
#else
        strcpy(cbfintmp, "/tmp/cif2cbfXXXXXX");
#endif
#ifdef NOMKSTEMP
        if (mktemp(cbfintmp) == NULL ) {
            fprintf(stderr,"\n convert_minicbf: Can't create temporary file name %s.\n", cbfintmp);
            fprintf(stderr,"%s\n",strerror(errno));
            exit(1);
        }
        if ( (file = fopen(cbfintmp,"wb+")) == NULL) {
            fprintf(stderr,"Can't open temporary file %s.\n", cbfintmp);
            fprintf(stderr,"%s\n",strerror(errno));
            exit(1);
        }
#else
        if ((cbfintmpfd = mkstemp(cbfintmp)) == -1 ) {
            fprintf(stderr,"\n convert_minicbf: Can't create temporary file name %s.\n", cbfintmp);
            fprintf(stderr,"%s\n",strerror(errno));
            exit(1);
        }
        if ( (file = fdopen(cbfintmpfd, "w+")) == NULL) {
            fprintf(stderr,"Can't open temporary file %s.\n", cbfintmp);
            fprintf(stderr,"%s\n",strerror(errno));
            exit(1);
        }
#endif
        while ((nbytes = fread(buf, 1, CVTBUFSIZ, stdin))) {
            if(nbytes != fwrite(buf, 1, nbytes, file)) {
                fprintf(stderr,"Failed to write %s.\n", cbfintmp);
                exit(1);
            }
        }
        fclose(file);
        cbfin = cbfintmp;
        cbfintmpused = 1;
    }
    
    /* Read the minicbf */
    
    
    if (!(in = fopen (cbfin, "rb"))) {
        fprintf (stderr,"Couldn't open the input minicbf file %s\n", cbfin);
        exit (1);
    }
    
    
    
    
    cbf_failnez (cbf_make_handle (&minicbf))
    
    cbf_failnez (cbf_read_widefile (minicbf, in, MSG_DIGEST))
    
    
    header_info_size = 0;
    
    header_info_cap = 0;
    
    header_info = NULL;
    
    if (!convention && !cbf_find_tag(minicbf,"_array_data.header_contents")) {
        
        cbf_failnez(cbf_get_value(minicbf,(const char * *)&header_info))
        
        cbf_parse_sls_header(minicbf, header_info, 0);
        
    } else {
        
        char * lead = "  ";
        
        if (quick) lead = "# ";
        
        if (!(in = fopen (cbfin, "rb"))) {
            fprintf (stderr,"Couldn't open the input minicbf file %s\n", cbfin);
            exit (1);
        }
        
        
        while (fgets(buf,CVTBUFSIZ,in)) {
            
            size_t slen;
            
            int ignore;
            
            char * bufptr;
            
            slen = strlen(buf);
            
            if (slen > 0 && buf[slen-1]=='\n') buf[slen] = '\0';
            
            if (!strncmp(buf,"##",2)) continue;
            
            ignore = 1;
            
            bufptr = buf;
            
            while(*bufptr) {
                
                if (!isspace(*bufptr)) break;
                
                bufptr++;
                
            }
            
            if (!*bufptr) continue;
            
            if (*bufptr != '#') break;
            
            if (!strncmp(bufptr,"# ",2)) {
                
                if (header_info_size+strlen(bufptr+2)+4 > header_info_cap) {
                    
                    char * nheader_info;
                    
                    size_t nheader_info_cap;
                    
                    size_t ii;
                    
                    nheader_info_cap = 2*(header_info_cap + strlen(bufptr+2)+4);
                    
                    cbf_failnez((nheader_info = malloc(sizeof(char)*nheader_info_cap))==NULL?CBF_ALLOC:0)
                    
                    if (header_info_size) for(ii=0;ii<header_info_size;ii++) nheader_info[ii]=header_info[ii];
                    
                    else {nheader_info[0] = '\n'; header_info_size=1;}
                    
                    if (header_info) free(header_info);
                    
                    header_info = nheader_info;
                    
                    header_info_cap = nheader_info_cap;
                    
                }
                
                strcpy(header_info+header_info_size,lead);  header_info_size += 2;
                
                strcpy(header_info+header_info_size,bufptr+2); header_info_size += strlen(bufptr+2);
                
                while (header_info_size &&
                       (*(header_info+header_info_size-1)=='\r' ||
                        *(header_info+header_info_size-1)=='\n' ||
                        !*(header_info+header_info_size-1))) header_info_size--;
                
                strcpy(header_info+header_info_size,"\n"); header_info_size++;
                
                cbf_parse_sls_header(minicbf, bufptr, 1);
                
            }
            
        }
        
        fclose(in);
        
        if (convention) {
            
            cbf_failnez(cbf_require_category(minicbf,"array_data"))
            
            cbf_failnez(cbf_require_column(minicbf,"header_convention"))
            
            cbf_failnez(cbf_set_value(minicbf,convention))
            
            cbf_failnez(cbf_require_column(minicbf,"header_contents"))
            
            cbf_failnez(cbf_set_value(minicbf,header_info))
            
        }
        
    }
    
    
    /* See if we want a quick exit */
    
    
    if (quick > 0)
    {
        
        /* Write the new file */
        
        out = stdout;
        
        if (cbfout && strcmp(cbfout,"-"))out = fopen (cbfout, "w+b");
        
        if (!out)
        {
            fprintf (stderr, " convert_minicbf:  Couldn't open the output CBF file %s\n", cbfout);
            
            exit (1);
        }
        
        cbf_failnez (cbf_write_file (minicbf, out, 1, CBF,
                                     MSG_DIGEST | MIME_HEADERS | PAD_4K, 0))
        
        /* Free the cbf */
        
        cbf_failnez (cbf_free_handle (cbf))
        
        
        /* Free the minicbf */
        
        cbf_failnez (cbf_free_handle (minicbf))
        
        
        /* Success */
        
        if (cbfintmpused) {
            if (unlink(cbfintmp) != 0 ) {
                fprintf(stderr," convert_minicbf:  Can't unlink temporary file %s.\n", cbfintmp);
                fprintf(stderr,"%s\n",strerror(errno));
                exit(1);
            }
            
        }
        
        
        return 0;
        
    } else if (quick < 0) {
        
        const char * value;
        
        cbf_failnez(cbf_datablock_name(minicbf,&datablockname))
        
        cbf_failnez(cbf_force_new_datablock(cbf,datablockname))
        
        cbf_failnez(cbf_find_tag(minicbf, "_array_data.data"))
        
        cbf_failnez(cbf_require_category(cbf,"array_data"));
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_find_column(minicbf,"header_convention") && !cbf_get_value(minicbf,&value) && value) {
            
            cbf_failnez(cbf_require_column(cbf,"header_convention"))
            
            cbf_failnez(cbf_set_value(cbf,value))
            
        }
        
        if (!cbf_find_column(minicbf,"header_contents") && !cbf_get_value(minicbf,&value) && value) {
            
            cbf_failnez(cbf_require_column(cbf,"header_contents"))
            
            cbf_failnez(cbf_set_value(cbf,value))
            
        } else if (header_info) {
            
            cbf_failnez(cbf_require_column(cbf,"header_contents"))
            
            cbf_failnez(cbf_set_value(cbf,header_info))
        }
        
        cbf_failnez(cbf_find_column(minicbf,"data"))
        
        cbf_failnez(cbf_get_integerarrayparameters_wdims (minicbf, &compression, &binary_id,
                                                          &elsize, &elsigned, &elunsigned, &elements, &minelement, &maxelement,(const char **) &byteorder,
                                                          &dim1, &dim2, &dim3, &padding))
        
        fastlen = dim1;
        slowlen = dim2;
        
        cbf_failnez((image = (unsigned char*)malloc(elements*elsize))!=NULL?0:CBF_ALLOC)
        cbf_failnez(cbf_get_integerarray (minicbf, &binary_id, (void *)image, elsize, elsigned,
                                          elements, &elements_read))
        if (elements != elements_read) { cbf_failnez(CBF_FORMAT) }
        
        cbf_failnez (cbf_require_column(cbf,"data"))
        
        if (flat) {
            
            cbf_failnez( cbf_set_integerarray_wdims (cbf, CBF_PACKED|CBF_FLAT_IMAGE, binary_id,
                                                     image, elsize, elsigned, elements, byteorder, dim1, dim2, dim3, padding))
            
        } else {
            cbf_failnez( cbf_set_integerarray_wdims (cbf, compression, binary_id,
                                                     image, elsize, elsigned, elements, byteorder, dim1, dim2, dim3, padding))
        }
        
        
        /* Write the new file */
        
        out = stdout;
        
        if (cbfout && strcmp(cbfout,"-"))out = fopen (cbfout, "w+b");
        
        if (!out) {
            
            fprintf (stderr, " convert_minicbf:  Couldn't open the output CBF file %s\n", cbfout);
            
            exit (1);
            
        }
        
        cbf_failnez (cbf_write_file (cbf, out, 1, CBF,
                                     MSG_DIGEST | MIME_HEADERS | PAD_4K, 0))
        
        /* Free the cbf */
        
        cbf_failnez (cbf_free_handle (cbf))
        
        
        /* Free the minicbf */
        
        cbf_failnez (cbf_free_handle (minicbf))
        
        
        /* Success */
        
        if (cbfintmpused) {
            if (unlink(cbfintmp) != 0 ) {
                fprintf(stderr," convert_minicbf:  Can't unlink temporary file %s.\n", cbfintmp);
                fprintf(stderr,"%s\n",strerror(errno));
                exit(1);
            }
            
        }
        
        return 0;
        
        
    }
    
    
    /* Find the image */
    
    cbf_failnez(cbf_find_tag(minicbf, "_array_data.data"))
    
    cbf_failnez(cbf_rewind_row(minicbf))
    
    cbf_failnez(cbf_get_integerarrayparameters_wdims (minicbf, &compression, &binary_id,
                                                      &elsize, &elsigned, &elunsigned, &elements, &minelement, &maxelement,(const char **) &byteorder,
                                                      &dim1, &dim2, &dim3, &padding))
    
    cbf_failnez((image = (unsigned char*)malloc(elements*elsize))!=NULL?0:CBF_ALLOC)
    cbf_failnez(cbf_get_integerarray (minicbf, &binary_id, (void *)image, elsize, elsigned,
                                      elements, &elements_read))
    if (elements != elements_read) { cbf_failnez(CBF_FORMAT) }
    
    
    /* Identify the detector */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.type")) {
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (cbf_get_value(minicbf,&detector_name) || !detector_name || !*detector_name) {
            
            if (detector_opt == NULL || *detector_opt == '\0') {
                
                fprintf (stderr, "\n convert_inage: no detector name provided in minicbf or on the command line!\n");
                fprintf (stderr, "                  defaulting to \"Pilatus\"\n");
            
                detector_opt = "Pilatus";
                
            }
            
            detector_name = detector_opt;
            
        }
        
    } else {
        
        if (detector_opt == NULL || *detector_opt == '\0') {
            
            fprintf (stderr, "\n convert_inage: no detector name provided in minicbf or on the command line!\n");
            fprintf (stderr, "                  defaulting to \"Pilatus\"\n");
            
            detector_opt = "Pilatus";
            
        }
        
        detector_name = detector_opt;
        
    }
    
    detector_temp = detector_name;
    
    for (c = detector_type; *detector_temp; detector_temp++)
        
        if (!isspace (*detector_temp))
            
            *c++ = tolower (*detector_temp);
    
    *c = '\0';
    
    
    /* Construct the template name */
    
    if (template) {
        
        in = fopen (template, "rb");
        
    } else {
        
        sprintf (template_name, "template_%s_%dx%d.cbf", detector_type,
                 (int)dim1,
                 (int)dim2);
        
        fprintf(stderr," convert_minicbf: template_name: %s\n", template_name);
        
        /* Read and modify the template */
        
        in = fopen (template_name, "rb");
        
    }
    
    if (!in)  {
        fprintf (stderr," convert_minicbf: unable to open template_name: %s\n",
                 template?template:template_name);
        
        exit (4);
        
    }
    
    cbf_failnez (cbf_read_template (cbf, in))
    
    
    
    cbf_failnez(cbf_get_array_id(cbf, 0, &array_id))
    
    cbf_failnez(cbf_require_column(cbf, "details"))
    
    if (header_info) {
        
        char * src;
        
        char * dst;
        
        char ccur, cprev;
        
        header_info_copy=(char *)malloc(strlen(header_info)+1);
        
        src = header_info;
        
        dst = header_info_copy;
        
        cprev = '\n';
        
        while((ccur=*src++)) {
            
            if (ccur == '#'
                && (cprev == '\n'|| cprev == '\r' ) ) *dst++ = ' ';
            else *dst++=ccur;
            
            cprev = ccur;
        }
        
        *dst++ = '\0';
        
        cbf_failnez(cbf_set_value(cbf, header_info_copy))
        
        cbf_failnez(cbf_set_typeofvalue(cbf,"text"))
        
    }
    
    
    
    
    /* diffrn.id */
    
    cbf_failnez (cbf_set_diffrn_id (cbf, "DS1"))
    
    /* diffrn_detector.type */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.type")) {
        
        const char *type;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&type) && type && *type) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"type"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,type))
            
        }
        
    } else {
        
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"type"))
            
            cbf_failnez(cbf_rewind_row(cbf))
        
            if (*detector_name) {
            
                cbf_failnez(cbf_set_value(cbf,detector_name))
                
            } else {
                
                cbf_failnez(cbf_set_value(cbf,"Pilatus"))
            }
       
        
    }

    /* diffrn_detector.details */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.details")) {
        
        const char *details;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&details) && details && *details) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"details"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,details))
            
        }
        
    }
 
    /* diffrn_detector.dtime */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.dtime")) {
        
        const char *dtime;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&dtime) && dtime && *dtime) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"dtime"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,dtime))
            
        }
        
    }

    /* diffrn_detector.threshold */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.threshold")) {
        
        const char *threshold;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&threshold) && threshold && *threshold) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"threshold"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,threshold))
            
        }
        
    }

    /* diffrn_detector.energy_range_low */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.energy_range_low")) {
        
        const char *erlow;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&erlow) && erlow && *erlow) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"erlow"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,erlow))
            
        }
        
    }

    /* diffrn_detector.energy_range_high */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.energy_range_high")) {
        
        const char *erhigh;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&erhigh) && erhigh && *erhigh) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"erhigh"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,erhigh))
            
        }
        
    }
    
    /* diffrn_detector.layer_thickness */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector.layer_thickness")) {
        
        const char *thickness;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&thickness) && thickness && *thickness) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_detector"))
            
            cbf_failnez(cbf_require_column(cbf,"thickness"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,thickness))
            
        }
        
    }
    
    
    
    /* Exposure time */
    
    
    if (!cbf_find_tag(minicbf,"_diffrn_scan_frame.integration_time")) {
        
        const char *time;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&time) && time && *time) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame"))
            
            cbf_failnez(cbf_require_column(cbf,"integration_time"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,time))
            
        }
        
    }
    
    
    
    /* Date stamp */
    
    if (!cbf_find_tag(minicbf,"_diffrn_scan_frame.date")) {
        
        const char *date;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&date) && date && *date) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame"))
            
            cbf_failnez(cbf_require_column(cbf,"date"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,date))
            
        }
        
    }
    
    
    /* Oscillations */
    
    if (!cbf_find_tag(minicbf,"_diffrn_scan_frame.oscillations")) {
        
        const char *oscillations;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&oscillations) && oscillations && *oscillations) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame"))
            
            cbf_failnez(cbf_require_column(cbf,"oscillations"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,oscillations))
            
        }
        
    }

    /* Exposure time */
    
    if (!cbf_find_tag(minicbf,"_diffrn_scan_frame.integration_time")) {
        
        const char *integration_time;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&integration_time) && integration_time && *integration_time) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame"))
            
            cbf_failnez(cbf_require_column(cbf,"integration_time"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,integration_time))
            
        }
        
    }

    /* Exposure period */
    
    if (!cbf_find_tag(minicbf,"_diffrn_scan_frame.integration_period")) {
        
        const char *integration_period;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&integration_period) && integration_period && *integration_period) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_scan_frame"))
            
            cbf_failnez(cbf_require_column(cbf,"integration_period"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,integration_period))
            
        }
        
    }

    /* Element size */
    
    
    if (!cbf_find_tag(minicbf,"_array_element_size.size")) {
        
        const char *size, *index;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&size) && size && *size) {
            
            cbf_failnez(cbf_require_category(cbf,"array_element_size"))
            
            cbf_failnez(cbf_require_column(cbf,"size"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,size))
            
            cbf_failnez(cbf_require_column(cbf,"index"))
            
            cbf_failnez(cbf_require_column(minicbf,"index"))
            
            if (!cbf_get_value(minicbf,&index) && index && *index) {
                
                cbf_failnez(cbf_set_value(cbf,index))
                
            }
            
            if (!cbf_next_row(minicbf)) {
                
                cbf_failnez(cbf_find_column(minicbf,"size"))
                
                if (!cbf_get_value(minicbf,&size) && size && *size) {
                    
                    cbf_failnez(cbf_find_column(cbf,"size"))
                    
                    cbf_failnez(cbf_next_row(cbf))
                    
                    cbf_failnez(cbf_set_value(cbf,size))
                    
                    cbf_failnez(cbf_find_column(cbf,"index"))
                    
                    cbf_failnez(cbf_find_column(minicbf,"index"))
                    
                    if (!cbf_get_value(minicbf,&index) && index && *index) {
                        
                        cbf_failnez(cbf_set_value(cbf,index))
                        
                    }
                    
                }
                
            }
            
        }
        
    }
    
    /* diffrn_radiation.tau */
    
    if (!cbf_find_tag(minicbf,"_diffrn_radiation.tau")) {
        
        const char *tau;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&tau) && tau && *tau) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_radiation"))
            
            cbf_failnez(cbf_require_column(cbf,"tau"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,tau))
            
        }
        
    }
    
    
    /* diffrn_radiation.flux */
    
    if (!cbf_find_tag(minicbf,"_diffrn_radiation.flux")) {
        
        const char *flux;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&flux) && flux && *flux) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_radiation"))
            
            cbf_failnez(cbf_require_column(cbf,"flux"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,flux))
            
        }
        
    }
    
    /* diffrn_radiation.filter_transmission */
    
    if (version_number != 1 && !cbf_find_tag(minicbf,"_diffrn_radiation.filter_transmission")) {
        
        const char *filter_transmission;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&filter_transmission) && filter_transmission && *filter_transmission) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_radiation"))
            
            cbf_failnez(cbf_require_column(cbf,"filter_transmission"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,filter_transmission))
            
        }
        
    }
    
    
    /* diffrn_radiation.polarizn_source_ratio */
    
    if (!cbf_find_tag(minicbf,"_diffrn_radiation.polarizn_source_ratio")) {
        
        const char *polarizn_source_ratio;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&polarizn_source_ratio) && polarizn_source_ratio && *polarizn_source_ratio) {
            
            cbf_failnez(cbf_require_category(cbf,"diffrn_radiation"))
            
            cbf_failnez(cbf_require_column(cbf,"polarizn_source_ratio"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,polarizn_source_ratio))
            
        }
        
    }
    
    /* array_intensities.overload */
    
    if (!cbf_find_tag(minicbf,"_array_intensities.overload")) {
        
        const char *overload;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        if (!cbf_get_value(minicbf,&overload) && overload && *overload) {
            
            cbf_failnez(cbf_require_category(cbf,"array_intensities"))
            
            cbf_failnez(cbf_require_column(cbf,"overload"))
            
            cbf_failnez(cbf_rewind_row(cbf))
            
            cbf_failnez(cbf_set_value(cbf,overload))
            
        }
        
    }
    
    /* Wavelength */
    
    if (!cbf_find_tag(minicbf,"_diffrn_radiation_wavelength.wavelength")) {
        
        double wavelength;
        
        cbf_failnez(cbf_get_doublevalue(minicbf,&wavelength))
        
        if (wavelength)
            
            cbf_failnez (cbf_set_wavelength (cbf, wavelength))
            
            }
    
    
    /* Distance */
    
    
    if (!cbf_find_tag(minicbf,"_diffrn_measurement.sample_detector_distance")) {
        
        double distance;
        
        cbf_failnez(cbf_get_doublevalue(minicbf,&distance))
        
        if (distance == 0. && distancestr) {
            
            distance = atof (distancestr);
            
        }
        
        cbf_failnez (cbf_set_axis_setting (cbf, 0, "DETECTOR_Z", distance, 0))
        
        cbf_failnez(cbf_require_category(cbf,"diffrn_measurement"))
        
        cbf_failnez(cbf_require_column(cbf,"sample_detector_distance"))
        
        cbf_failnez(cbf_set_doublevalue(cbf,"%g", distance))
        
    }
    
    
    /* Vertical Offset */
    
    
    if (!cbf_find_tag(minicbf,"_diffrn_measurement.sample_detector_voffset")) {
        
        double voffset;
        
        cbf_failnez(cbf_get_doublevalue(minicbf,&voffset))
        
        if ( cbf_set_axis_setting (cbf, 0, "DETECTOR_Y", voffset, 0) && voffset !=0.) {
        
            fprintf(stderr,"\n convert_minicbf: No DETECTOR_Y to accept voffset\n" );

        }
        
        cbf_failnez(cbf_require_category(cbf,"diffrn_measurement"))
        
        cbf_failnez(cbf_require_column(cbf,"sample_detector_voffset"))
        
        cbf_failnez(cbf_set_doublevalue(cbf,"%g", voffset))
        
    }
    
    
    /* Oscillation start and range */
    
    if (!cbf_find_tag(minicbf,"_diffrn_scan_frame_axis.axis_id")) {
        
        char * axis;
        
        char oscaxis[40];
        
        double osc_start, osc_range;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        cbf_failnez(cbf_find_row(minicbf,"GONIOMETER_SCAN"))
        
        axis = "PHI";
        
        cbf_failnez(cbf_find_column(minicbf,"angle"))
        
        cbf_failnez(cbf_get_doublevalue(minicbf,&osc_start))
        
        cbf_failnez(cbf_find_column(minicbf,"angle_increment"))
        
        cbf_failnez(cbf_get_doublevalue(minicbf,&osc_range))
        
        sprintf (oscaxis, "GONIOMETER_%s", axis);
        
        cbf_failnez (cbf_set_axis_setting (cbf, 0, oscaxis,
                                           osc_start, osc_range))
    }
    
    
    /* Beam Center */
    
    if (!cbf_find_tag(minicbf,"_diffrn_detector_element.reference_center_fast")){
        
        cbf_detector detector;
        
        const char * units;
        
        double bcx, bcy;
        
        cbf_failnez(cbf_rewind_row(minicbf))
        
        cbf_failnez(cbf_require_column(minicbf,"reference_center_fast"))
        
        cbf_failnez(cbf_get_doublevalue(minicbf,&bcx))
        
        cbf_failnez(cbf_require_column(minicbf,"reference_center_slow"))
        
        cbf_failnez(cbf_get_doublevalue(minicbf,&bcy))
        
        cbf_failnez(cbf_require_column(minicbf,"reference_center_units"))
        
        cbf_failnez(cbf_require_value(minicbf,&units,"mm"))
        
        if (!cbf_cistrcmp(units,"pixels")) {
            
            if(!cbf_construct_detector (cbf, &detector, 0)){
            
            cbf_failnez(cbf_set_beam_center(detector, &bcy, &bcx, NULL, NULL))
            
            cbf_failnez(cbf_free_detector(detector))
            
            if (dorefs) {
                
                cbf_failnez(cbf_require_reference_detector (cbf, &detector, 0))
                
                cbf_failnez(cbf_set_reference_beam_center(detector, &bcy, &bcx, NULL, NULL))
                
                cbf_failnez(cbf_free_detector(detector))
                
            }
            }
            
        } else if (!cbf_cistrcmp(units,"mm")) {
            
            cbf_failnez(cbf_construct_detector (cbf, &detector, 0))
            
            cbf_failnez(cbf_set_beam_center(detector, NULL, NULL, &bcy, &bcx))
            
            cbf_failnez(cbf_free_detector(detector))
            
            if (dorefs) {
                
                cbf_failnez(cbf_require_reference_detector (cbf, &detector, 0))
                
                cbf_failnez(cbf_set_reference_beam_center(detector, NULL, NULL, &bcy, &bcx))
                
                cbf_failnez(cbf_free_detector(detector))
                
            }
            
        } else cbf_failnez(CBF_FORMAT)
            
            }
    
    
    
    
    /* Image */
    
    fastlen = dim1;
    slowlen = dim2;
    
    
    if (overall.posxtarg != posx || overall.posytarg != posy )
    { int fastorig, faststep, sloworig, slowstep, curpos, i, j;
        
        int * tempimg;
        
        if (overall.posxtarg==0 || overall.posytarg==0) {
            fprintf (stderr,"\n convert_minicbf: invalid image transform.\n");
            exit(1);
        }
        
        if (dim2 != dim1 ) {
            fprintf(stderr,"\n convert_img: Unable to transpose image\n");
            exit(-1);
        }
        
        /* The fast index is the x axis, counting
         the columns, and the slow index is the y axis, counting the
         rows */
        
        
        fastorig = sloworig = 0;
        faststep = 1;
        slowstep = dim1;
        
        switch (overall.posxtarg) {
            case (posx): break;
            case (negx): fastorig = dim1-1; faststep = -1; break;
            case (posy): faststep = dim1;
                fastlen = dim2;
                slowlen = dim1; break;
            case (negy): fastorig = (dim1)*(dim2-1);
                faststep = -dim1;
                fastlen = dim2;
                slowlen = dim1; break;
        }
        switch (overall.posytarg) {
            case (posx): slowstep = 1;
                fastlen = dim2;
                slowlen = dim1; break;
            case (negx): sloworig = dim1-1; slowstep= -1;
                fastlen = dim2;
                slowlen = dim1; break;
            case (posy): break;
            case (negy): sloworig = dim1*(dim2-1);
                slowstep = -dim1; break;
        }
        
        
        curpos = fastorig+sloworig;
        
        tempimg = malloc(dim1*dim2*elsize);
        if (!tempimg) {
            fprintf(stderr,"\n unable to allocate temporary image array\n");
        }
        
        if (elsize == sizeof(int)) {
            
            for (i=0;i<fastlen;i++) {
                curpos = fastorig+i*faststep+sloworig;
                for (j=0; j<slowlen;j++) {
                    *((int *)tempimg+curpos) = *((int *)image+i+j*fastlen);
                    curpos = curpos+slowstep;
                }
            }
            
            for (i=0;i<fastlen;i++) {
                for (j=0; j<slowlen;j++) {
                    *(int *)((int *)image+i+j*fastlen) = *((int *)tempimg+i+j*fastlen);
                }
            }
        } else if (elsize == sizeof(short))  {
            for (i=0;i<fastlen;i++) {
                curpos = fastorig+i*faststep+sloworig;
                for (j=0; j<slowlen;j++) {
                    *((short *)tempimg+curpos) = *((short *)image+i+j*fastlen);
                    curpos = curpos+slowstep;
                }
            }
            
            for (i=0;i<fastlen;i++) {
                for (j=0; j<slowlen;j++) {
                    *(int *)((short *)image+i+j*fastlen) = *((short *)tempimg+i+j*fastlen);
                }
            }
            
        }
        else cbf_failnez(CBF_FORMAT)
            
            free (tempimg);
        
    }
    
    if (!unshort || (elsize==sizeof(short) && elunsigned ) ) {
        
        
        if (flat) {
            
            cbf_failnez (cbf_set_image (cbf, 0, 0, CBF_PACKED|CBF_FLAT_IMAGE,
                                        image, elsize, elsigned,
                                        slowlen, fastlen))
            
        } else {
            cbf_failnez (cbf_set_image (cbf, 0, 0, compression,
                                        image, elsize, elsigned,
                                        slowlen, fastlen))
        }
        
    } else {
        
        unsigned short *tempimg;
        
        int i;
        
        tempimg = malloc(dim1*dim2*sizeof(short));
        if (!tempimg) {
            fprintf(stderr,"\n unable to allocate temporary image array\n");
        }
        
        if (elsize == sizeof(short)){
            for (i = 0; i < dim1*dim2; i++) {
                short j;
                j = ((short *)image)[i];
                if (j < 0) j = 0;
                tempimg[i] = j;
            }
        } else {
            for (i = 0; i < dim1*dim2; i++) {
                int j;
                j = ((int *)image)[i];
                if (j < 0) j = 0;
                if (j > 0xFFFF) j = 0xFFFF;
                tempimg[i] = j;
            }
        }
        
        
        if (flat) {
            
            cbf_failnez (cbf_set_image (cbf, 0, 0, CBF_PACKED|CBF_FLAT_IMAGE,
                                        image, sizeof(short), 0,
                                        slowlen, fastlen))
            
        } else {
            cbf_failnez (cbf_set_image (cbf, 0, 0, compression,
                                        image, sizeof(short), 0,
                                        slowlen, fastlen))
        }
        
    }
    
    
    /* fix up the array_structure_list.direction and .precedence */
    
    
    if (overall.posxtarg != posx || overall.posytarg != posy) {
        
        unsigned int arow[2], precedence[2], temp;
        
        char * direction[2], * dtemp;
        
        arow[0] = arow[1] = 0;
        
        precedence[0] = 1;
        
        precedence[1] = 2;
        
        direction[0] = direction[1] = NULL;
        
        cbf_failnez (cbf_find_category (cbf, "array_structure_list"))
        cbf_failnez (cbf_find_column   (cbf, "array_id"))
        
        while (!cbf_find_nextrow (cbf, array_id)) {
            
            cbf_failnez (cbf_find_column      (cbf, "precedence"))
            cbf_failnez (cbf_get_integervalue (cbf, (int *)&temp))
            
            if (temp == 1 || temp == 2) {
                cbf_failnez(cbf_row_number(cbf,&(arow[temp-1])))
                arow[temp-1]++;
                cbf_failnez(cbf_find_column(cbf,"direction"))
                cbf_failnez(cbf_get_value(cbf,(const char**)&(direction[temp-1])))
                cbf_failnez(cbf_find_column   (cbf, "array_id"))
            }
            
        }
        
        
        switch (overall.posxtarg) {
            case (posx): break;
            case (negx): if (!cbf_cistrcmp(direction[0],"increasing")) {
                direction[0] = "decreasing";
            } else {
                direction[0] = "increasing";
            } 
                break;
            case (posy): precedence[0] = 2; precedence[1] = 1;
                dtemp = direction[0]; direction[0]=direction[1]; direction[1]=dtemp;
                break;
            case (negy): precedence[0] = 2; precedence[1] = 1;
                dtemp = direction[0]; direction[0]=direction[1]; direction[1]=dtemp;
                if (!cbf_cistrcmp(direction[0],"increasing")) {
                    direction[0] = "decreasing";
                } else {
                    direction[0] = "increasing";
                } 
                break;
        }
        switch (overall.posytarg) {
            case (posx): break;
            case (negx): if (!cbf_cistrcmp(direction[1],"increasing")) {
                direction[1] = "decreasing";
            } else {
                direction[1] = "increasing";
            } 
                break;
            case (posy): break;
            case (negy): if (!cbf_cistrcmp(direction[1],"increasing")) {
                direction[1] = "decreasing";
            } else {
                direction[1] = "increasing";
            }  break;
        }
        
        if (arow[0]) {
            cbf_failnez (cbf_select_row       (cbf, arow[0]-1))
            cbf_failnez (cbf_find_column      (cbf, "precedence"))
            cbf_failnez (cbf_set_integervalue (cbf, precedence[0]))
            cbf_failnez (cbf_find_column      (cbf, "direction"))
            cbf_failnez (cbf_set_value        (cbf, direction[0]))
        }
        
        if (arow[1]) {
            cbf_failnez (cbf_select_row       (cbf, arow[1]-1))
            cbf_failnez (cbf_find_column      (cbf, "precedence"))
            cbf_failnez (cbf_set_integervalue (cbf, precedence[1]))
            cbf_failnez (cbf_find_column      (cbf, "direction"))
            cbf_failnez (cbf_set_value        (cbf, direction[1]))
        }
        
    }
    
    
    
    
    
    
    /*****************************************************************************/
    
    
    
    /* Write the new file */
    
    out = stdout;
    
    if (cbfout && strcmp(cbfout,"-"))out = fopen (cbfout, "w+b");
    
    if (!out)
    {
        fprintf (stderr, " convert_minicbf:  Couldn't open the output CBF file %s\n", cbfout);
        
        exit (1);
    }
    
    cbf_failnez (cbf_write_file (cbf, out, 1, CBF,
                                 MSG_DIGEST | MIME_HEADERS | PAD_4K, 0))
    
    
    /* Free the cbf */
    
    cbf_failnez (cbf_free_handle (cbf))
    
    
    /* Free the minicbf */
    
    cbf_failnez (cbf_free_handle (minicbf))
    
    /* Free the getopt_handle */
    
    cbf_failnez (cbf_free_getopt_handle(opts))
    
    /* Success */
    
    if (cbfintmpused) {
        if (unlink(cbfintmp) != 0 ) {
            fprintf(stderr," convert_minicbf:  Can't unlink temporary file %s.\n", cbfintmp);
            fprintf(stderr,"%s\n",strerror(errno));
            exit(1);
        }
        
    }
    
	free((void*)image);
	free((void*)header_info_copy);

    return 0;
}

int local_exit (int status)
{
    exit(status);
    return 1; /* avoid warnings */
}

