1618 lines
37 KiB
C
1618 lines
37 KiB
C
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@file iofits.c
|
|
@author N. Devillard
|
|
@date July 1998
|
|
@version $Revision: 1.2 $
|
|
@brief convert FITS from a pixel depth to another.
|
|
This is a stand-alone tool.
|
|
Yes, it is a hack. However, it is a real boost compared to any "intelligent"
|
|
FITS handling software because it does not even try to understand what it
|
|
finds in the FITS header (except for BITPIX and NAXIS?, of course). The
|
|
worst part is pixel to pixel conversion, because it required to study it
|
|
case by case. Nice feature is that it handles Intel/Motorola endian-ness
|
|
dynamically, no need to specify anything on the command-line nor at
|
|
compilation time.
|
|
|
|
Conversions almost always use the fastest bitwise method to construct the
|
|
outputs. Heavy use of mmap() allows to go on without allocating much memory,
|
|
I do believe no method could do it faster than direct transfer from disk to
|
|
disk with a shortcut through CPU registers.
|
|
|
|
Unsupported are:
|
|
|
|
* Machines on which the size of a char is not 8 bits. It would mean a
|
|
complete rewrite of all pixel to pixel conversions. No way.
|
|
* Machines for which a float or a double are not stored as described in the
|
|
IEEE reference (cannot find the exact number... well, the usual floats and
|
|
doubles as described in the FITS format for example). It would also mean
|
|
re-writing most of the conversion functions, forget it.
|
|
|
|
Some assumptions taken along:
|
|
|
|
* FITS lines are 80 chars wide.
|
|
* A FITS block size is 2880 bytes wide.
|
|
* FITS data types are 8 16 32 -32 and -64 ONLY.
|
|
* The size of an IEEE float is 4 chars.
|
|
* The size of an IEEE double is 8 chars.
|
|
|
|
* The size of a short is 16 bits
|
|
* The size of a long is 32 bits
|
|
|
|
The two latter are ensured by redefining the following int types:
|
|
short16 is a signed integer on 16 bits
|
|
long32 is a signed integer on 32 bits
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
$Id: iofits.c,v 1.2 2002/11/21 13:41:00 yjung Exp $
|
|
$Author: yjung $
|
|
$Date: 2002/11/21 13:41:00 $
|
|
$Revision: 1.2 $
|
|
*/
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Includes
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Define
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#define NM_SIZ 512
|
|
#define FITS_BLSZ 2880
|
|
#define ONE_MEGABYTE (1024 * 1024)
|
|
|
|
#ifndef SEEK_SET
|
|
#define SEEK_SET 0
|
|
#endif
|
|
|
|
#define ENDIAN_UNKNOWN -1
|
|
#define ENDIAN_MOTOROLA 0
|
|
#define ENDIAN_INTEL 1
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Macros
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#define ENDIAN_NESS(f) ((f)&1)
|
|
#define IEEE_FLOAT_COMPAT(f) ((f)&2)
|
|
#define IEEE_DOUBLE_COMPAT(f) ((f)&4)
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
typedefs
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
typedef short short16;
|
|
typedef unsigned short ushort16;
|
|
typedef int long32;
|
|
typedef unsigned char byte;
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Function prototypes
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
static int bits_per_byte (void);
|
|
static int convert_fits_pixel_depth (char *, char *, int);
|
|
static int get_FITS_header_size (char *);
|
|
static int filesize (char *);
|
|
static int get_bitpix (char *);
|
|
static int set_bitpix (char *, int);
|
|
static int get_npix (char *);
|
|
static int write_pixbuf (char *, char *, int, int, int);
|
|
static int test_machine_formats (void);
|
|
static void swap_bytes (void *, int);
|
|
static void check_all_types (int);
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Global variables
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
static unsigned compat_flags;
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Main
|
|
-----------------------------------------------------------------------------*/
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
int ptype;
|
|
|
|
if (argc != 4)
|
|
{
|
|
printf ("\n\n");
|
|
printf ("use: %s <in> <out> <8|16|32|-32|-64>\n", argv[0]);
|
|
printf ("\n");
|
|
printf ("\t<in> is a valid FITS file in the current directory\n");
|
|
printf ("\t<out> is the name of the output file\n");
|
|
printf ("\t<8|16|32|-32|-64> is the output file pixel type\n");
|
|
printf ("\n\n");
|
|
return 0;
|
|
}
|
|
ptype = (int) atoi (argv[3]);
|
|
check_all_types (ptype);
|
|
if (!strcmp (argv[1], argv[2]))
|
|
{
|
|
fprintf (stderr, "cannot convert a file to itself\n");
|
|
fprintf (stderr, "specify another name for the output\n");
|
|
return -1;
|
|
}
|
|
return convert_fits_pixel_depth (argv[1], argv[2], ptype);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Functions code
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief convert FITS files from one pixel depth to another
|
|
@param name_in input file name
|
|
@param name_out output file name
|
|
@param ptype_out Output pixel type
|
|
@return int 0 if Ok, anything else otherwise
|
|
Heavy use of mmap() to speed up the process
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
convert_fits_pixel_depth (char *name_in, char *name_out, int ptype_out)
|
|
{
|
|
int fd_in, fd_out;
|
|
char *buf_in;
|
|
char *buf_out;
|
|
int fsize_in, fsize_out, header_size, padd_size;
|
|
int ptype_in;
|
|
int bpp_out;
|
|
int npix;
|
|
char *zero;
|
|
int yet_to_dump;
|
|
int buf_dump;
|
|
|
|
/* Open input file and get pixel depth and number of pixels */
|
|
fsize_in = filesize (name_in);
|
|
header_size = get_FITS_header_size (name_in);
|
|
if ((fd_in = open (name_in, O_RDONLY)) == -1)
|
|
{
|
|
fprintf (stderr, "cannot open file %s: aborting\n", name_in);
|
|
return -1;
|
|
}
|
|
buf_in = (char *) mmap (0, fsize_in, PROT_READ, MAP_SHARED, fd_in, 0);
|
|
if (buf_in == (char *) -1)
|
|
{
|
|
perror ("mmap");
|
|
fprintf (stderr, "cannot mmap file: %s\n", name_in);
|
|
close (fd_in);
|
|
return -1;
|
|
}
|
|
ptype_in = get_bitpix (buf_in);
|
|
if (ptype_in == 0)
|
|
{
|
|
close (fd_in);
|
|
munmap (buf_in, fsize_in);
|
|
return -1;
|
|
}
|
|
if (ptype_in == -32)
|
|
{
|
|
if (!IEEE_FLOAT_COMPAT (compat_flags))
|
|
{
|
|
fprintf (stderr,
|
|
"this machine does not support IEEE floating point values\n");
|
|
fprintf (stderr, "cannot convert from -32 type\n");
|
|
exit (-1);
|
|
}
|
|
}
|
|
if (ptype_in == -64)
|
|
{
|
|
if (!IEEE_DOUBLE_COMPAT (compat_flags))
|
|
{
|
|
fprintf (stderr,
|
|
"this machine does not support IEEE double values\n");
|
|
fprintf (stderr, "cannot convert from -64 type\n");
|
|
exit (-1);
|
|
}
|
|
}
|
|
|
|
/* Compute the size of the output file: header size+pixel area+padding */
|
|
npix = get_npix (buf_in);
|
|
if (npix < 1)
|
|
{
|
|
close (fd_in);
|
|
munmap (buf_in, fsize_in);
|
|
return -1;
|
|
}
|
|
bpp_out = ptype_out / 8;
|
|
if (bpp_out < 0)
|
|
{
|
|
bpp_out = -bpp_out;
|
|
}
|
|
fsize_out = header_size + npix * bpp_out;
|
|
if ((fsize_out % FITS_BLSZ) == 0)
|
|
{
|
|
padd_size = 0;
|
|
}
|
|
else
|
|
{
|
|
padd_size = FITS_BLSZ - fsize_out % FITS_BLSZ;
|
|
}
|
|
fsize_out += padd_size;
|
|
|
|
/* Now create the output file and fill it with zeros, then mmap it. */
|
|
/* The permissions are rw-rw-r-- by default. */
|
|
if ((fd_out =
|
|
creat (name_out,
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)) == -1)
|
|
{
|
|
perror ("creat");
|
|
fprintf (stderr, "cannot create file %s: aborting\n", name_out);
|
|
close (fd_in);
|
|
munmap (buf_in, fsize_in);
|
|
return -1;
|
|
}
|
|
zero = calloc (ONE_MEGABYTE, 1);
|
|
yet_to_dump = fsize_out;
|
|
if (fsize_out < ONE_MEGABYTE)
|
|
{
|
|
buf_dump = fsize_out;
|
|
}
|
|
else
|
|
{
|
|
buf_dump = ONE_MEGABYTE;
|
|
}
|
|
while (yet_to_dump > 0)
|
|
{
|
|
if (write (fd_out, zero, buf_dump) != buf_dump)
|
|
{
|
|
perror ("write");
|
|
fprintf (stderr, "error writing to the output file: aborting\n");
|
|
close (fd_in);
|
|
close (fd_out);
|
|
munmap (buf_in, fsize_in);
|
|
free (zero);
|
|
return -1;
|
|
}
|
|
yet_to_dump -= buf_dump;
|
|
if (yet_to_dump > ONE_MEGABYTE)
|
|
{
|
|
buf_dump = ONE_MEGABYTE;
|
|
}
|
|
else
|
|
{
|
|
buf_dump = yet_to_dump;
|
|
}
|
|
}
|
|
free (zero);
|
|
close (fd_out);
|
|
if ((fd_out = open (name_out, O_RDWR)) == -1)
|
|
{
|
|
perror ("open");
|
|
fprintf (stderr, "cannot reopen file %s for writing\n", name_out);
|
|
close (fd_in);
|
|
munmap (buf_in, fsize_in);
|
|
return -1;
|
|
}
|
|
|
|
buf_out = (char *) mmap (0,
|
|
fsize_out,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, fd_out, 0);
|
|
if (buf_out == (char *) -1)
|
|
{
|
|
perror ("mmap");
|
|
fprintf (stderr, "cannot mmap file: %s\n", name_out);
|
|
munmap (buf_in, fsize_in);
|
|
close (fd_in);
|
|
close (fd_out);
|
|
return -1;
|
|
}
|
|
|
|
/* Copy FITS header from input to output, modify BITPIX */
|
|
memcpy (buf_out, buf_in, header_size);
|
|
if (set_bitpix (buf_out, ptype_out) != 0)
|
|
{
|
|
fprintf (stderr, "error writing BITPIX in output: aborting\n");
|
|
munmap (buf_in, fsize_in);
|
|
munmap (buf_out, fsize_out);
|
|
close (fd_in);
|
|
close (fd_out);
|
|
return -1;
|
|
}
|
|
|
|
/* Now write pixels */
|
|
write_pixbuf (buf_in + header_size,
|
|
buf_out + header_size, npix, ptype_in, ptype_out);
|
|
|
|
/* Blank-pad the output file if needed */
|
|
if (padd_size)
|
|
{
|
|
if (lseek (fd_out, fsize_out - padd_size, SEEK_SET) == -1)
|
|
{
|
|
perror ("lseek");
|
|
fprintf (stderr, "error seeking output file: aborting\n");
|
|
}
|
|
else
|
|
{
|
|
zero = calloc (padd_size, 1);
|
|
if (write (fd_out, zero, 1) == -1)
|
|
{
|
|
perror ("write");
|
|
fprintf (stderr, "error writing into output file: aborting\n");
|
|
}
|
|
free (zero);
|
|
}
|
|
}
|
|
|
|
/* Close, unmap, goodbye */
|
|
close (fd_in);
|
|
close (fd_out);
|
|
munmap (buf_in, fsize_in);
|
|
munmap (buf_out, fsize_out);
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief compute the size (in bytes) of a FITS header
|
|
@param name FITS file name
|
|
@return int
|
|
Should always be a multiple of 2880. This implementation assumes only that 80
|
|
characters are found per line.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
get_FITS_header_size (char *name)
|
|
{
|
|
FILE *in;
|
|
char line[81];
|
|
int found = 0;
|
|
int count;
|
|
int hs;
|
|
|
|
if ((in = fopen (name, "r")) == NULL)
|
|
{
|
|
fprintf (stderr, "cannot open %s: aborting\n", name);
|
|
return 0;
|
|
}
|
|
count = 0;
|
|
while (!found)
|
|
{
|
|
if (fread (line, 1, 80, in) != 80)
|
|
break;
|
|
count++;
|
|
if (!strncmp (line, "END ", 4))
|
|
found = 1;
|
|
}
|
|
fclose (in);
|
|
|
|
if (!found)
|
|
return 0;
|
|
/* The size is the cards nb x 80, rounded to the nextmultiple of 2880 */
|
|
hs = count * 80;
|
|
if ((hs % FITS_BLSZ) != 0)
|
|
hs = (1 + (hs / FITS_BLSZ)) * FITS_BLSZ;
|
|
return hs;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief how many bytes can I read from this file
|
|
@param filename Name of file
|
|
@return size of the file in bytes
|
|
Strongly non portable. Only on Unix systems!
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
filesize (char *filename)
|
|
{
|
|
int size;
|
|
struct stat fileinfo;
|
|
|
|
/* POSIX compliant */
|
|
if (stat (filename, &fileinfo) != 0)
|
|
size = (int) 0;
|
|
else
|
|
size = (int) fileinfo.st_size;
|
|
return size;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief gets the value of BITPIX from a FITS header
|
|
@param buf allocated char buffer containing the whole FITS header
|
|
@return int 8 16 32 -32 or -64 or 0 if cannot find it
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
get_bitpix (char *buf)
|
|
{
|
|
int bitpix;
|
|
char *where;
|
|
|
|
where = strstr (buf, "BITPIX");
|
|
if (where == NULL)
|
|
{
|
|
fprintf (stderr, "cannot find BITPIX in header: aborting\n");
|
|
return 0;
|
|
}
|
|
sscanf (where, "%*[^=] = %d", &bitpix);
|
|
/* Check the returned value makes sense */
|
|
if ((bitpix != 8) &&
|
|
(bitpix != 16) && (bitpix != 32) && (bitpix != -32) && (bitpix != -64))
|
|
{
|
|
bitpix = 0;
|
|
}
|
|
return bitpix;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief overwrites the value of BITPIX in a FITS header
|
|
@param buf allocated char buffer containing the whole FITS header
|
|
@param ptype pixel type to write
|
|
@return int 0 if Ok, anything else otherwise
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
set_bitpix (char *buf, int ptype)
|
|
{
|
|
char *where;
|
|
char replace[81];
|
|
|
|
where = strstr (buf, "BITPIX");
|
|
if (where == NULL)
|
|
{
|
|
fprintf (stderr, "cannot find BITPIX in header: aborting\n");
|
|
return -1;
|
|
}
|
|
sprintf (replace,
|
|
"BITPIX = % 3d / Bits per pixel ",
|
|
ptype);
|
|
memcpy (where, replace, 80);
|
|
return 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief retrieves how many pixels in a FITS file from the header
|
|
@param buf allocated char buffer containing the whole FITS header
|
|
@return int # of pixels in the file
|
|
Does not support extensions!
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
get_npix (char *buf)
|
|
{
|
|
int naxes;
|
|
int npix;
|
|
int naxis;
|
|
char *where;
|
|
char lookfor[80];
|
|
int i;
|
|
|
|
where = strstr (buf, "NAXIS");
|
|
if (where == NULL)
|
|
{
|
|
fprintf (stderr, "cannot find NAXIS in header: aborting\n");
|
|
return 0;
|
|
}
|
|
sscanf (where, "%*[^=] = %d", &naxes);
|
|
if ((naxes < 1) || (naxes > 999))
|
|
{
|
|
fprintf (stderr, "illegal value for %s: %d\n", lookfor, naxes);
|
|
return 0;
|
|
}
|
|
npix = 1;
|
|
for (i = 1; i <= naxes; i++)
|
|
{
|
|
sprintf (lookfor, "NAXIS%d", i);
|
|
where = strstr (buf, lookfor);
|
|
if (where == NULL)
|
|
{
|
|
fprintf (stderr, "cannot find %s in header: aborting\n", lookfor);
|
|
return 0;
|
|
}
|
|
sscanf (where, "%*[^=] = %d", &naxis);
|
|
if (naxis < 1)
|
|
{
|
|
fprintf (stderr, "error: found %s=%d\n", lookfor, naxis);
|
|
return 0;
|
|
}
|
|
npix *= naxis;
|
|
}
|
|
return npix;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief transfers a pixel buffer from one area to another
|
|
@param bi allocated char buffer containing the whole in FITS header
|
|
@param bo allocated char buffer containing the whole out FITS header
|
|
@param npix number of pixels in input area
|
|
@param ptype_in input pixel type
|
|
@param ptype_out output pixel type
|
|
@return int 0 if Ok, anything else otherwise
|
|
Optimized code, very limited readability!!!
|
|
Pixel format conversion on the fly if needed.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
write_pixbuf (char *bi, char *bo, int npix, int ptype_in, int ptype_out)
|
|
{
|
|
int bpp;
|
|
register int i;
|
|
register char *ip;
|
|
register char *op;
|
|
double d;
|
|
float f;
|
|
char a2[2];
|
|
char a4[4];
|
|
char a8[8];
|
|
|
|
/*
|
|
* Trivial case of identical copies
|
|
* 8 to 8
|
|
* 16 to 16
|
|
* 32 to 32
|
|
* -32 to-32
|
|
* -64 to-64
|
|
*/
|
|
|
|
if (ptype_in == ptype_out)
|
|
{
|
|
/* How many bytes per pixel? */
|
|
bpp = ptype_in / 8;
|
|
if (bpp < 0)
|
|
bpp = -bpp;
|
|
/* Copy the buffer as it is and return */
|
|
memcpy (bo, bi, npix * bpp);
|
|
return 0;
|
|
}
|
|
|
|
/* Use registers to boost speed */
|
|
ip = bi;
|
|
op = bo;
|
|
|
|
/* ---------- 8 bit to something */
|
|
|
|
/*
|
|
* 8 to 16
|
|
* one byte in input becomes the LSB in the 2 output bytes
|
|
* we transfer it directly in the LSB, this is independent from
|
|
* machine endian-ness.
|
|
*/
|
|
|
|
if ((ptype_in == 8) && (ptype_out == 16))
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
op++;
|
|
*op++ |= *ip++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 8 to 32
|
|
* One byte in input becomes the LSB in the 4 output bytes
|
|
* we transfer it directly in the LSB, this is independent from
|
|
* machine endian-ness.
|
|
*/
|
|
|
|
if ((ptype_in == 8) && (ptype_out == 32))
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
op++;
|
|
op++;
|
|
op++;
|
|
*op++ |= *ip++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 8 to -32
|
|
* Conversion achieved through cast of the input byte into a float
|
|
* this means we use the local float type, need to know endian-ness
|
|
*/
|
|
|
|
if ((ptype_in == 8) && (ptype_out == -32))
|
|
{
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
f = (float) (*(byte *) ip);
|
|
memcpy (op, &f, 4);
|
|
ip++;
|
|
op += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
f = (float) (*(byte *) ip);
|
|
swap_bytes (&f, sizeof (float));
|
|
memcpy (op, &f, 4);
|
|
ip++;
|
|
op += 4;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 8 to -64
|
|
* Conversion achieved through cast of the input byte into a double
|
|
* this means we use the local float type, need to know endian-ness
|
|
*/
|
|
if ((ptype_in == 8) && (ptype_out == -64))
|
|
{
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
d = (double) (*(byte *) ip);
|
|
memcpy (op, &d, 8);
|
|
ip++;
|
|
op += 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
d = (double) (*(byte *) ip);
|
|
swap_bytes (&d, sizeof (double));
|
|
memcpy (op, &d, 8);
|
|
ip++;
|
|
op += 8;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- 16 bit to something */
|
|
|
|
/*
|
|
* 16 to 8
|
|
* We only keep the 8 LSBits. If the MSB is set, it means the input
|
|
* number is negative (FITS 16 bit is signed), so we clip to 0. If
|
|
* the MSB is cleared but any other bit in the above 8 is set, it
|
|
* means the input is greater than 0xff, so we clip to 0xff.
|
|
*/
|
|
|
|
if ((ptype_in == 16) && (ptype_out == 8))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
if (!*ip)
|
|
{
|
|
ip++;
|
|
*op++ = *ip++;
|
|
}
|
|
else
|
|
{
|
|
if (*ip & 0x80)
|
|
{
|
|
*op++ = 0;
|
|
ip++;
|
|
ip++;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (byte) 0xff;
|
|
ip++;
|
|
ip++;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 16 to 32
|
|
* We only need to transfer the 16 input bits as LSB for the output
|
|
* 32 bits. No need to know local endian-ness.
|
|
*/
|
|
if ((ptype_in == 16) && (ptype_out == 32))
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
op++;
|
|
op++;
|
|
*op++ = *ip++;
|
|
*op++ = *ip++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 16 to -32
|
|
* Conversion to IEEE float is done through a cast of the input
|
|
* number. Need to know local endian-ness.
|
|
*/
|
|
if ((ptype_in == 16) && (ptype_out == -32))
|
|
{
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* signed short to float conversion */
|
|
f = (float) (*(short16 *) ip);
|
|
memcpy (op, &f, 4);
|
|
ip++;
|
|
ip++;
|
|
op += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* swap to get a local signed short */
|
|
memcpy (a2, ip, 2);
|
|
swap_bytes (a2, 2);
|
|
/* signed short to float conversion */
|
|
f = (float) (*(short16 *) & a2[0]);
|
|
/* swap to write as Motorola data */
|
|
swap_bytes (&f, sizeof (float));
|
|
memcpy (op, &f, 4);
|
|
ip++;
|
|
ip++;
|
|
op += 4;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 16 to -64
|
|
* Conversion to IEEE double is done through a cast of the input
|
|
* number. Need to know local endian-ness.
|
|
*/
|
|
if ((ptype_in == 16) && (ptype_out == -64))
|
|
{
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* signed short to double conversion */
|
|
d = (double) (*(short16 *) ip);
|
|
memcpy (op, &d, 8);
|
|
ip++;
|
|
ip++;
|
|
op += 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* swap to get a local signed short */
|
|
memcpy (a2, ip, 2);
|
|
swap_bytes (a2, 2);
|
|
/* signed short to double conversion */
|
|
d = (double) (*(short16 *) & a2[0]);
|
|
/* swap back to Motorola format */
|
|
swap_bytes (&d, sizeof (double));
|
|
memcpy (op, &d, 8);
|
|
ip++;
|
|
ip++;
|
|
op += 8;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- 32 bit to something */
|
|
|
|
/*
|
|
* 32 to 8
|
|
* Loss of the 24 upper bits: as for 16->8 we try to find if the
|
|
* input is negative by looking at the MSB and in that case clip to
|
|
* zero. If the MSB is cleared but any other of the upper 24 bits is
|
|
* set, the number is greater than 0xff and is clipped to 0xff.
|
|
*/
|
|
if ((ptype_in == 32) && (ptype_out == 8))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/*
|
|
* if first bit is set, the number is negative on 32 bits,
|
|
* should be clipped to 0 on 8 bits
|
|
*/
|
|
if (*ip & 0x80)
|
|
{
|
|
*op++ = 0;
|
|
}
|
|
else if ((byte) * ip | (byte) * (ip + 1) | (byte) * (ip + 2))
|
|
{
|
|
/*
|
|
* if any bit is set in the first 24 bits, the number is
|
|
* greater than 0xff, should be clipped to 0xff
|
|
*/
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else
|
|
{
|
|
*op++ = *(ip + 3);
|
|
}
|
|
ip += 4;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 32 to 16
|
|
* Loss of the 16 upper bits.
|
|
* We convert the input to a local signed long to see if it
|
|
* overflows a signed short. If it does, it is clipped.
|
|
*/
|
|
if ((ptype_in == 32) && (ptype_out == 16))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
if ((*(long32 *) ip) > 32767)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
ip += 4;
|
|
}
|
|
else if ((*(long32 *) ip) < -32768)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
ip += 4;
|
|
}
|
|
else
|
|
{
|
|
ip += 2;
|
|
*op++ = *ip++;
|
|
*op++ = *ip++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* construct a local signed long to check its value */
|
|
memcpy (a4, ip, 4);
|
|
swap_bytes (a4, 4);
|
|
if ((*(long32 *) & a4[0]) > 32767)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
ip += 4;
|
|
}
|
|
else if ((*(long32 *) & a4[0]) < -32768)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
ip += 4;
|
|
}
|
|
else
|
|
{
|
|
ip += 2;
|
|
*op++ = *ip++;
|
|
*op++ = *ip++;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 32 to -32
|
|
* We cast the input to a local float, then output it to disk.
|
|
*/
|
|
if ((ptype_in == 32) && (ptype_out == -32))
|
|
{
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* conversion through cast to local float */
|
|
f = (float) (*(long32 *) ip);
|
|
memcpy (op, &f, 4);
|
|
ip += 4;
|
|
op += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* conversion through swap and cast to a local float */
|
|
memcpy (a4, ip, 4);
|
|
swap_bytes (a4, 4);
|
|
f = (float) (*(long32 *) & a4[0]);
|
|
/* construct a motorola float in the output */
|
|
swap_bytes (&f, sizeof (float));
|
|
memcpy (op, &f, 4);
|
|
ip += 4;
|
|
op += 4;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 32 to -64
|
|
* Conversion through cast to a local double, then output to disk.
|
|
*/
|
|
if ((ptype_in == 32) && (ptype_out == -64))
|
|
{
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
d = (double) (*(long32 *) ip);
|
|
memcpy (op, &d, 8);
|
|
ip += 4;
|
|
op += 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
/* build a local double though swap and cast */
|
|
memcpy (a4, ip, 4);
|
|
swap_bytes (a4, 4);
|
|
d = (double) (*(long32 *) & a4[0]);
|
|
/* construct a Motorola double for output */
|
|
swap_bytes (&d, sizeof (double));
|
|
memcpy (op, &d, 8);
|
|
ip += 4;
|
|
op += 8;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- -32 to something */
|
|
|
|
/*
|
|
* -32 to 8
|
|
* Construct the input float through cast (need to know endian-ness).
|
|
* Clip it to [0..255], round the value to the smaller integer.
|
|
*/
|
|
if ((ptype_in == -32) && (ptype_out == 8))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
f = *((float *) ip);
|
|
if (f > 255.0)
|
|
{
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (f < 0.0)
|
|
{
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (byte) (f + 0.5);
|
|
}
|
|
ip += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a4, ip, 4);
|
|
swap_bytes (a4, 4);
|
|
f = *((float *) &a4[0]);
|
|
if (f > 255.0)
|
|
{
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (f < 0.0)
|
|
{
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (byte) (f + 0.5);
|
|
}
|
|
ip += 4;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* -32 to 16
|
|
* Construct the input float through cast (need to know endian-ness)
|
|
* Clip it to [-32768..32767], round the value to the smaller
|
|
* integer.
|
|
*/
|
|
if ((ptype_in == -32) && (ptype_out == 16))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
f = *((float *) ip);
|
|
if (f > 32767.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (f < -32768.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (short16) f >> 8;
|
|
*op++ = (short16) f & (byte) 0xff;
|
|
}
|
|
ip += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a4, ip, 4);
|
|
swap_bytes (a4, 4);
|
|
f = *((float *) &a4[0]);
|
|
if (f > 32767.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (f < -32768.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (short16) f >> 8;
|
|
*op++ = (short16) f & (byte) 0xff;
|
|
}
|
|
ip += 4;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* -32 to 32
|
|
* Construct the input float through cast (need to know endian-ness)
|
|
* Clip it to [-2147483648 .. 2147483647], then round to the smaller
|
|
* integer.
|
|
*/
|
|
if ((ptype_in == -32) && (ptype_out == 32))
|
|
{
|
|
fprintf (stderr, "warning: probable loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
f = *((float *) ip);
|
|
if (f > 2147483647.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (f < -2147483648.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (long32) f >> 24;
|
|
*op++ = ((long32) f >> 16) & 0xff;
|
|
*op++ = ((long32) f >> 8) & 0xff;
|
|
*op++ = (long32) f & 0xff;
|
|
}
|
|
ip += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a4, ip, 4);
|
|
swap_bytes (a4, 4);
|
|
f = *((float *) &a4[0]);
|
|
if (f > 2147483647.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (f < -2147483648.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (long32) f >> 24;
|
|
*op++ = ((long32) f >> 16) & 0xff;
|
|
*op++ = ((long32) f >> 8) & 0xff;
|
|
*op++ = (long32) f & 0xff;
|
|
}
|
|
ip += 4;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* -32 to -64
|
|
* Conversion achieved through cast. Need to know endian-ness.
|
|
*/
|
|
if ((ptype_in == -32) && (ptype_out == -64))
|
|
{
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
d = (double) (*(float *) ip);
|
|
memcpy (op, &d, 8);
|
|
ip += 4;
|
|
op += 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a4, ip, 4);
|
|
swap_bytes (a4, 4);
|
|
d = (double) (*(float *) &a4[0]);
|
|
swap_bytes (&d, sizeof (double));
|
|
memcpy (op, &d, 8);
|
|
ip += 4;
|
|
op += 8;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------- -64 to something */
|
|
|
|
/*
|
|
* -64 to 8
|
|
* Heavy loss of input precision!
|
|
* The input double is constructed through swap and cast. It is then
|
|
* clipped to [0..255] and rounded to the smaller integer.
|
|
*/
|
|
if ((ptype_in == -64) && (ptype_out == 8))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
d = *((double *) ip);
|
|
if (d > 255.0)
|
|
{
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (d < 0.0)
|
|
{
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (byte) (d + 0.5);
|
|
}
|
|
ip += 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a8, ip, 8);
|
|
swap_bytes (a8, 8);
|
|
d = *((double *) &a8[0]);
|
|
if (d > 255.0)
|
|
{
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (d < 0.0)
|
|
{
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (byte) (d + 0.5);
|
|
}
|
|
ip += 8;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* -64 to 16
|
|
* Heavy loss of input precision!
|
|
* The input double is constructed through swap and cast. It is then
|
|
* clipped to [-32768..32767] and rounded to the smaller integer.
|
|
*/
|
|
if ((ptype_in == -64) && (ptype_out == 16))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
d = *((double *) ip);
|
|
if (d > 32767.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (d < -32768.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (short16) d >> 8;
|
|
*op++ = (short16) d & (byte) 0xff;
|
|
}
|
|
ip += 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a8, ip, 8);
|
|
swap_bytes (a8, 8);
|
|
d = *((double *) &a8[0]);
|
|
if (d > 32767.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (d < -32768.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (short16) d >> 8;
|
|
*op++ = (short16) d & (byte) 0xff;
|
|
}
|
|
ip += 8;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* -64 to 32
|
|
* Heavy loss of input precision!
|
|
* The input double is constructed through swap and cast. It is then
|
|
* clipped to [-2147483648..2147483647] and rounded to the smaller
|
|
* integer.
|
|
*/
|
|
if ((ptype_in == -64) && (ptype_out == 32))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
d = *((double *) ip);
|
|
if (d > 2147483647.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (d < -2147483648.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (long32) d >> 24;
|
|
*op++ = ((long32) d >> 16) & (byte) 0xff;
|
|
*op++ = ((long32) d >> 8) & (byte) 0xff;
|
|
*op++ = (long32) d & (byte) 0xff;
|
|
}
|
|
ip += 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a8, ip, 8);
|
|
swap_bytes (a8, 8);
|
|
d = *((double *) &a8[0]);
|
|
if (d > 2147483647.0)
|
|
{
|
|
*op++ = (byte) 0x7f;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
*op++ = (byte) 0xff;
|
|
}
|
|
else if (d < -2147483648.0)
|
|
{
|
|
*op++ = (byte) 0x80;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
*op++ = (byte) 0x00;
|
|
}
|
|
else
|
|
{
|
|
*op++ = (long32) d >> 24;
|
|
*op++ = ((long32) d >> 16) & 0xff;
|
|
*op++ = ((long32) d >> 8) & 0xff;
|
|
*op++ = (long32) d & 0xff;
|
|
}
|
|
ip += 8;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* -64 to -32
|
|
* Heavy loss of input precision!
|
|
* The input double is constructed through swap and cast. It is then
|
|
* simply cast to a float using the local algorithm for this
|
|
* conversion.
|
|
*/
|
|
if ((ptype_in == -64) && (ptype_out == -32))
|
|
{
|
|
fprintf (stderr, "warning: loss of precision in output\n");
|
|
if (ENDIAN_NESS (compat_flags) == ENDIAN_MOTOROLA)
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
f = (float) (*(double *) ip);
|
|
memcpy (op, &f, 4);
|
|
ip += 8;
|
|
op += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < npix; i++)
|
|
{
|
|
memcpy (a8, ip, 8);
|
|
swap_bytes (a8, 8);
|
|
f = (float) (*(double *) &a8[0]);
|
|
swap_bytes (&f, sizeof (float));
|
|
memcpy (op, &f, 4);
|
|
ip += 8;
|
|
op += 4;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
bits_per_byte (void)
|
|
{
|
|
unsigned char c = 1;
|
|
int i = 0;
|
|
while (c)
|
|
{
|
|
c <<= 1;
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief test out endian-ness and IEEE compatibility of the local machine
|
|
@return flag (1 unsigned int)
|
|
bit 0 stands for endian-ness: 0=Motorola, 1=Intel
|
|
bit 1 stands for IEEE float compatible (1=yes, 0=no)
|
|
bit 2 stands for IEEE double compatible (1=yes, 0=no)
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static int
|
|
test_machine_formats (void)
|
|
{
|
|
ushort16 ps = 0xff;
|
|
int endian = ENDIAN_UNKNOWN;
|
|
unsigned flags = 0;
|
|
float f;
|
|
double d;
|
|
byte *b;
|
|
|
|
/* Test endian-ness for this machine */
|
|
endian = ((*((char *) (&ps))) ? ENDIAN_INTEL : ENDIAN_MOTOROLA);
|
|
flags |= endian;
|
|
|
|
/* Test whether the internal float format is IEEE 32bit floating */
|
|
if (sizeof (float) == 4)
|
|
{
|
|
f = (float) 2.5e-16;
|
|
b = (byte *) (&f);
|
|
if (endian == ENDIAN_INTEL)
|
|
{
|
|
swap_bytes (&f, sizeof (float));
|
|
}
|
|
if ((b[0] == (byte) 0x25) &&
|
|
(b[1] == (byte) 0x90) &&
|
|
(b[2] == (byte) 0x1d) && (b[3] == (byte) 0x7d))
|
|
{
|
|
flags |= 2;
|
|
}
|
|
}
|
|
|
|
if (sizeof (double) == 8)
|
|
{
|
|
d = (double) 3.14e32;
|
|
b = (byte *) & d;
|
|
if (endian == ENDIAN_INTEL)
|
|
{
|
|
swap_bytes (&d, sizeof (double));
|
|
}
|
|
if ((b[0] == (byte) 0x46) &&
|
|
(b[1] == (byte) 0xae) &&
|
|
(b[2] == (byte) 0xf6) &&
|
|
(b[3] == (byte) 0x79) &&
|
|
(b[4] == (byte) 0x70) &&
|
|
(b[5] == (byte) 0xae) &&
|
|
(b[6] == (byte) 0xec) && (b[7] == (byte) 0xd7))
|
|
{
|
|
flags |= 4;
|
|
}
|
|
}
|
|
return flags;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief swap bytes in a even-sized memory area
|
|
@param p memory area
|
|
@param s area size (should be even)
|
|
The area pointed to by p is modified (byte swapped) as:
|
|
AB -> BA
|
|
ABCD -> DCBA
|
|
ABCDEFGH -> HGFEDCBA
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static void
|
|
swap_bytes (void *p, int s)
|
|
{
|
|
byte tmp, *a, *b;
|
|
|
|
a = (byte *) p;
|
|
b = a + s;
|
|
|
|
while (a < b)
|
|
{
|
|
tmp = *a;
|
|
*a++ = *--b;
|
|
*b = tmp;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief test out if the requested pixel type corresponds to a valid type
|
|
@param ptype requested pixel type for output
|
|
Also tests out the sizes of all basic types (short16, long32, byte) to
|
|
ensure they are the correct size. Also checks out that a float is IEEE
|
|
compatible and a double is what it pretends to be.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
static void
|
|
check_all_types (int ptype)
|
|
{
|
|
/* Check the requested pixel type is correct */
|
|
if ((ptype != 8) && (ptype != 16) && (ptype != 32) && (ptype != -32)
|
|
&& (ptype != -64))
|
|
{
|
|
fprintf (stderr, "illegal pixel type: %d\n", ptype);
|
|
fprintf (stderr, "should be 8 16 32 -32 or -64\n");
|
|
exit (-1);
|
|
}
|
|
|
|
/*
|
|
* Check the following:
|
|
* bitsize of byte is 8 bits
|
|
* bitsize of short is 16 bits
|
|
* bitsize of long is 32 bits
|
|
*/
|
|
|
|
if (bits_per_byte () != 8)
|
|
{
|
|
fprintf (stderr, "this machine does not support 8-bit chars\n");
|
|
fprintf (stderr, "cannot go any further -- sorry.\n");
|
|
exit (-1);
|
|
}
|
|
|
|
if (sizeof (short16) != 2)
|
|
{
|
|
fprintf (stderr, "internal: wrong definition for short16\n");
|
|
fprintf (stderr, "edit definition and recompile.\n");
|
|
exit (-1);
|
|
}
|
|
|
|
if (sizeof (long32) != 4)
|
|
{
|
|
fprintf (stderr, "internal: wrong definition for long32\n");
|
|
fprintf (stderr, "edit definition and recompile.\n");
|
|
exit (-1);
|
|
}
|
|
|
|
/*
|
|
* If -32 or -64 are requested in input check out that
|
|
* the local CPU works with float and double in IEEE format,
|
|
* otherwise, we cannot do much (arithmetic and bitwise
|
|
* interpretations needed, not implemented here...).
|
|
*/
|
|
|
|
compat_flags = test_machine_formats ();
|
|
if (ptype == -32)
|
|
{
|
|
if (!IEEE_FLOAT_COMPAT (compat_flags))
|
|
{
|
|
fprintf (stderr,
|
|
"this machine does not support IEEE floating point values\n");
|
|
fprintf (stderr, "cannot convert from -32 type\n");
|
|
exit (-1);
|
|
}
|
|
}
|
|
if (ptype == -64)
|
|
{
|
|
if (!IEEE_DOUBLE_COMPAT (compat_flags))
|
|
{
|
|
fprintf (stderr,
|
|
"this machine does not support IEEE double values\n");
|
|
fprintf (stderr, "cannot convert from -64 type\n");
|
|
exit (-1);
|
|
}
|
|
}
|
|
return;
|
|
}
|