4317 lines
128 KiB
C
4317 lines
128 KiB
C
/**
|
||
** $Header: /roq/libsdsc/bin.c 1 11/02/99 4:39p Zaphod $
|
||
** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC)
|
||
** a division of General Atomics, San Diego, California, USA
|
||
**
|
||
** Users and possessors of this source code are hereby granted a
|
||
** nonexclusive, royalty-free copyright and design patent license to
|
||
** use this code in individual software. License is not granted for
|
||
** commercial resale, in whole or in part, without prior written
|
||
** permission from SDSC. This source is provided "AS IS" without express
|
||
** or implied warranty of any kind.
|
||
**
|
||
** For further information contact:
|
||
** E-Mail: info@sds.sdsc.edu
|
||
**
|
||
** Surface Mail: Information Center
|
||
** San Diego Supercomputer Center
|
||
** P.O. Box 85608
|
||
** San Diego, CA 92138-5608
|
||
** (619) 534-5000
|
||
**/
|
||
|
||
#define HEADER " $Header: /roq/libsdsc/bin.c 1 11/02/99 4:39p Zaphod $"
|
||
|
||
/**
|
||
** FILE
|
||
** bin.c - Binary I/O Functions
|
||
**
|
||
** PROJECT
|
||
** libsdsc - SDSC standard function library
|
||
**
|
||
** DESCRIPTION
|
||
** This file contains source for the portable binary I/O function set.
|
||
** These functions allow binary files to be read and written regardless
|
||
** of the machine type and its word size and structure field padding.
|
||
**
|
||
** ASSUMPTIONS!!!
|
||
** It is assumed that a variable of type 'char' is exactly 8-bits long,
|
||
** and no longer!
|
||
**
|
||
** The size of variables, and the resolution (amount of storage actually
|
||
** used) are both assumed to be multiplies of 1 byte (8-bits).
|
||
**
|
||
** It is assumed that the host represents integers in 2's compliment form.
|
||
**
|
||
** See the discussion of the 'binFloatFormatInfo' structure for further
|
||
** assumptions regarding floating point.
|
||
**
|
||
** PUBLIC CONTENTS
|
||
** d =defined constant
|
||
** f =function
|
||
** m =defined macro
|
||
** t =typedef/struct/union
|
||
** v =variable
|
||
** ? =other
|
||
**
|
||
** BinErrNo v error number
|
||
** BinNErr v number of error messages
|
||
** BinErrList v error messages
|
||
**
|
||
** BinQMachine f Query machine information
|
||
** BinPError f Print error message
|
||
** BinQError f Query error message
|
||
** BinErrorHandler f nominate an error condition handler func
|
||
**
|
||
** BinByteOrder f Select the byte order of the file
|
||
** BinQByteOrder f Query the byte order of the file
|
||
** BinFloatFormat f Select the floating point format of the file
|
||
** BinQFloatFormat f Query the floating point format of the file
|
||
**
|
||
** BinRead f Read binary file using unbuffered I/O
|
||
** BinFRead f Read binary file using buffered I/O
|
||
** BinSRead f Read binary string
|
||
** BinWrite f Write binary file using unbuffered I/O
|
||
** BinFWrite f Write binary file using buffered I/O
|
||
** BinSWrite f Write binary string
|
||
**
|
||
** BinReadStruct f Read binary file into a C struct using unbuf I/O
|
||
** BinFReadStruct f Read binary file into a C struct using buf I/O
|
||
** BinSReadStruct f Read binary string into a C struct
|
||
** BinWriteStruct f Write binary file from a C struct using unbuf I/O
|
||
** BinFWriteStruct f Write binary file from a C struct using buf I/O
|
||
** BinSWriteStruct f Write binary string from a C struct
|
||
**
|
||
** PRIVATE CONTENTS
|
||
** binFileBO v current file byte order
|
||
** binReadMBFDisp v array of MBF handling functions
|
||
** binReadLBFDisp v array of LBF handling functions
|
||
** binReadDisp v pointer to the current read function array
|
||
** binWriteMBFDisp v array of MBF handling functions
|
||
** binWriteLBFDisp v array of LBF handling functions
|
||
** binWriteDisp v pointer to the current write function array
|
||
**
|
||
** binTypeName v names of the types
|
||
** binTypeSize v size of each type, as stored by host
|
||
** binTypeRes v resolution of each type, as used by host
|
||
** binTypeSigned v is the type signed?
|
||
** binTypePad v how are types padded?
|
||
** binTypePadMask v how are type's padding addresses masked?
|
||
**
|
||
** binPadStructxxx t Dummy structures to figure padding
|
||
** binFloatFormatInfo t Floating point format description
|
||
** binFloatFormatCooked t cooked floating point format description
|
||
** binHostFloatFormat v Host floating point format description
|
||
** binFileFloatFormat v File floating point format description
|
||
**
|
||
** binErrFunc v error condition handler function
|
||
** binOp v Current operation (for error handling)
|
||
**
|
||
** binInit v Tables initialized yet?
|
||
** binInitialize f Initialize the tables
|
||
** binDefaultHandler f Default error condition handler
|
||
** binNoHandler f No error condition handler
|
||
**
|
||
** binByteRead f read bytes into a buffer
|
||
** binByteWrite f write bytes from a buffer
|
||
**
|
||
** binReadCharMBF f Read into characters from an MBF input
|
||
** binReadCharLBF f Read into characters from an LBF input
|
||
** binWriteCharMBF f Write from characters to MBF output
|
||
** binWriteCharLBF f Write from characters to LBF output
|
||
**
|
||
** binReadIntMBF f Read MBF input into integers
|
||
** binReadIntLBF f Read LBF input into integers
|
||
** binWriteIntMBF f Write from integers to MBF output
|
||
** binWriteIntLBF f Write from integers to LBF output
|
||
**
|
||
** binReadFloat f Read float from input
|
||
** binWriteFloat f Write from float to output
|
||
**
|
||
** HISTORY
|
||
** $Log: /roq/libsdsc/bin.c $
|
||
*
|
||
* 1 11/02/99 4:39p Zaphod
|
||
** Revision 1.18 1995/06/30 21:52:27 bduggan
|
||
** added a cast
|
||
** took out curses.h
|
||
**
|
||
** Revision 1.17 1995/06/29 07:19:16 bduggan
|
||
** changed an unsigned char to an unsigned int (oops.)
|
||
**
|
||
** Revision 1.17 1995/06/29 07:17:54 bduggan
|
||
** changed an unsigned char to an inunsigned int
|
||
**
|
||
** Revision 1.16 1995/06/29 00:17:39 bduggan
|
||
** updated copyright
|
||
**
|
||
** Revision 1.15 1995/06/29 00:13:51 bduggan
|
||
** removed use of 'this', added prototypes
|
||
**
|
||
** Revision 1.14 1995/04/21 17:56:41 bduggan
|
||
** Changed bzero to memset, replaced prototypes for
|
||
** standard functions with include files.
|
||
**
|
||
** Revision 1.13 1995/04/12 22:27:52 bduggan
|
||
** Made non-ansi compatible.
|
||
**
|
||
** Revision 1.12 1994/10/03 16:18:52 nadeau
|
||
** Built table initializations in to code instead of using external
|
||
** include files generated by the Makefile. No longer seems necessary
|
||
** to generate on-the-fly since the value set is relatively static.
|
||
** Fixed a bug in reading & writing structures that failed to advance
|
||
** through memory correctly on non-32-bit architectures.
|
||
** Updated to ANSI C and C++ compatibility.
|
||
** Removed all use of register keyword.
|
||
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
|
||
** Added forward declarations.
|
||
** Added misc. casts to passify SGI and DEC compilers.
|
||
** Updated comments.
|
||
** Updated indenting on some code.
|
||
** Updated copyright message.
|
||
**
|
||
** Revision 1.11 92/09/02 13:28:57 vle
|
||
** Updated copyright notice.
|
||
**
|
||
** Revision 1.10 92/03/04 09:19:54 nadeau
|
||
** Fixed bugs in BinSWriteStruct and BinSReadStruct. Both were
|
||
** forgetting to increment the output/input 'data' buffer from
|
||
** struct field to struct field. The resulting read and write
|
||
** operations failed to read or write from the correct locations.
|
||
**
|
||
** Revision 1.9 91/12/23 11:43:01 nadeau
|
||
** Corrected comments. Optimized code throughout. Added generic
|
||
** byte read and write functions to handle I/O to the various
|
||
** ioType's (fd, fp, and string). Added support for string read
|
||
** and write (BinSRead, BinSWrite, etc). Simplified and reduced
|
||
** bulky code.
|
||
**
|
||
** Revision 1.8 91/10/03 13:06:38 nadeau
|
||
** Changed binread/binwrite to accept counts of 0 and
|
||
** just return silently.
|
||
**
|
||
** Revision 1.7 91/09/17 19:18:43 nadeau
|
||
** Misc changes to comments. Removed some ifdefs for MBF/LBF
|
||
** handling in favor of a defined BINHOSTBO constant. Removed
|
||
** bzero alternate code. Assume bzero is available.
|
||
**
|
||
** Revision 1.6 91/03/11 16:34:23 nadeau
|
||
** Fixed bug in float write case: was calling write() when
|
||
** should have called fwrite().
|
||
**
|
||
** Revision 1.5 91/01/09 16:36:52 nadeau
|
||
** Added BinQError().
|
||
**
|
||
** Revision 1.4 90/06/25 10:38:11 ferrerj
|
||
** Added IBM floating point format.
|
||
**
|
||
** Revision 1.3 90/05/16 12:20:45 nadeau
|
||
** Added code to handle file pointers as well as file descriptors.
|
||
** Previous code just got the fileno() of the fp and used the file
|
||
** descriptor code. This caused problems with data already in the
|
||
** input/output buffers.
|
||
**
|
||
** Revision 1.2 90/04/23 14:11:05 nadeau
|
||
** Changed BinErrno to BinErrNo.
|
||
**
|
||
** Revision 1.1 89/12/14 13:56:57 nadeau
|
||
** Initial revision
|
||
**
|
||
**/
|
||
/*LINTLIBRARY*/
|
||
|
||
#include "sdsccopyright.h"
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include "sdsc.h"
|
||
#include <string.h>
|
||
#include <malloc.h>
|
||
#include <stdlib.h>
|
||
//#include <unistd.h>
|
||
|
||
#ifndef NULL
|
||
#define NULL (0)
|
||
#endif
|
||
|
||
#ifndef FALSE
|
||
#define FALSE 0
|
||
#endif
|
||
|
||
#ifndef TRUE
|
||
#define TRUE 1
|
||
#endif
|
||
|
||
#define BINMAXBUF (40*sizeof( int ))/* Max size before dynamic alloc*/
|
||
|
||
#define FPIO 1
|
||
#define FDIO 2
|
||
#define DATAIO 3
|
||
|
||
#ifdef MBF
|
||
#define BINHOSTBO BINMBF
|
||
#else
|
||
#define BINHOSTBO BINLBF
|
||
#endif
|
||
|
||
#define BINERROR(errno,ret) {BinErrNo = (errno);return(ret);}
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION DECLARATIONS
|
||
*/
|
||
|
||
#ifdef __STDC__
|
||
static void binInitialize( void );
|
||
static int binNoHandler( int, int, int, void *, int, int );
|
||
static int binDefaultHandler( int, int, int, void *, int, int );
|
||
static int binByteRead( int, int, FILE *, unsigned char *, unsigned char *, int );
|
||
static int binByteWrite( int, int, FILE *, unsigned char *, unsigned char *, int );
|
||
static int binReadCharMBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binReadCharLBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binWriteCharMBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binWriteCharLBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binReadIntMBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binReadIntLBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binWriteIntMBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binWriteIntLBF( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binReadFloat( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
static int binWriteFloat( int, int, FILE *, unsigned char *, unsigned char *, int, int, int );
|
||
#else
|
||
|
||
static void binInitialize( );
|
||
static int binNoHandler( );
|
||
static int binDefaultHandler( );
|
||
static int binByteRead( );
|
||
static int binByteWrite( );
|
||
static int binReadCharMBF( );
|
||
static int binReadCharLBF( );
|
||
static int binWriteCharMBF( );
|
||
static int binWriteCharLBF( );
|
||
static int binReadIntMBF( );
|
||
static int binReadIntLBF( );
|
||
static int binWriteIntMBF( );
|
||
static int binWriteIntLBF( );
|
||
static int binReadFloat( );
|
||
static int binWriteFloat( );
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* BinErrNo - error number
|
||
* BinNErr - number of error messages
|
||
* BinErrList - error messages
|
||
* binErrFunc - error condition handler function
|
||
*
|
||
* DESCRIPTION
|
||
* On an error, the binary I/O package routines return -1 and set
|
||
* BinErrNo to an error code. The programmer may call BinPError
|
||
* to print the associated error message to stderr, or may do the
|
||
* message lookup in BinErrList themselves.
|
||
*/
|
||
int BinErrNo = -1; /* Bin package error number */
|
||
char *BinErrList[] = /* Error message list */
|
||
{
|
||
/* BINESYS */ "System error: see errno",
|
||
/* BINETYPE */ "Unknown type selection",
|
||
/* BINENBYTES */ "nBytes cannot be <= 0",
|
||
/* BINECOUNT */ "count cannot be <= 0",
|
||
/* BINEBYTEORDER */ "Unknown file byte order selection",
|
||
/* BINEMALLOC */ "Cannot malloc more host memory",
|
||
/* BINEFLOATFORMAT */ "Unknown floating point format selection",
|
||
/* BINEFLOATUNSUPPORTED*/"Unsupported size for file floating point selection",
|
||
};
|
||
int BinNErr = 8; /* Number of error messages */
|
||
#ifdef __STDC__
|
||
static int (*binErrFunc)( int, int, int, void *, int, int ) = NULL;
|
||
/* Error condition callback func */
|
||
#else
|
||
static int (*binErrFunc)( ) = NULL;
|
||
/* Error condition callback func */
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binTypeName - names of the types
|
||
*
|
||
* DESCRIPTION
|
||
* To aid in debugging, binTypeName gives the character string name for
|
||
* a type.
|
||
*/
|
||
static char *binTypeName[BINNTYPE] =
|
||
{
|
||
"pointer",
|
||
"char",
|
||
"unsigned char",
|
||
"short",
|
||
"long",
|
||
"int",
|
||
"int8",
|
||
"int16",
|
||
"int32",
|
||
"unsigned short",
|
||
"unsigned long",
|
||
"unsigned int",
|
||
"unsigned int8",
|
||
"unsigned int16",
|
||
"unsigned int32",
|
||
"boolean",
|
||
"float",
|
||
"double",
|
||
"int64",
|
||
"unsigned int64"
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binTypeSize - size of each type, as stored by host
|
||
* binTypeRes - resolution of each type, as used by host
|
||
*
|
||
* DESCRIPTION
|
||
* binTypeSize holds the size, in bytes, of each type supported
|
||
* by this package. The size is defined as the number of bytes
|
||
* a single item of this type takes up in memory on the host.
|
||
*
|
||
* binTypeRes holds the resolution, in bytes, of each type. The
|
||
* resolution is defined as the number of bytes ** ACTUALLY USED **
|
||
* by the host in manipulating an item of this type.
|
||
*
|
||
* On most systems the size of a type and the resolution of a type
|
||
* are the same. A 'short' on a SPARCstation takes up 2 bytes of
|
||
* memory and can hold 2 bytes worth of data (16 bits). However,
|
||
* on some systems, most notibly the Cray, the size and resolution of
|
||
* some types differ. A 'short' on a CRAY-XMP takes up 8 bytes of
|
||
* memory but can only hold 3 bytes of data (24 bits).
|
||
*
|
||
* In processing items we need to know the size of an item so that
|
||
* we can properly advance through an array of data treated as
|
||
* unsigned char's.
|
||
*
|
||
* We need to know the resolution of an item so that we know how
|
||
* many bytes to put into and take out of a file before padding.
|
||
*
|
||
* binTypeSize is intialized at compile time. binTypeRes is
|
||
* initialized at runtime upon its first usage.
|
||
*/
|
||
static int binTypeSize[BINNTYPE] =
|
||
{
|
||
#ifdef __STDC__
|
||
sizeof( void * ),
|
||
#else
|
||
sizeof( unsigned char * ),
|
||
#endif
|
||
sizeof( char ),
|
||
sizeof( unsigned char ),
|
||
sizeof( short ),
|
||
sizeof( long ),
|
||
sizeof( int ),
|
||
sizeof( sdsc_int8 ),
|
||
sizeof( sdsc_int16 ),
|
||
sizeof( sdsc_int32 ),
|
||
sizeof( unsigned short ),
|
||
sizeof( unsigned long ),
|
||
sizeof( unsigned int ),
|
||
sizeof( sdsc_uint8 ),
|
||
sizeof( sdsc_uint16 ),
|
||
sizeof( sdsc_uint32 ),
|
||
sizeof( sdsc_boolean ),
|
||
sizeof( float ),
|
||
sizeof( double ),
|
||
#if LONG_SIZE >= 64
|
||
sizeof( sdsc_int64 ),
|
||
sizeof( sdsc_uint64 )
|
||
#else
|
||
0,
|
||
0
|
||
#endif
|
||
};
|
||
static int binTypeRes[BINNTYPE];
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binTypeSigned - is the type signed?
|
||
*
|
||
* DESCRIPTION
|
||
* binTypeSigned indicates whether a type is signed or not. Signed
|
||
* types require sign-extension when they are read into with fewer
|
||
* bytes than their size, and cause sign-extension when they are
|
||
* written out into greater bytes than their size.
|
||
*
|
||
* This array is initialized at compile time.
|
||
*/
|
||
static int binTypeSigned[BINNTYPE] =
|
||
{
|
||
FALSE,
|
||
TRUE,
|
||
FALSE,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE,
|
||
FALSE
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* TYPEDEF & STRUCTURE
|
||
* binPadStructxxxx - Dummy structure to figure padding
|
||
*
|
||
* DESCRIPTION
|
||
* Most compilers pad structures to move integer and float types
|
||
* to the next word or halfword boundary. BinReadStruct and
|
||
* BinWriteStruct must be aware of this padding in order to
|
||
* properly advance through the input or output buffer to the
|
||
* next field of a struct to read or write.
|
||
*
|
||
* These pad structures are only used in the initialization of the
|
||
* binTypePad[].
|
||
*/
|
||
|
||
#define PADSTRUCT(name,type) \
|
||
typedef struct name \
|
||
{ \
|
||
char bin_c; \
|
||
type bin_i; \
|
||
} name;
|
||
|
||
|
||
#ifdef __STDC__
|
||
PADSTRUCT( binPadStructpointer, void * )
|
||
#else
|
||
PADSTRUCT( binPadStructpointer, unsigned char * )
|
||
#endif
|
||
PADSTRUCT( binPadStructchar, char )
|
||
PADSTRUCT( binPadStructuchar, unsigned char )
|
||
PADSTRUCT( binPadStructshort, short )
|
||
PADSTRUCT( binPadStructlong, long )
|
||
PADSTRUCT( binPadStructint, int )
|
||
PADSTRUCT( binPadStructint8, sdsc_int8 )
|
||
PADSTRUCT( binPadStructint16, sdsc_int16 )
|
||
PADSTRUCT( binPadStructint32, sdsc_int32 )
|
||
PADSTRUCT( binPadStructushort, unsigned short )
|
||
PADSTRUCT( binPadStructulong, unsigned long )
|
||
PADSTRUCT( binPadStructuint, unsigned int )
|
||
PADSTRUCT( binPadStructuint8, sdsc_uint8 )
|
||
PADSTRUCT( binPadStructuint16, sdsc_uint16 )
|
||
PADSTRUCT( binPadStructuint32, sdsc_uint32 )
|
||
PADSTRUCT( binPadStructboolean, sdsc_boolean )
|
||
PADSTRUCT( binPadStructfloat, float )
|
||
PADSTRUCT( binPadStructdouble, double )
|
||
#if LONG_SIZE >= 64
|
||
PADSTRUCT( binPadStructint64, sdsc_int64 )
|
||
PADSTRUCT( binPadStructuint64, sdsc_uint64 )
|
||
#endif
|
||
|
||
#undef PADSTRUCT
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binTypePad - how are types padded?
|
||
* binTypePadMask - how are type's padding addresses masked?
|
||
*
|
||
* DESCRIPTION
|
||
* Each entry in this array gives the padding boundary to advance to
|
||
* for a particular field type when padding structures. For instance,
|
||
* on most 32-bit machines, structure fields of type 'short' are padded
|
||
* to bring them to the next 16-bit boundary, while fields of type
|
||
* 'long' are padded to the next 32-bit boundary. A structure like
|
||
* the following:
|
||
* struct example
|
||
* {
|
||
* char c1;
|
||
* short s;
|
||
* char c2;
|
||
* long l;
|
||
* };
|
||
* actually occupies space like the following:
|
||
* struct example
|
||
* {
|
||
* char c1;
|
||
* char pad1;
|
||
* short s;
|
||
* char c2;
|
||
* char pad2[3];
|
||
* long l;
|
||
* };
|
||
*
|
||
* BinReadStruct and BinWriteStruct must know about such padding in
|
||
* order to properly advance from field to field within the structure.
|
||
*
|
||
* The above dummy padding structure declarations create one structure
|
||
* for each supported type. The structure declares a single character
|
||
* field, followed by a subject field. By calculating the difference
|
||
* in the addresses between these two fields, we get the byte boundary
|
||
* the type must be padded to. A value of 1 means no padding.
|
||
*
|
||
* The binTypePadMask array is an array of address masks, one per type.
|
||
* The mask is calculated to mask off the relevant bits in a char ptr
|
||
* that should be 0 for the type's alignment needs. For instance,
|
||
* on a byte-addressed machine (like a Sun) that aligns int's to 4-byte
|
||
* boundaries, the mask would be 0x3. The mask is used in code like:
|
||
*
|
||
* if ( ((int)addr & mask) != 0 )
|
||
* addr = (addr & ~mask) + pad;
|
||
*
|
||
* The pad and mask tables are both initialized at runtime.
|
||
*/
|
||
static int binTypePad[BINNTYPE];
|
||
static unsigned long binTypePadMask[BINNTYPE];
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binFileBO - current file byte order
|
||
* binReadMBFDisp - array of MBF handling functions
|
||
* binReadLBFDisp - array of LBF handling functions
|
||
* binReadDisp - pointer to the current read function array
|
||
*
|
||
* binWriteMBFDisp - array of MBF handling functions
|
||
* binWriteLBFDisp - array of LBF handling functions
|
||
* binWriteDisp - pointer to the current write function array
|
||
*
|
||
* DESCRIPTION
|
||
* The output file will be read or written assuming the byte order
|
||
* is that selected by binFileBO. The programmer may call BinByteOrder
|
||
* to change that byte order.
|
||
*
|
||
* The read and write dispatch tables point to functions to read or
|
||
* write files in the current byte order.
|
||
*
|
||
* ** MBF and LBF here refer to the byte order **
|
||
* ** of data in the file, not on the host! **
|
||
*
|
||
* Each of the read functions read in 'nBytes' bytes from the file, then
|
||
* save the least-significant bytes into the user's buffer. When file
|
||
* data is in MBF form (the default), the least-significant bytes are
|
||
* the last ones read in. When file data is in LBF form, the least-
|
||
* significant bytes are the first ones read in.
|
||
*
|
||
* Each of the write functions write the 'nBytes' least-significant bytes
|
||
* of items in the user's buffer to the file. When file data is to be in
|
||
* MBF form, the least-significant bytes are the last ones written out.
|
||
* When file data is to be in LBF form, the least-significant bytes are
|
||
* the first ones written out.
|
||
*
|
||
* What's the significance of reading and writing only the 'nBytes'
|
||
* least-significant bytes? Consider writing out a 32-bit integer that
|
||
* is stored in a 64-bit word. For numbers that take 32-bits or less
|
||
* to represent, it is the lower 32-bits of the 64-bit word that hold
|
||
* the value. For numbers that take more than 32-bits, the number must be
|
||
* truncated in order to write it out in 32-bits. Truncation traditionally
|
||
* happens from the top of the word. So, writing the least-significant
|
||
* 'nBytes' of each incomming data item handles both cases. The
|
||
* situation is similar for reading.
|
||
*/
|
||
|
||
static int binFileBO = BINMBF; /* File data byte order */
|
||
|
||
#ifdef __STDC__
|
||
static int (*binReadMBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
|
||
#else
|
||
static int (*binReadMBFDisp[])() =
|
||
#endif
|
||
{
|
||
binReadIntMBF,
|
||
binReadCharMBF,
|
||
binReadCharMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
binReadFloat,
|
||
binReadFloat,
|
||
#if LONG_SIZE >= 64
|
||
binReadIntMBF,
|
||
binReadIntMBF,
|
||
#else
|
||
NULL,
|
||
NULL,
|
||
#endif
|
||
};
|
||
|
||
#ifdef __STDC__
|
||
static int (*binReadLBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
|
||
#else
|
||
static int (*binReadLBFDisp[])() =
|
||
#endif
|
||
{
|
||
binReadIntLBF,
|
||
binReadCharLBF,
|
||
binReadCharLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
binReadFloat,
|
||
binReadFloat,
|
||
#if LONG_SIZE >= 64
|
||
binReadIntLBF,
|
||
binReadIntLBF,
|
||
#else
|
||
NULL,
|
||
NULL,
|
||
#endif
|
||
};
|
||
|
||
#ifdef __STDC__
|
||
static int (*binWriteMBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
|
||
#else
|
||
static int (*binWriteMBFDisp[])() =
|
||
#endif
|
||
{
|
||
binWriteCharMBF,
|
||
binWriteCharMBF,
|
||
binWriteCharMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
binWriteFloat,
|
||
binWriteFloat,
|
||
#if LONG_SIZE >= 64
|
||
binWriteIntMBF,
|
||
binWriteIntMBF,
|
||
#else
|
||
NULL,
|
||
NULL,
|
||
#endif
|
||
};
|
||
|
||
#ifdef __STDC__
|
||
static int (*binWriteLBFDisp[])(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int) =
|
||
#else
|
||
static int (*binWriteLBFDisp[])() =
|
||
#endif
|
||
{
|
||
binWriteCharLBF,
|
||
binWriteCharLBF,
|
||
binWriteCharLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
binWriteFloat,
|
||
binWriteFloat,
|
||
#if LONG_SIZE >= 64
|
||
binWriteIntLBF,
|
||
binWriteIntLBF,
|
||
#else
|
||
NULL,
|
||
NULL,
|
||
#endif
|
||
};
|
||
|
||
#ifdef __STDC__
|
||
static int (**binReadDisp)(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int)
|
||
= binReadMBFDisp;
|
||
static int (**binWriteDisp)(int , int , FILE*, unsigned char *, unsigned char *, int ,int , int)
|
||
= binWriteMBFDisp;
|
||
#else
|
||
static int (**binReadDisp)() = binReadMBFDisp;
|
||
static int (**binWriteDisp)() = binWriteMBFDisp;
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* Host's floating point type.
|
||
*/
|
||
#if FLOAT_TYPE == IEEE_FLOAT
|
||
#define BINHOSTFLOAT BINIEEE
|
||
#endif
|
||
|
||
#if FLOAT_TYPE == VAX_FLOAT
|
||
#define BINHOSTFLOAT BINVAX
|
||
#endif
|
||
|
||
#if FLOAT_TYPE == VAXG_FLOAT
|
||
#define BINHOSTFLOAT BINVAXG
|
||
#endif
|
||
|
||
#if FLOAT_TYPE == CRAYMP_FLOAT
|
||
#define BINHOSTFLOAT BINCRAYMP
|
||
#endif
|
||
|
||
|
||
#ifndef BINHOSTFLOAT
|
||
/*
|
||
* Crash and Burn:
|
||
* If the host's floating type is unknown, generate a syntax error
|
||
* to bring the programmer here...
|
||
*/
|
||
<<<<--+=+ Syntax Error +=+-->>>> /* Read message below!!! */
|
||
|
||
/*
|
||
* Programmer! This syntax error was generated because the floating point
|
||
* type used by this host is currently unknown by this package. This
|
||
* prevents the functioning of code to convert from the host's floating
|
||
* point format to that of another machine.
|
||
*
|
||
* Please read the comments describing the 'binFloatFormatInfo' struct and the
|
||
* initialization of the 'binFloatFormats' array below to learn about
|
||
* floating point formats and how to set them up for this host. Please do
|
||
* not simply default them to something you think is right. Check and make
|
||
* sure! Bugs arising from faulty defaulting can be very hard to find.
|
||
*
|
||
* When you have a format defined for this host, please forward it to us for
|
||
* inclusion in a future release of this software. Thanks!
|
||
*/
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* STRUCTURE & TYPEDEF
|
||
* binFloatFormatInfo - floating point format description
|
||
*
|
||
* DESCRIPTION
|
||
* The binFloatFormatInfo struct describes the attributes of a floating
|
||
* point format. The values provided make it possible to generically
|
||
* convert a float from one format to another.
|
||
*
|
||
* Floating point numbers have three pieces:
|
||
* sign positive or negative flag
|
||
* exponent the power to raise the mantissa to
|
||
* mantissa the fractional part of the float
|
||
*
|
||
* The sign is a 1-bit value that indicates if the floating point value
|
||
* is positive or negative. Negative floats set the sign bit to a 1.
|
||
*
|
||
* The exponent is the power to which the float is raised. The exponent
|
||
* is "biased" to make it a positive value. For instance, in IEEE
|
||
* single-precision, the exponent is 8-bits wide and its bias is 127.
|
||
* An unbiased 8-bit value can represent a signed value between -127 and
|
||
* +128, or an unsigned value from 0 to 255. Biasing the exponent makes
|
||
* it always positive (unsigned) in representation, yet still allows
|
||
* negative exponents. So, with an IEEE bias of 127, the exponent
|
||
* -10 would be represented as: -10 + 127 = 117.
|
||
*
|
||
* The mantissa is the fractional part of the float. When normallized,
|
||
* the upper bit of the mantissa is always a 1. Some formats keep this
|
||
* 1 bit in the float, while others remove it (calling it an implied
|
||
* bit).
|
||
*
|
||
* The binFloatFormatInfo struct uses the following fields to describe a
|
||
* floating point format:
|
||
*
|
||
* bin_name
|
||
* The character string name of the format.
|
||
*
|
||
* bin_number
|
||
* The #define number associated with this format.
|
||
*
|
||
* bin_subname
|
||
* The name of this size of the float.
|
||
*
|
||
* bin_expBits
|
||
* The number of bits in the exponent.
|
||
*
|
||
* bin_mantBits
|
||
* The number of bits in the mantissa.
|
||
*
|
||
* bin_expBias
|
||
* The exponent bias.
|
||
*
|
||
* bin_mantImplied
|
||
* Is the implied bit kept in, or removed?
|
||
*
|
||
* bin_signOverflow
|
||
* Whether the sign bit is set or not on an overflow.
|
||
*
|
||
* bin_expOverflow
|
||
* The value of the exponent on an overflow.
|
||
*
|
||
* bin_flags
|
||
* Flag special "exception" conditions in the format:
|
||
* BINVAXBO Bizzare VAX float byte order
|
||
*
|
||
* GENERAL ASSUMPTIONS
|
||
* The order of fields in a float is:
|
||
* On MBF systems:
|
||
* low high
|
||
* sign exponent mantissa
|
||
* On LBF systems:
|
||
* low high
|
||
* mantissa exponent sign
|
||
* Except when BINVAXBO is set in bin_flags, in which case bytes
|
||
* are swapped every-other to take into account of the VAX's
|
||
* strange byte ordering of floating point values.
|
||
*
|
||
* The sign is 1 bit.
|
||
*
|
||
* There are no unused bits in the float.
|
||
*
|
||
* (bin_expBits + bin_mantBits + 1) % 8 == 0.
|
||
*
|
||
* The float is normalized.
|
||
*
|
||
* SIGN ASSUMPTIONS
|
||
* If the sign is a 1, the float is negative.
|
||
*
|
||
* The sign bit is 0 when the float is 0.
|
||
*
|
||
* EXPONENT ASSUMPTIONS
|
||
* The exponent is representable as a signed 32-bit integer on the host.
|
||
*
|
||
* The exponent is zero when the float is zero.
|
||
*
|
||
* MANTISSA ASSUMPTIONS
|
||
* The mantissa is zero when the float is zero.
|
||
*
|
||
* The mantissa is zero on an overflow.
|
||
*
|
||
* NON-ASSUMPTIONS (ie, "It is **NOT** assumed that...")
|
||
* The mantissa is storeable in an integer on the host.
|
||
*
|
||
* The # of bits in the exponent or mantissa are modulo 8 or that
|
||
* the exponent starts on a byte boundary.
|
||
*
|
||
* The redundant high bit of the mantissa on a normalized float is dropped.
|
||
*/
|
||
|
||
typedef struct binFloatFormatInfo
|
||
{
|
||
char *bin_name; /* Name of format */
|
||
/* NULL flags end of list */
|
||
int bin_number; /* Format number */
|
||
char *bin_subname; /* Name of this size of the format */
|
||
/* NULL flags unusable entry */
|
||
int bin_expBits; /* Number of bits in exponent */
|
||
int bin_mantBits; /* Number of bits in mantissa */
|
||
int bin_expBias; /* Exponent bias */
|
||
int bin_mantImplied; /* Is implied bit saved in format? */
|
||
int bin_signOverflow; /*Is sign bit set on overflow? */
|
||
unsigned int bin_expOverflow;/* Exponent value on overflow */
|
||
int bin_flags; /* Excpetion flags */
|
||
} binFloatFormatInfo;
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* CONSTANTS
|
||
* BINVAXBO - Bizzare VAX floating point byte order exception
|
||
*/
|
||
|
||
#define BINVAXBO 0x1
|
||
/* 0x2-0x800000 Reserved */
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binFloatFormats - List of supported floating point formats
|
||
*
|
||
* DESCRIPTION
|
||
* The binFloatFormats array of binFloatFormatInfo structs lists the
|
||
* attributes of each of the floating point formats supported.
|
||
*
|
||
* TO ADD A NEW FORMAT
|
||
* 1. Create one or more entries in the array initilaization below.
|
||
*
|
||
* 2. Make up a name for the format and create a #define BINname in
|
||
* bin.raw.h.
|
||
*
|
||
* 3. Add an #if FLOAT_TYPE for the format to define the BINHOSTFLOAT
|
||
* constant on hosts that support that float (the #if's are just
|
||
* before the description of the BinFloatFormat struct).
|
||
*
|
||
* NOTE: The list is terminated by a NULL pointer in bin_name.
|
||
* Additionally, a NULL pointer for bin_subname flags that entry as
|
||
* unusable.
|
||
*
|
||
* NOTE NOTE: Different precisions of the same format must be grouped
|
||
* together!
|
||
*/
|
||
|
||
#ifndef YES
|
||
#define YES 1
|
||
#endif
|
||
|
||
#ifndef NO
|
||
#define NO 0
|
||
#endif
|
||
|
||
binFloatFormatInfo binFloatFormats[ ] =
|
||
{
|
||
|
||
/* # bits overflow */
|
||
/* name number subname exp mant bias imp? sgn? exp flags*/
|
||
{ "IEEE", BINIEEE, "single", 8, 23, 127, NO, YES, 0x0FF, 0 },
|
||
{ "IEEE", BINIEEE, "double", 11, 52, 1023, NO, YES, 0x7FF, 0 },
|
||
{ "CRAYMP", BINCRAYMP, "single", 15, 48, 16384, YES, NO, 0x6000, 0 },
|
||
{ "VAX", BINVAX, "f", 8, 23, 129, NO, YES, 0, BINVAXBO },
|
||
{ "VAX", BINVAX, "d", 8, 55, 129, NO, YES, 0, BINVAXBO },
|
||
{ "VAX", BINVAX, "h", 15, 112, 16385, NO, YES, 0, BINVAXBO },
|
||
{ "VAXG", BINVAXG, "f", 8, 23, 129, NO, YES, 0, BINVAXBO },
|
||
{ "VAXG", BINVAXG, "g", 11, 52, 1025, NO, YES, 0, BINVAXBO },
|
||
{ "VAXG", BINVAXG, "h", 15, 112, 16385, NO, YES, 0, BINVAXBO },
|
||
#ifdef notdef
|
||
{ "IBM", BINIBM, "f", 7, 24, 63, NO, YES, 0, 0 },
|
||
#endif
|
||
{ NULL, -1, NULL, 0, 0, 0, NO, NO, 0, 0 },
|
||
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* STRUCTURE & TYPEDEF
|
||
* binFloatFormatCooked - cooked floating point format description
|
||
*
|
||
* DESCRIPTION
|
||
* The binFloatFormatCooked struct describes the attributes of a floating
|
||
* point format (as does the BinFloatFormat struct), but also includes
|
||
* some pre-calculated byte counts, shifts, and masks that help speed
|
||
* up the conversion algorithm.
|
||
*
|
||
* The binFloatFormatCooked struct uses these fields to describe the
|
||
* floating point format:
|
||
*
|
||
* bin_format
|
||
* A copy of the data from the binFloatFormatInfo struct.
|
||
*
|
||
* bin_nbytes
|
||
* The number of bytes it takes to store this float.
|
||
*
|
||
* bin_expStartByte
|
||
* bin_expEndByte
|
||
* The byte numbers of the first and last bytes
|
||
* containing exponent bits.
|
||
*
|
||
* bin_expStartMask
|
||
* bin_expEndMask
|
||
* An 8-bit mask to extract only the relevant exponent
|
||
* bits from the first and last bytes of the exponent.
|
||
*
|
||
* bin_expShift
|
||
* The number of bits in the starting byte NOT used
|
||
* for the exponent (ie, how far to shift the starting
|
||
* byte left to bring the 1st exponent bit into the
|
||
* 1st bit of the byte).
|
||
*
|
||
* bin_expMask
|
||
* A 32-bit mask to apply to an unsigned integer that
|
||
* will leave only the exponent bits.
|
||
*/
|
||
|
||
typedef struct binFloatFormatCooked
|
||
{
|
||
binFloatFormatInfo bin_format; /* Raw format */
|
||
int bin_nbytes; /* Size, in bytes, of this entry*/
|
||
|
||
int bin_expStartByte; /* Byte containing exponent start*/
|
||
int bin_expEndByte; /* Byte containing exponent end */
|
||
|
||
unsigned char bin_expStartMask; /* Mask for starting exponent byte*/
|
||
unsigned char bin_expEndMask; /* Mask for ending exponent byte*/
|
||
int bin_expShift; /* Shift for starting exponent byte*/
|
||
unsigned int bin_expMask; /* Mask to just get relevant bits*/
|
||
} binFloatFormatCooked;
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binFloatFormatsCooked - cooked floating point format descriptions
|
||
*
|
||
* DESCRIPTION
|
||
* The binFloatFormatsCooked array gives the "cooked" (after pre-calc)
|
||
* version of the data in the binFloatFormats array. It is the
|
||
* cooked version of the data that is actually used by the floating
|
||
* point conversion code.
|
||
*
|
||
* This array is initialized at startup by binInitialize().
|
||
*/
|
||
binFloatFormatCooked binFloatFormatsCooked[sizeof(binFloatFormats)/sizeof(binFloatFormatInfo)];
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binHostFloatFormat - Host floating point format description
|
||
* binFileFloatFormat - File floating point format description
|
||
*
|
||
* DESCRIPTION
|
||
* binHostFloatFormat points to the set of floating point format
|
||
* descriptions appropriate for the host.
|
||
*
|
||
* binFileFloatFormat points to the set of floating point format
|
||
* descriptions selected for the file.
|
||
*
|
||
* Both of these globals are initialized at startup by binInitialize().
|
||
*/
|
||
binFloatFormatCooked *binFileFloatFormat = NULL;
|
||
binFloatFormatCooked *binHostFloatFormat = NULL;
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* GLOBAL VARIABLE
|
||
* binOp - Current operation
|
||
*
|
||
* DESCRIPTION
|
||
* Each of the top level read or write functions set binOp to the
|
||
* operation type being done so that, should an error occur, the
|
||
* user's error handler can be told what operation was in progress.
|
||
*/
|
||
static int binOp; /* Current operation (for error handling)*/
|
||
|
||
|
||
|
||
#ifdef __STDC__
|
||
static int binConvertFloat( int, binFloatFormatCooked *, int, int, unsigned char *, binFloatFormatCooked *, int, int, unsigned char *, int );
|
||
#else
|
||
static int binConvertFloat( );
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* binInit - tables initialized yet?
|
||
* binInitialize - Initialize the tables
|
||
*
|
||
* DESCRIPTION
|
||
* This routine initializes the tables:
|
||
* binTypeRes - type resolution
|
||
* binTypePad - type structure field padding
|
||
* binTypePadMask - type padding address masks
|
||
* binFloatFormatsCooked - cooked float information
|
||
*
|
||
* determines the floating point type of the host:
|
||
* binHostFloatFormat - host format selection
|
||
*
|
||
* and the default floating point type for the file:
|
||
* binFileFloatFormat - file format selection
|
||
*
|
||
* The resolution table indicates the number of bytes in a type that
|
||
* are actually available for storing data, as opposed to the number
|
||
* of bytes the type occupies in memory. On most machines these
|
||
* two values are the same. A notible exception is the CRAY's 'short'
|
||
* which occupies 8 bytes in memory, but can only hold a 3 byte value.
|
||
*
|
||
* The padding table indicates how the various types are padded when
|
||
* they occur as fields in a structure. To initialize the table we
|
||
* compute the difference between a char structure field's address
|
||
* and the address of a field of the desired type. If padding has
|
||
* taken place, the difference will be greater than 1 byte.
|
||
*
|
||
* Many machines require that all integer or floating point accesses
|
||
* be made at boundaries that are a multiple of the item size. For
|
||
* instance, on a SPARCstation all 32-bit integers must be on 32-bit
|
||
* boundaries, and all 16-bit integers on 16-bit boundaries. Accesses
|
||
* that are not word aligned cause a bus error.
|
||
*
|
||
* Compilers for machines that do not require word alignment may still
|
||
* do structure padding, such as the VAX ULTRIX compiler.
|
||
*
|
||
* Still other compilers do no structure padding, such as the VAX
|
||
* VMS compiler.
|
||
*
|
||
* The Cooked formats table includes the basic floating point format
|
||
* information from binFloatFormats[], plus various masks and byte
|
||
* counts to make floating point conversions easier and quicker.
|
||
*/
|
||
|
||
static int binInit = FALSE;
|
||
|
||
static void /* Returns nothing */
|
||
#ifdef __STDC__
|
||
binInitialize( void )
|
||
#else
|
||
binInitialize( )
|
||
#endif
|
||
{
|
||
int *br = binTypeRes; /* Pointer to Res table */
|
||
int *bp = binTypePad; /* Pointer to Pad table */
|
||
unsigned long charbit; /* Address bit for byte addressing */
|
||
unsigned long shiftbit; /* How far to shift to get to charbit */
|
||
int i; /* Counter */
|
||
binFloatFormatInfo *fp; /* Float format table pointer */
|
||
binFloatFormatCooked *fcp;/* Cooked format table pointer */
|
||
int nbits; /* Number of extra bits in byte */
|
||
binPadStructpointer structpointer;
|
||
binPadStructchar structchar;
|
||
binPadStructuchar structuchar;
|
||
binPadStructshort structshort;
|
||
binPadStructlong structlong;
|
||
binPadStructint structint;
|
||
binPadStructint8 structint8;
|
||
binPadStructint16 structint16;
|
||
binPadStructint32 structint32;
|
||
binPadStructushort structushort;
|
||
binPadStructulong structulong;
|
||
binPadStructuint structuint;
|
||
binPadStructuint8 structuint8;
|
||
binPadStructuint16 structuint16;
|
||
binPadStructuint32 structuint32;
|
||
binPadStructboolean structboolean;
|
||
binPadStructfloat structfloat;
|
||
binPadStructdouble structdouble;
|
||
#if LONG_SIZE >= 64
|
||
binPadStructint64 structint64;
|
||
binPadStructuint64 structuint64;
|
||
#endif
|
||
|
||
/*
|
||
* Initialize the resolution table.
|
||
*/
|
||
|
||
#define DEF(type) \
|
||
{ \
|
||
type var = ((type)1)<<(8*sizeof(type)-2);\
|
||
var <<= 1; \
|
||
if ( var != ((type)0) ) \
|
||
*br++ = sizeof(type); \
|
||
else \
|
||
{ \
|
||
int ii = 1; \
|
||
for ( var = ((type)1); var != ((type)0); var <<= 1 )\
|
||
ii++; \
|
||
*br++ = ii>>3; \
|
||
} \
|
||
}
|
||
*br++ = 0; /* skip pointer */
|
||
DEF(char)
|
||
DEF(unsigned char)
|
||
DEF(short)
|
||
DEF(long)
|
||
DEF(int)
|
||
DEF(sdsc_int8)
|
||
DEF(sdsc_int16)
|
||
DEF(sdsc_int32)
|
||
DEF(unsigned short)
|
||
DEF(unsigned long)
|
||
DEF(unsigned int)
|
||
DEF(sdsc_uint8)
|
||
DEF(sdsc_uint16)
|
||
DEF(sdsc_uint32)
|
||
DEF(sdsc_boolean)
|
||
*br++ = 0; /* skip float */
|
||
*br++ = 0; /* skip double */
|
||
#if LONG_SIZE >= 64
|
||
DEF(sdsc_int64)
|
||
DEF(sdsc_uint64)
|
||
#else
|
||
*br++ = 0;
|
||
*br++ = 0;
|
||
#endif
|
||
|
||
#undef DEF
|
||
|
||
|
||
/*
|
||
* Initialize the structure padding table.
|
||
*/
|
||
*bp++ = (char *)&structpointer.bin_i-&structpointer.bin_c;
|
||
*bp++ = (char *)&structchar.bin_i-&structchar.bin_c;
|
||
*bp++ = (char *)&structuchar.bin_i-&structuchar.bin_c;
|
||
*bp++ = (char *)&structshort.bin_i-&structshort.bin_c;
|
||
*bp++ = (char *)&structlong.bin_i-&structlong.bin_c;
|
||
*bp++ = (char *)&structint.bin_i-&structint.bin_c;
|
||
*bp++ = (char *)&structint8.bin_i-&structint8.bin_c;
|
||
*bp++ = (char *)&structint16.bin_i-&structint16.bin_c;
|
||
*bp++ = (char *)&structint32.bin_i-&structint32.bin_c;
|
||
*bp++ = (char *)&structushort.bin_i-&structushort.bin_c;
|
||
*bp++ = (char *)&structulong.bin_i-&structulong.bin_c;
|
||
*bp++ = (char *)&structuint.bin_i-&structuint.bin_c;
|
||
*bp++ = (char *)&structuint8.bin_i-&structuint8.bin_c;
|
||
*bp++ = (char *)&structuint16.bin_i-&structuint16.bin_c;
|
||
*bp++ = (char *)&structuint32.bin_i-&structuint32.bin_c;
|
||
*bp++ = (char *)&structboolean.bin_i-&structboolean.bin_c;
|
||
*bp++ = (char *)&structfloat.bin_i-&structfloat.bin_c;
|
||
*bp++ = (char *)&structdouble.bin_i-&structdouble.bin_c;
|
||
#if LONG_SIZE >= 64
|
||
*bp++ = (char *)&structint64.bin_i-&structint64.bin_c;
|
||
*bp++ = (char *)&structuint64.bin_i-&structuint64.bin_c;
|
||
#else
|
||
*bp++ = -1;
|
||
*bp++ = -1;
|
||
#endif
|
||
|
||
|
||
/*
|
||
* Initialize the structure padding mask table.
|
||
*/
|
||
charbit = (unsigned long)((char *)&i + 1) - (unsigned long)(char *)&i;
|
||
for ( shiftbit = ((unsigned long)(-1)); charbit != 0; shiftbit++ )
|
||
charbit >>= 1;
|
||
for ( i = 0; i < BINMAXTYPE; i++ )
|
||
binTypePadMask[i] = ((unsigned long)(binTypePad[i]-1))<<shiftbit;
|
||
|
||
|
||
/*
|
||
* Initialize the cooked floating point format table.
|
||
*/
|
||
for ( fp = binFloatFormats, fcp = binFloatFormatsCooked;
|
||
fp->bin_name != NULL; fp++, fcp++ )
|
||
{
|
||
fcp->bin_format = *fp;
|
||
fcp->bin_nbytes = (fp->bin_expBits + fp->bin_mantBits + 1)/8;
|
||
|
||
if ( (fp->bin_expBits + fp->bin_mantBits + 1) % 8 != 0 )
|
||
{
|
||
/* Illegal entry. */
|
||
fcp->bin_format.bin_subname = NULL;
|
||
continue;
|
||
}
|
||
|
||
fcp->bin_expStartByte = fp->bin_mantBits / 8;
|
||
fcp->bin_expShift = nbits = fp->bin_mantBits % 8;
|
||
fcp->bin_expStartMask = (unsigned char) (((unsigned long)0xFF) << nbits);
|
||
|
||
/* Assume last byte is end byte and last bit is sign. */
|
||
fcp->bin_expEndByte = fcp->bin_nbytes - 1;
|
||
fcp->bin_expEndMask = (unsigned char)((unsigned long)0x7F);
|
||
fcp->bin_expMask = (unsigned int) (~( (~((unsigned long)0)) << fp->bin_expBits));
|
||
}
|
||
|
||
|
||
/*
|
||
* Initialize the host and file floating point format selections.
|
||
*/
|
||
for ( fcp = binFloatFormatsCooked; fcp->bin_format.bin_name != NULL; fcp++ )
|
||
{
|
||
if ( fcp->bin_format.bin_number == BINHOSTFLOAT )
|
||
{
|
||
binHostFloatFormat = fcp;
|
||
break;
|
||
}
|
||
}
|
||
if ( binFileFloatFormat == NULL )
|
||
{
|
||
for ( fcp = binFloatFormatsCooked; fcp->bin_format.bin_name != NULL; fcp++ )
|
||
{
|
||
if ( fcp->bin_format.bin_number == BINIEEE )
|
||
{
|
||
binFileFloatFormat = fcp;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
binErrFunc = binDefaultHandler;
|
||
|
||
binInit = TRUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinQMachine - query machine characteristics
|
||
*
|
||
* DESCRIPTION
|
||
* The tables are initialized, if not done already, and a static
|
||
* BinMachineInfo struct set up. A pointer to the info is returned.
|
||
*/
|
||
|
||
static BinMachineInfo binMachine; /* Machine info struct */
|
||
|
||
|
||
BinMachineInfo * /* Returns ptr to info struct */
|
||
#ifdef __STDC__
|
||
BinQMachine( void )
|
||
#else
|
||
BinQMachine( )
|
||
#endif
|
||
{
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
memset( (void *)&binMachine, 0x00, sizeof (binMachine) );
|
||
|
||
#ifdef VENDOR_NAME
|
||
binMachine.bin_vendorName = VENDOR_NAME;
|
||
#else
|
||
binMachine.bin_vendorName = "Unknown";
|
||
#endif
|
||
|
||
#ifdef MACHINE_NAME
|
||
binMachine.bin_machineName = MACHINE_NAME;
|
||
#else
|
||
binMachine.bin_machineName = "Unknown";
|
||
#endif
|
||
|
||
#ifdef CPU_NAME
|
||
binMachine.bin_cpuName = CPU_NAME;
|
||
#else
|
||
binMachine.bin_cpuName = "Unknown";
|
||
#endif
|
||
|
||
#ifdef OS_NAME
|
||
binMachine.bin_osName = OS_NAME;
|
||
#else
|
||
binMachine.bin_osName = "Unknown";
|
||
#endif
|
||
|
||
binMachine.bin_byteOrder = BINHOSTBO;
|
||
#ifdef MBF
|
||
binMachine.bin_byteOrderName = "MBF";
|
||
#else
|
||
binMachine.bin_byteOrderName = "LBF";
|
||
#endif
|
||
|
||
binMachine.bin_floatFormat= BINHOSTFLOAT;
|
||
binMachine.bin_floatFormatName = binHostFloatFormat->bin_format.bin_name;
|
||
|
||
binMachine.bin_typeSize = binTypeSize;
|
||
binMachine.bin_typeSigned = binTypeSigned;
|
||
binMachine.bin_typeRes = binTypeRes;
|
||
binMachine.bin_typePad = binTypePad;
|
||
binMachine.bin_typeName = binTypeName;
|
||
binMachine.bin_typePadMask= binTypePadMask;
|
||
|
||
return ( &binMachine );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinPError - Print error message
|
||
*
|
||
* DESCRIPTION
|
||
* The error text associated with the current BinErrNo is printed
|
||
* to stderr, preceded by the given leader string.
|
||
*/
|
||
|
||
void /* Returns nothing */
|
||
#ifdef __STDC__
|
||
BinPError( char *s )
|
||
#else
|
||
BinPError( s )
|
||
char *s; /* Leader string */
|
||
#endif
|
||
{
|
||
if ( BinErrNo == BINESYS )
|
||
perror( s );
|
||
else if ( BinErrNo < 0 || BinErrNo >= BinNErr )
|
||
(void)fprintf( stderr, "Unknown error\n" );
|
||
else if ( s && *s )
|
||
(void)fprintf( stderr, "%s: %s\n", s, BinErrList[BinErrNo] );
|
||
else
|
||
(void)fprintf( stderr, "%s\n", BinErrList[BinErrNo] );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinQError - Query error message
|
||
*
|
||
* DESCRIPTION
|
||
* The error text associated with the current BinErrNo is returned.
|
||
*/
|
||
|
||
extern int errno; /* System call error code */
|
||
extern int sys_nerr; /* # of system call error codes */
|
||
extern char *sys_errlist[]; /* Error code message strings */
|
||
|
||
char * /* Returns error text */
|
||
#ifdef __STDC__
|
||
BinQError( void )
|
||
#else
|
||
BinQError( )
|
||
#endif
|
||
{
|
||
if ( BinErrNo == BINESYS )
|
||
{
|
||
if ( errno < 0 || errno >= sys_nerr )
|
||
return ( "Unknown error" );
|
||
return ( sys_errlist[errno] );
|
||
}
|
||
if ( BinErrNo < 0 || BinErrNo >= BinNErr )
|
||
return ( "Unknown error" );
|
||
return ( BinErrList[BinErrNo] );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinErrorHandler - nominate an error condition handler func
|
||
* binDefaultHandler - Default error condition handler
|
||
* binNoHandler - No error condition handler
|
||
*
|
||
* DESCRIPTION
|
||
* On errors in integer and floating point format conversion we call the
|
||
* nominated error condition callback function. By default it is set to
|
||
* our own stderr printing function. The user may override this by
|
||
* nominating his/her own function.
|
||
*/
|
||
|
||
void /* Returns nothing */
|
||
#ifdef __STDC__
|
||
BinErrorHandler( int (*func)(int , int , int , void *, int , int ) )
|
||
#else
|
||
BinErrorHandler( func )
|
||
int (*func)(); /* Function to nominate */
|
||
#endif
|
||
{
|
||
if ( func == BINDEFFUNC )
|
||
binErrFunc = binDefaultHandler;
|
||
else if ( func == BINNOFUNC )
|
||
binErrFunc = binNoHandler;
|
||
else
|
||
binErrFunc = func;
|
||
return;
|
||
}
|
||
|
||
static int
|
||
#ifdef __STDC__
|
||
binNoHandler( int fd, int op, int reason, void *data, int frombits, int tobits )
|
||
#else
|
||
binNoHandler( fd, op, reason, data, frombits, tobits )
|
||
int fd; /* File descriptor */
|
||
int op; /* Current operation */
|
||
int reason; /* Error reason code */
|
||
unsigned char *data; /* Data holding bad value */
|
||
int frombits; /* Max # bits in type comming from*/
|
||
int tobits; /* Max # bits in type going to */
|
||
#endif
|
||
{
|
||
return ( 0 );
|
||
}
|
||
|
||
static int /* Returns nothing */
|
||
#ifdef __STDC__
|
||
binDefaultHandler( int fd, int op, int reason, void *data, int frombits, int tobits )
|
||
#else
|
||
binDefaultHandler( fd, op, reason, data, frombits, tobits )
|
||
int fd; /* File descriptor */
|
||
int op; /* Current operation */
|
||
int reason; /* Error reason code */
|
||
unsigned char *data; /* Data holding bad value */
|
||
int frombits; /* Max # bits in type comming from*/
|
||
int tobits; /* Max # bits in type going to */
|
||
#endif
|
||
{
|
||
char opname[100]; /* Operation name */
|
||
int nBytes; /* Number of bytes */
|
||
unsigned char *pData; /* Data byte pointer */
|
||
|
||
switch ( op )
|
||
{
|
||
case BINOPREAD:
|
||
(void)sprintf( opname, "read of file %d", fd );
|
||
break;
|
||
case BINOPWRITE:
|
||
(void)sprintf( opname, "write of file %d", fd );
|
||
break;
|
||
case BINOPREADSTRUCT:
|
||
(void)sprintf( opname, "structure read of file %d", fd );
|
||
break;
|
||
case BINOPWRITESTRUCT:
|
||
(void)sprintf( opname, "structure write of file %d", fd );
|
||
break;
|
||
case BINOPCONVERTFLOAT:
|
||
(void)sprintf( opname, "floating point conversion" );
|
||
break;
|
||
default:
|
||
(void)sprintf( opname, "unknown operation" );
|
||
break;
|
||
}
|
||
|
||
nBytes = frombits / 8;
|
||
if ( frombits % 8 != 0 )
|
||
nBytes++;
|
||
|
||
pData = (unsigned char *)data;
|
||
switch ( reason )
|
||
{
|
||
case BINEINTEGERTRUNC: /* Integer truncation occurred */
|
||
(void)fprintf( stderr, "Bin: integer truncation during %s\n",
|
||
opname );
|
||
(void)fprintf( stderr, " %d bit integer truncated on storage into %d bit integer\n",
|
||
frombits, tobits );
|
||
(void)fprintf( stderr, " Pre-truncation integer = 0x" );
|
||
do
|
||
(void)fprintf( stderr, "%02x", (int)*(pData++) );
|
||
while ( --nBytes );
|
||
(void)fprintf( stderr, "\n" );
|
||
return ( 0 );
|
||
|
||
case BINEFLOATOVERFLOW: /* Floating point overflow occurred */
|
||
(void)fprintf( stderr, "Bin: floating point overflow during %s\n",
|
||
opname );
|
||
(void)fprintf( stderr, " %d bit exponent overflows when reduced to %d bits\n",
|
||
frombits, tobits );
|
||
(void)fprintf( stderr, " Pre-overflow float = 0x" );
|
||
do
|
||
(void)fprintf( stderr, "%02x", (int)*(pData++) );
|
||
while ( --nBytes );
|
||
(void)fprintf( stderr, "\n" );
|
||
return ( 0 );
|
||
|
||
case BINEFLOATUNDERFLOW:/* Floating point underflow occurred */
|
||
(void)fprintf( stderr, "Bin: floating point underflow during %s\n",
|
||
opname );
|
||
(void)fprintf( stderr, " %d bit exponent underflows when reduced to %d bits\n",
|
||
frombits, tobits );
|
||
(void)fprintf( stderr, " Pre-underflow float = 0x" );
|
||
do
|
||
(void)fprintf( stderr, "%02x", (int)*(pData++) );
|
||
while ( --nBytes );
|
||
(void)fprintf( stderr, "\n" );
|
||
return ( 0 );
|
||
|
||
default: /* Unknown!? */
|
||
(void)fprintf( stderr, "Bin: unknown error has occurred during %s\n",
|
||
opname );
|
||
return ( 0 );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinByteOrder - Select the byte order of the file
|
||
* BinQByteOrder - Query the byte order of the file
|
||
*
|
||
* DESCRIPTION
|
||
* The byte order of the data in the file must be known in order to
|
||
* handle conversion of data to the byte order of the host. The
|
||
* default is MBF (Most-Significant Byte First).
|
||
*
|
||
* BinByteOrder sets the byte order and returns -1 or 0.
|
||
*
|
||
* BinQByteOrder queries the byte order.
|
||
*/
|
||
|
||
int /* Returns status */
|
||
#ifdef __STDC__
|
||
BinByteOrder( int which )
|
||
#else
|
||
BinByteOrder( which )
|
||
int which; /* Which byte order to use */
|
||
#endif
|
||
{
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
switch ( which )
|
||
{
|
||
case BINMBF:
|
||
binFileBO = BINMBF;
|
||
binReadDisp = binReadMBFDisp;
|
||
binWriteDisp = binWriteMBFDisp;
|
||
return ( 0 );
|
||
|
||
case BINLBF:
|
||
binFileBO = BINLBF;
|
||
binReadDisp = binReadLBFDisp;
|
||
binWriteDisp = binWriteLBFDisp;
|
||
return ( 0 );
|
||
|
||
default:
|
||
BINERROR( BINEBYTEORDER, -1 );
|
||
}
|
||
}
|
||
|
||
int /* Returns current byte order */
|
||
#ifdef __STDC__
|
||
BinQByteOrder( void )
|
||
#else
|
||
BinQByteOrder( )
|
||
#endif
|
||
{
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
return ( binFileBO );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinFloatFormat - Select the floating point format of the file
|
||
* BinQFloatFormat - Query the floating point format of the file
|
||
*
|
||
* DESCRIPTION
|
||
* The floating format for data in the file must be known in order to
|
||
* handle conversion of data to the float format of the host. The
|
||
* default is IEEE.
|
||
*
|
||
* BinFloatFormat sets the floating point format and returns -1 or 0.
|
||
*
|
||
* BinQFloatFormat queries the floating point format.
|
||
*/
|
||
|
||
int /* Returns status */
|
||
#ifdef __STDC__
|
||
BinFloatFormat( int which )
|
||
#else
|
||
BinFloatFormat( which )
|
||
int which; /* Which floating point format to use */
|
||
#endif
|
||
{
|
||
binFloatFormatCooked *fcp;/* Cooked table pointer */
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
for ( fcp = binFloatFormatsCooked; fcp->bin_format.bin_name != NULL; fcp++ )
|
||
if ( fcp->bin_format.bin_number == which )
|
||
break;
|
||
if ( fcp->bin_format.bin_name == NULL )
|
||
BINERROR( BINEFLOATFORMAT, -1 ); /* Unknown */
|
||
binFileFloatFormat = fcp;
|
||
return ( 0 );
|
||
}
|
||
|
||
int /* Returns current float format */
|
||
#ifdef __STDC__
|
||
BinQFloatFormat( void )
|
||
#else
|
||
BinQFloatFormat( )
|
||
#endif
|
||
{
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
return ( binFileFloatFormat->bin_format.bin_number );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
#define BINCHECKRTYPE(type) \
|
||
if ( (type) <= 0 || (type) > BINMAXTYPE || binReadDisp[(type)] == NULL)\
|
||
BINERROR( BINETYPE, -1 );
|
||
|
||
|
||
#define BINCHECKWTYPE(type) \
|
||
if ( (type) <= 0 || (type) > BINMAXTYPE || binWriteDisp[(type)] ==NULL)\
|
||
BINERROR( BINETYPE, -1 );
|
||
|
||
|
||
#define BINCHECKNBYTES(nBytes) \
|
||
if ( (nBytes) <= 0 ) \
|
||
BINERROR( BINENBYTES, -1 );
|
||
|
||
|
||
#define BINCHECKCOUNT(count) \
|
||
if ( (count) == 0 ) \
|
||
return ( 0 ); \
|
||
if ( (count) < 0 ) \
|
||
BINERROR( BINECOUNT, -1 );
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinRead - Read binary file using unbuffered I/O
|
||
* BinFRead - Read binary file using buffered I/O
|
||
* BinSRead - Read binary string
|
||
* BinWrite - Write binary file using unbuffered I/O
|
||
* BinFWrite - Write binary file using buffered I/O
|
||
* BinSWrite - Write binary string
|
||
*
|
||
* DESCRIPTION
|
||
* The incomming arguments are checked for legality. If any are
|
||
* bad, a -1 is returned and the global error variable 'BinErrNo'
|
||
* set to an appropriate error code.
|
||
*
|
||
* Based on the user's 'type', an appropriate read or write function is
|
||
* called through the read or write dispatch tables. The dispatch tables
|
||
* point to LBF or MBF functions, as selected by an earlier user
|
||
* call to BinByteOrder.
|
||
*/
|
||
|
||
int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
BinRead( int fd, void *buf, int type, int nBytes, int count )
|
||
#else
|
||
BinRead( fd, buf, type, nBytes, count )
|
||
int fd; /* File descriptor */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Buffer variable's type */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
BINCHECKRTYPE( type );
|
||
BINCHECKNBYTES( nBytes );
|
||
BINCHECKCOUNT( count );
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
binOp = BINOPREAD;
|
||
dispatch = binReadDisp[type];
|
||
return ( (*dispatch)( FDIO, fd, (FILE *)NULL, (unsigned char *)NULL,
|
||
(unsigned char*) buf, type, nBytes, count ) );
|
||
}
|
||
|
||
int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
BinFRead( FILE *fp, void *buf, int type, int nBytes, int count )
|
||
#else
|
||
BinFRead( fp, buf, type, nBytes, count )
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Buffer variable's type */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
BINCHECKRTYPE( type );
|
||
BINCHECKNBYTES( nBytes );
|
||
BINCHECKCOUNT( count );
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
binOp = BINOPREAD;
|
||
dispatch = binReadDisp[type];
|
||
return ( (*dispatch)( FPIO, -1, fp,
|
||
(unsigned char *)NULL, (unsigned char*) buf, type, nBytes, count ) );
|
||
}
|
||
|
||
int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
BinSRead( unsigned char *data, void *buf, int type, int nBytes, int count )
|
||
#else
|
||
BinSRead( data, buf, type, nBytes, count )
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Buffer variable's type */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
BINCHECKRTYPE( type );
|
||
BINCHECKNBYTES( nBytes );
|
||
BINCHECKCOUNT( count );
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
binOp = BINOPREAD;
|
||
dispatch = binReadDisp[type];
|
||
return ( (*dispatch)( DATAIO, -1, (FILE *)NULL,
|
||
data, (unsigned char*) buf, type, nBytes, count ) );
|
||
}
|
||
|
||
int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
BinWrite( int fd, void *buf, int type, int nBytes, int count )
|
||
#else
|
||
BinWrite( fd, buf, type, nBytes, count )
|
||
int fd; /* File descriptor */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Buffer variable's type */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
BINCHECKWTYPE( type );
|
||
BINCHECKNBYTES( nBytes );
|
||
BINCHECKCOUNT( count );
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
binOp = BINOPWRITE;
|
||
dispatch = binWriteDisp[type];
|
||
return ( (*dispatch)( FDIO, fd, (FILE *)NULL,
|
||
(unsigned char *)NULL, (unsigned char*) buf, type, nBytes, count ) );
|
||
}
|
||
|
||
int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
BinFWrite( FILE *fp, void *buf, int type, int nBytes, int count )
|
||
#else
|
||
BinFWrite( fp, buf, type, nBytes, count )
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Buffer variable's type */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
BINCHECKWTYPE( type );
|
||
BINCHECKNBYTES( nBytes );
|
||
BINCHECKCOUNT( count );
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
binOp = BINOPWRITE;
|
||
dispatch = binWriteDisp[type];
|
||
return ( (*dispatch)( FPIO, -1, fp,
|
||
(unsigned char *)NULL, (unsigned char*) buf, type, nBytes, count ) );
|
||
}
|
||
|
||
int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
BinSWrite( unsigned char *data, void *buf, int type, int nBytes, int count )
|
||
#else
|
||
BinSWrite( data, buf, type, nBytes, count )
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Buffer variable's type */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
BINCHECKWTYPE( type );
|
||
BINCHECKNBYTES( nBytes );
|
||
BINCHECKCOUNT( count );
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
binOp = BINOPWRITE;
|
||
dispatch = binWriteDisp[type];
|
||
return ( (*dispatch)( DATAIO, -1, (FILE *)NULL,
|
||
data, (unsigned char*) buf, type, nBytes, count ) );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* BinReadStruct - Read binary file into a C struct using unbuf I/O
|
||
* BinFReadStruct - Read binary file into a C struct using buf I/O
|
||
* BinSReadStruct - Read binary string into a C struct
|
||
* BinWriteStruct - Write binary file from a C struct using unbuf I/O
|
||
* BinFWriteStruct - Write binary file from a C struct using buf I/O
|
||
* BinSWriteStruct - Write binary string from a C struct
|
||
*
|
||
* DESCRIPTION
|
||
* The incomming arguments are checked for legality. If any are
|
||
* bad, a -1 is returned and the global error variable 'BinErrNo'
|
||
* set to an appropriate error code.
|
||
*
|
||
* The structure description array is walked and the appropriate
|
||
* single type read or write function called through the read or write
|
||
* dispatch tables. The dispatch tables point to LBF or MBF functions,
|
||
* as selected by an earlier user call to BinByteOrder( ).
|
||
*
|
||
* Structure field padding is done per the host system's characteristics.
|
||
* For instance, on most 32-bit workstations, short's are aligned to
|
||
* 16-bit boundaries, and int's and long's to 32-bit boundaries.
|
||
*/
|
||
|
||
int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
BinReadStruct( int fd, void *buf, BinField *fields )
|
||
#else
|
||
BinReadStruct( fd, buf, fields )
|
||
int fd; /* File descriptor */
|
||
unsigned char *buf; /* Data buffer */
|
||
BinField *fields; /* Structure field description */
|
||
#endif
|
||
{
|
||
BinField *bfp; /* Field pointer */
|
||
int nBytes = 0; /* Number of bytes read */
|
||
int n; /* Read status & # bytes read */
|
||
unsigned long ptrAsInt; /* Pointer cast as int for math */
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
|
||
/*
|
||
* Check all values in the fields array before doing anything.
|
||
*/
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
BINCHECKRTYPE( bfp->bin_type );
|
||
BINCHECKNBYTES( bfp->bin_nbytes )
|
||
}
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
|
||
/*
|
||
* Now execute the reads.
|
||
*
|
||
* This is potentially confusing code, so here's what's happening:
|
||
*
|
||
* - If the buf pointer is not currently at the next address
|
||
* needed based upon the host's struct padding characteristics,
|
||
* then we need to move it there.
|
||
*
|
||
* - To do that check we need to do some arithmetic on the
|
||
* buf pointer as an integer. This requires that we cast it
|
||
* to an integer type (unsigned long). We assume that an
|
||
* unsigned long is big enough to hold a pointer (!!!).
|
||
*
|
||
* - As a quick check, we mask off the lower bits of the address
|
||
* based upon the binTypePadMask[] value for the type. This
|
||
* tells us fast if the buf pointer needs aligning or not.
|
||
*
|
||
* - Say we need to align. To do so we need to get rid of those
|
||
* lower bits, then add the right amount to leap to the next
|
||
* alignment point for the address. This is type dependent.
|
||
* The distance to leap is the pad amount for the type and is
|
||
* contained in binTypePad[]. The amount to mask off is again
|
||
* in binTypePadMask[]. Because we're doing arithmetic, we
|
||
* need to cast the buf pointer as an integer (unsigned long)
|
||
* to do the math.
|
||
*
|
||
* That's it.
|
||
*/
|
||
binOp = BINOPREADSTRUCT;
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= binTypePadMask[bfp->bin_type];
|
||
if ( ptrAsInt != (unsigned long)0 )
|
||
{
|
||
/* Then we need to align the pointer. */
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= ~binTypePadMask[bfp->bin_type];
|
||
buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
|
||
}
|
||
dispatch = binReadDisp[bfp->bin_type];
|
||
if ( (n = (*dispatch)( FDIO, fd, (FILE *)NULL,
|
||
(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
|
||
bfp->bin_nbytes, bfp->bin_count )) == -1 )
|
||
return ( -1 ); /* Error occured */
|
||
nBytes += n;
|
||
buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
|
||
}
|
||
return ( nBytes );
|
||
}
|
||
|
||
int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
BinFReadStruct( FILE *fp, void *buf, BinField *fields )
|
||
#else
|
||
BinFReadStruct( fp, buf, fields )
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *buf; /* Data buffer */
|
||
BinField *fields; /* Structure field description */
|
||
#endif
|
||
{
|
||
BinField *bfp; /* Field pointer */
|
||
int nBytes = 0; /* Number of bytes read */
|
||
int n; /* Read status & # bytes read */
|
||
unsigned long ptrAsInt; /* Pointer cast as int for math */
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
|
||
/*
|
||
* Check all values in the fields array before doing anything.
|
||
*/
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
BINCHECKRTYPE( bfp->bin_type );
|
||
BINCHECKNBYTES( bfp->bin_nbytes )
|
||
}
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
|
||
/*
|
||
* Now execute the reads.
|
||
*
|
||
* This is potentially confusing code, so here's what's happening:
|
||
*
|
||
* - If the buf pointer is not currently at the next address
|
||
* needed based upon the host's struct padding characteristics,
|
||
* then we need to move it there.
|
||
*
|
||
* - To do that check we need to do some arithmetic on the
|
||
* buf pointer as an integer. This requires that we cast it
|
||
* to an integer type (unsigned long). We assume that an
|
||
* unsigned long is big enough to hold a pointer (!!!).
|
||
*
|
||
* - As a quick check, we mask off the lower bits of the address
|
||
* based upon the binTypePadMask[] value for the type. This
|
||
* tells us fast if the buf pointer needs aligning or not.
|
||
*
|
||
* - Say we need to align. To do so we need to get rid of those
|
||
* lower bits, then add the right amount to leap to the next
|
||
* alignment point for the address. This is type dependent.
|
||
* The distance to leap is the pad amount for the type and is
|
||
* contained in binTypePad[]. The amount to mask off is again
|
||
* in binTypePadMask[]. Because we're doing arithmetic, we
|
||
* need to cast the buf pointer as an integer (unsigned long)
|
||
* to do the math.
|
||
*
|
||
* That's it.
|
||
*/
|
||
binOp = BINOPREADSTRUCT;
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= binTypePadMask[bfp->bin_type];
|
||
if ( ptrAsInt != (unsigned long)0 )
|
||
{
|
||
/* Then we need to align the pointer. */
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= ~binTypePadMask[bfp->bin_type];
|
||
buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
|
||
}
|
||
dispatch = binReadDisp[bfp->bin_type];
|
||
if ( (n = (*dispatch)( FPIO, -1, fp,
|
||
(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
|
||
bfp->bin_nbytes, bfp->bin_count )) == -1 )
|
||
return ( -1 ); /* Error occured */
|
||
nBytes += n;
|
||
buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
|
||
}
|
||
return ( nBytes );
|
||
}
|
||
|
||
int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
BinSReadStruct( unsigned char *data, void *buf, BinField *fields )
|
||
#else
|
||
BinSReadStruct( data, buf, fields )
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buf; /* Data buffer */
|
||
BinField *fields; /* Structure field description */
|
||
#endif
|
||
{
|
||
BinField *bfp; /* Field pointer */
|
||
int nBytes = 0; /* Number of bytes read */
|
||
int n; /* Read status & # bytes read */
|
||
unsigned long ptrAsInt; /* Pointer cast as int for math */
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
|
||
/*
|
||
* Check all values in the fields array before doing anything.
|
||
*/
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
BINCHECKRTYPE( bfp->bin_type );
|
||
BINCHECKNBYTES( bfp->bin_nbytes )
|
||
}
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
|
||
/*
|
||
* Now execute the reads.
|
||
*
|
||
* This is potentially confusing code, so here's what's happening:
|
||
*
|
||
* - If the buf pointer is not currently at the next address
|
||
* needed based upon the host's struct padding characteristics,
|
||
* then we need to move it there.
|
||
*
|
||
* - To do that check we need to do some arithmetic on the
|
||
* buf pointer as an integer. This requires that we cast it
|
||
* to an integer type (unsigned long). We assume that an
|
||
* unsigned long is big enough to hold a pointer (!!!).
|
||
*
|
||
* - As a quick check, we mask off the lower bits of the address
|
||
* based upon the binTypePadMask[] value for the type. This
|
||
* tells us fast if the buf pointer needs aligning or not.
|
||
*
|
||
* - Say we need to align. To do so we need to get rid of those
|
||
* lower bits, then add the right amount to leap to the next
|
||
* alignment point for the address. This is type dependent.
|
||
* The distance to leap is the pad amount for the type and is
|
||
* contained in binTypePad[]. The amount to mask off is again
|
||
* in binTypePadMask[]. Because we're doing arithmetic, we
|
||
* need to cast the buf pointer as an integer (unsigned long)
|
||
* to do the math.
|
||
*
|
||
* That's it.
|
||
*/
|
||
binOp = BINOPREADSTRUCT;
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= binTypePadMask[bfp->bin_type];
|
||
if ( ptrAsInt != (unsigned long)0 )
|
||
{
|
||
/* Then we need to align the pointer. */
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= ~binTypePadMask[bfp->bin_type];
|
||
buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
|
||
}
|
||
dispatch = binReadDisp[bfp->bin_type];
|
||
if ( (n = (*dispatch)( DATAIO, -1, (FILE *)NULL,
|
||
data, (unsigned char*) buf, bfp->bin_type,
|
||
bfp->bin_nbytes, bfp->bin_count )) == -1 )
|
||
return ( -1 ); /* Error occured */
|
||
nBytes += n;
|
||
data += bfp->bin_nbytes * bfp->bin_count;
|
||
buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
|
||
}
|
||
return ( nBytes );
|
||
}
|
||
|
||
int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
BinWriteStruct( int fd, void *buf, BinField *fields )
|
||
#else
|
||
BinWriteStruct( fd, buf, fields )
|
||
int fd; /* File descriptor */
|
||
unsigned char *buf; /* Data buffer */
|
||
BinField *fields; /* Structure field description */
|
||
#endif
|
||
{
|
||
BinField *bfp; /* Field pointer */
|
||
int nBytes = 0; /* Number of bytes written */
|
||
int n; /* Read status & # bytes written*/
|
||
unsigned long ptrAsInt; /* Pointer cast as int for math */
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
|
||
/*
|
||
* Check all values in the fields array before doing anything.
|
||
*/
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
BINCHECKWTYPE( bfp->bin_type );
|
||
BINCHECKNBYTES( bfp->bin_nbytes );
|
||
}
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
|
||
/*
|
||
* Now execute the writes.
|
||
*
|
||
* This is potentially confusing code, so here's what's happening:
|
||
*
|
||
* - If the buf pointer is not currently at the next address
|
||
* needed based upon the host's struct padding characteristics,
|
||
* then we need to move it there.
|
||
*
|
||
* - To do that check we need to do some arithmetic on the
|
||
* buf pointer as an integer. This requires that we cast it
|
||
* to an integer type (unsigned long). We assume that an
|
||
* unsigned long is big enough to hold a pointer (!!!).
|
||
*
|
||
* - As a quick check, we mask off the lower bits of the address
|
||
* based upon the binTypePadMask[] value for the type. This
|
||
* tells us fast if the buf pointer needs aligning or not.
|
||
*
|
||
* - Say we need to align. To do so we need to get rid of those
|
||
* lower bits, then add the right amount to leap to the next
|
||
* alignment point for the address. This is type dependent.
|
||
* The distance to leap is the pad amount for the type and is
|
||
* contained in binTypePad[]. The amount to mask off is again
|
||
* in binTypePadMask[]. Because we're doing arithmetic, we
|
||
* need to cast the buf pointer as an integer (unsigned long)
|
||
* to do the math.
|
||
*
|
||
* That's it.
|
||
*/
|
||
binOp = BINOPWRITESTRUCT;
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= binTypePadMask[bfp->bin_type];
|
||
if ( ptrAsInt != (unsigned long)0 )
|
||
{
|
||
/* Then we need to align the pointer. */
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= ~binTypePadMask[bfp->bin_type];
|
||
buf = (unsigned char *) ptrAsInt + binTypePad[bfp->bin_type];
|
||
}
|
||
dispatch = binWriteDisp[bfp->bin_type];
|
||
if ( (n = (*dispatch)( FDIO, fd, (FILE *)NULL,
|
||
(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
|
||
bfp->bin_nbytes, bfp->bin_count )) == -1 )
|
||
return ( -1 ); /* Error occured */
|
||
nBytes += n;
|
||
|
||
buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
|
||
}
|
||
return ( nBytes );
|
||
}
|
||
|
||
int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
BinFWriteStruct( FILE *fp, void *buf, BinField *fields )
|
||
#else
|
||
BinFWriteStruct( fp, buf, fields )
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *buf; /* Data buffer */
|
||
BinField *fields; /* Structure field description */
|
||
#endif
|
||
{
|
||
BinField *bfp; /* Field pointer */
|
||
int nBytes = 0; /* Number of bytes written */
|
||
int n; /* Read status & # bytes written*/
|
||
unsigned long ptrAsInt; /* Pointer cast as int for math */
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
|
||
/*
|
||
* Check all values in the fields array before doing anything.
|
||
*/
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
BINCHECKWTYPE( bfp->bin_type );
|
||
BINCHECKNBYTES( bfp->bin_nbytes );
|
||
}
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
|
||
/*
|
||
* Now execute the writes.
|
||
*
|
||
* This is potentially confusing code, so here's what's happening:
|
||
*
|
||
* - If the buf pointer is not currently at the next address
|
||
* needed based upon the host's struct padding characteristics,
|
||
* then we need to move it there.
|
||
*
|
||
* - To do that check we need to do some arithmetic on the
|
||
* buf pointer as an integer. This requires that we cast it
|
||
* to an integer type (unsigned long). We assume that an
|
||
* unsigned long is big enough to hold a pointer (!!!).
|
||
*
|
||
* - As a quick check, we mask off the lower bits of the address
|
||
* based upon the binTypePadMask[] value for the type. This
|
||
* tells us fast if the buf pointer needs aligning or not.
|
||
*
|
||
* - Say we need to align. To do so we need to get rid of those
|
||
* lower bits, then add the right amount to leap to the next
|
||
* alignment point for the address. This is type dependent.
|
||
* The distance to leap is the pad amount for the type and is
|
||
* contained in binTypePad[]. The amount to mask off is again
|
||
* in binTypePadMask[]. Because we're doing arithmetic, we
|
||
* need to cast the buf pointer as an integer (unsigned long)
|
||
* to do the math.
|
||
*
|
||
* That's it.
|
||
*/
|
||
binOp = BINOPWRITESTRUCT;
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= binTypePadMask[bfp->bin_type];
|
||
if ( ptrAsInt != (unsigned long)0 )
|
||
{
|
||
/* Then we need to align the pointer. */
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= ~binTypePadMask[bfp->bin_type];
|
||
buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
|
||
}
|
||
dispatch = binWriteDisp[bfp->bin_type];
|
||
if ( (n = (*dispatch)( FPIO, -1, fp,
|
||
(unsigned char *)NULL, (unsigned char*) buf, bfp->bin_type,
|
||
bfp->bin_nbytes, bfp->bin_count )) == -1 )
|
||
return ( -1 ); /* Error occured */
|
||
nBytes += n;
|
||
buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
|
||
}
|
||
return ( nBytes );
|
||
}
|
||
|
||
int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
BinSWriteStruct( unsigned char *data, void *buf, BinField *fields )
|
||
#else
|
||
BinSWriteStruct( data, buf, fields )
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buf; /* Data buffer */
|
||
BinField *fields; /* Structure field description */
|
||
#endif
|
||
{
|
||
BinField *bfp; /* Field pointer */
|
||
int nBytes = 0; /* Number of bytes written */
|
||
int n; /* Read status & # bytes written*/
|
||
unsigned long ptrAsInt; /* Pointer cast as int for math */
|
||
#ifdef __STDC__
|
||
int (*dispatch)( int, int, FILE *, unsigned char *, unsigned char *,
|
||
int, int, int ); /* Dispatch table entry */
|
||
#else
|
||
int (*dispatch)( ); /* Dispatch table entry */
|
||
#endif
|
||
|
||
/*
|
||
* Check all values in the fields array before doing anything.
|
||
*/
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
BINCHECKWTYPE( bfp->bin_type );
|
||
BINCHECKNBYTES( bfp->bin_nbytes );
|
||
}
|
||
|
||
if ( !binInit )
|
||
binInitialize( );
|
||
|
||
|
||
/*
|
||
* Now execute the writes.
|
||
*
|
||
* This is potentially confusing code, so here's what's happening:
|
||
*
|
||
* - If the buf pointer is not currently at the next address
|
||
* needed based upon the host's struct padding characteristics,
|
||
* then we need to move it there.
|
||
*
|
||
* - To do that check we need to do some arithmetic on the
|
||
* buf pointer as an integer. This requires that we cast it
|
||
* to an integer type (unsigned long). We assume that an
|
||
* unsigned long is big enough to hold a pointer (!!!).
|
||
*
|
||
* - As a quick check, we mask off the lower bits of the address
|
||
* based upon the binTypePadMask[] value for the type. This
|
||
* tells us fast if the buf pointer needs aligning or not.
|
||
*
|
||
* - Say we need to align. To do so we need to get rid of those
|
||
* lower bits, then add the right amount to leap to the next
|
||
* alignment point for the address. This is type dependent.
|
||
* The distance to leap is the pad amount for the type and is
|
||
* contained in binTypePad[]. The amount to mask off is again
|
||
* in binTypePadMask[]. Because we're doing arithmetic, we
|
||
* need to cast the buf pointer as an integer (unsigned long)
|
||
* to do the math.
|
||
*
|
||
* That's it.
|
||
*/
|
||
binOp = BINOPWRITESTRUCT;
|
||
for ( bfp = fields; bfp->bin_count; bfp++ )
|
||
{
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= binTypePadMask[bfp->bin_type];
|
||
if ( ptrAsInt != (unsigned long)0 )
|
||
{
|
||
/* Then we need to align the pointer. */
|
||
ptrAsInt = (unsigned long)buf;
|
||
ptrAsInt &= ~binTypePadMask[bfp->bin_type];
|
||
buf = (unsigned char *)ptrAsInt + binTypePad[bfp->bin_type];
|
||
}
|
||
dispatch = binWriteDisp[bfp->bin_type];
|
||
if ( (n = (*dispatch)( DATAIO, -1, (FILE *)NULL,
|
||
data, (unsigned char*) buf, bfp->bin_type,
|
||
bfp->bin_nbytes, bfp->bin_count )) == -1 )
|
||
return ( -1 ); /* Error occured */
|
||
nBytes += n;
|
||
data += bfp->bin_nbytes * bfp->bin_count;
|
||
buf = (unsigned char *)buf + binTypeSize[bfp->bin_type] * bfp->bin_count;
|
||
}
|
||
return ( nBytes );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* binByteRead - read bytes into a buffer
|
||
* binByteWrite - write bytes from a buffer
|
||
*
|
||
* DESCRIPTION
|
||
* binByteRead: N bytes of data are read in from a file descriptor,
|
||
* file pointer, or data buffer.
|
||
*
|
||
* binByteWrite: N bytes of data are written to a file descriptor,
|
||
* file pointer, or data buffer.
|
||
*
|
||
* When reading from or writing to file descriptors or file pointers,
|
||
* we loop on the read or write in order to block, even on non-blocking
|
||
* I/O connections, such as pipes and sockets.
|
||
*/
|
||
|
||
static int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
binByteRead( int ioType, int fd, FILE *fp, unsigned char *data, unsigned char *buffer, int n )
|
||
#else
|
||
binByteRead( ioType, fd, fp, data, buffer, n )
|
||
int ioType; /* Where to get data */
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buffer; /* Output data */
|
||
int n; /* # of bytes to read */
|
||
#endif
|
||
{
|
||
int cnt; /* Counter */
|
||
int nBytes; /* # of bytes read in at once */
|
||
unsigned char *pBuffer; /* Buffer pointer */
|
||
|
||
switch ( ioType )
|
||
{
|
||
case FDIO: /* File descriptor. */
|
||
for ( cnt = 0, pBuffer = buffer; cnt != n; )
|
||
{
|
||
switch ( (nBytes = read( fd, pBuffer, n-cnt )) )
|
||
{
|
||
case 0: /* EOF reached. */
|
||
return ( cnt );
|
||
case -1:/* Error. */
|
||
BINERROR( BINESYS, -1 );
|
||
default:
|
||
pBuffer += nBytes;
|
||
cnt += nBytes;
|
||
break;
|
||
}
|
||
}
|
||
return ( cnt );
|
||
|
||
case FPIO: /* File pointer. */
|
||
for ( cnt = 0, pBuffer = buffer; cnt != n; )
|
||
{
|
||
switch ( (nBytes = fread( (char *)pBuffer, 1, n-cnt, fp )) )
|
||
{
|
||
case 0: /* EOF or error reached. */
|
||
return ( cnt );
|
||
default:
|
||
pBuffer += nBytes;
|
||
cnt += nBytes;
|
||
break;
|
||
}
|
||
}
|
||
return ( cnt );
|
||
|
||
case DATAIO: /* Data buffer. */
|
||
memcpy( (void*)buffer, (void*)data, n);
|
||
return ( n );
|
||
}
|
||
return( 0 );
|
||
/*NOTREACHED*/
|
||
}
|
||
|
||
static int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
binByteWrite( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buffer, int n )
|
||
#else
|
||
binByteWrite( ioType, fd, fp, data, buffer, n )
|
||
int ioType; /* Where to send data */
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buffer; /* Input data */
|
||
int n; /* # of bytes to write */
|
||
#endif
|
||
{
|
||
int cnt; /* Counter */
|
||
int nBytes; /* # of bytes read in at once */
|
||
unsigned char *pBuffer; /* Buffer pointer */
|
||
|
||
switch ( ioType )
|
||
{
|
||
case FDIO: /* File descriptor. */
|
||
for ( cnt = 0, pBuffer = buffer; cnt != n; )
|
||
{
|
||
switch ( (nBytes = write( fd, (char *)pBuffer, n-cnt )) )
|
||
{
|
||
case 0: /* EOF reached. */
|
||
return ( cnt );
|
||
case -1:/* Error. */
|
||
BINERROR( BINESYS, -1 );
|
||
default:
|
||
pBuffer += nBytes;
|
||
cnt += nBytes;
|
||
break;
|
||
}
|
||
}
|
||
return ( cnt );
|
||
|
||
case FPIO: /* File pointer. */
|
||
for ( cnt = 0, pBuffer = buffer; cnt != n; )
|
||
{
|
||
switch ( (nBytes = fwrite( (char *)pBuffer, 1, n-cnt, fp )) )
|
||
{
|
||
case 0: /* EOF or error reached. */
|
||
return ( cnt );
|
||
default:
|
||
pBuffer += nBytes;
|
||
cnt += nBytes;
|
||
break;
|
||
}
|
||
}
|
||
return ( cnt );
|
||
|
||
case DATAIO: /* Data buffer. */
|
||
memcpy( (void*) data, (void*) buffer, n);
|
||
return ( n );
|
||
}
|
||
return( 0 );
|
||
/*NOTREACHED*/
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* binReadCharMBF - Read characters from an MBF input
|
||
* binReadCharLBF - Read characters from an LBF input
|
||
* binWriteCharMBF - Write characters to MBF output
|
||
* binWriteCharLBF - Write characters to LBF output
|
||
*
|
||
* DESCRIPTION
|
||
* If the host and input/output data share the same size, then a
|
||
* simple byte-for-byte read or write is done.
|
||
*
|
||
* Otherwise, for reads we read the required number of bytes from the
|
||
* input into a holding buffer, then pull out the least-significant
|
||
* byte of each 'nBytes' item and copy it into the next output buffer slot.
|
||
*
|
||
* If the incomming data has more bits of precision (and uses them) than
|
||
* the host-side character, then truncation occurs and the user's
|
||
* integer truncation callback is called. (if the input's type is signed,
|
||
* bytes that aren't 0x00 or 0xFF (sign-extension) indicate truncation.
|
||
* if the input's type is unsigned, only non-0x00 bytes indicate
|
||
* truncation).
|
||
*
|
||
* For each item to be written, the byte is extracted from the input
|
||
* buffer and added to a holding buffer. More-significant bytes in the
|
||
* holding buffer are zero padded or sign-extended.
|
||
*
|
||
* For all four routines, a 'byteHold' buffer allocated on the stack
|
||
* is prefered. However, if the buffer isn't big enough, a dynamically
|
||
* allocated holding buffer is used.
|
||
*/
|
||
|
||
static int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
binReadCharMBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binReadCharMBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Always char */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
unsigned char byteHold[BINMAXBUF]; /* Input holding buffer */
|
||
unsigned char *pHold = byteHold;/* Holding buffer pointer */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated hold buf*/
|
||
int i, j; /* Counters */
|
||
unsigned char thisOne, that; /* Byte values to check for */
|
||
|
||
|
||
if ( nBytes == 1 ) /* sizeof( char ) assumed to be 1*/
|
||
return ( binByteRead( ioType, fd, fp, data, buf, nBytes*count));
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
|
||
BINERROR( BINEMALLOC, -1 );
|
||
if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
|
||
{
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( -1 );
|
||
}
|
||
|
||
|
||
/*
|
||
* Copy selected bytes from the input temp buffer to the return
|
||
* buffer. Check the bytes skipped to see if any of them contained
|
||
* information that we're truncating. If so, call the truncation
|
||
* callback.
|
||
*/
|
||
thisOne = that = 0x00;
|
||
if ( binTypeSigned[type] )
|
||
that = 0xFF;
|
||
for ( i = count; i; --i )
|
||
{
|
||
for ( j = nBytes - 1; j; --j, ++pHold )
|
||
{
|
||
if ( *pHold != thisOne && *pHold != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(pHold-(nBytes-j-1)), nBytes*8, 8 );
|
||
pHold += j;
|
||
break;
|
||
}
|
||
}
|
||
*buf++ = *pHold++; /* Use the last byte read in */
|
||
}
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( nBytes * count );
|
||
}
|
||
|
||
static int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
binReadCharLBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binReadCharLBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Always char */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
unsigned char byteHold[BINMAXBUF]; /* Input holding buffer */
|
||
unsigned char *pHold = byteHold;/* Holding buffer pointer */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated hold buf*/
|
||
int i, j; /* Counters */
|
||
unsigned char thisOne, that; /* Byte values to check for */
|
||
|
||
|
||
if ( nBytes == 1 ) /* sizeof( char ) assumed to be 1*/
|
||
return ( binByteRead( ioType, fd, fp, data, buf, nBytes*count));
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
|
||
BINERROR( BINEMALLOC, -1 );
|
||
if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
|
||
{
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( -1 );
|
||
}
|
||
|
||
|
||
/*
|
||
* Copy selected bytes from the input temp buffer to the return
|
||
* buffer. Check the bytes skipped to see if any of them contained
|
||
* information that we're truncating. If so, call the truncation
|
||
* callback.
|
||
*/
|
||
thisOne = that = 0x00;
|
||
if ( binTypeSigned[type] )
|
||
that = 0xFF;
|
||
for ( i = count; i; --i )
|
||
{
|
||
*buf++ = *pHold++; /* Use the first byte read in */
|
||
for ( j = nBytes - 1; j; --j, ++pHold )
|
||
{
|
||
if ( *pHold != thisOne && *pHold != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(pHold-(nBytes-j)), nBytes*8, 8 );
|
||
pHold += j;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( nBytes * count );
|
||
}
|
||
|
||
static int /* Returns # of bytes write */
|
||
#ifdef __STDC__
|
||
binWriteCharMBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binWriteCharMBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Always char */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
int i, j; /* Counters */
|
||
unsigned char byteHold[BINMAXBUF]; /* Temp holding buffer */
|
||
unsigned char *pHold = byteHold;/* Pointer to holding buffer */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated hold buf*/
|
||
|
||
|
||
if ( nBytes == 1 ) /* sizeof( char ) assumed to be 1*/
|
||
return ( binByteWrite( ioType, fd, fp, data, buf, count ) );
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
|
||
BINERROR( BINEMALLOC, -1 );
|
||
|
||
|
||
/*
|
||
* Transfer the input data to the holding buffer in the right
|
||
* units. Zero pad or sign-extend as necessary.
|
||
*/
|
||
memset( (void *)pHold, 0x00, nBytes * count);
|
||
if ( binTypeSigned[type] )
|
||
for ( i = 0; i < count; i++, *pHold++ = *buf++ )
|
||
if ( (*buf & 0x70) != 0 ) /* sign bit set */
|
||
for ( j = 1; j < nBytes; j++ )
|
||
*pHold++ = 0xFF;/* Sign extend */
|
||
else
|
||
pHold += nBytes - 1;
|
||
else
|
||
for ( i = 0; i < count; i++, *pHold++ = *buf++ )
|
||
pHold += nBytes - 1;
|
||
|
||
|
||
/*
|
||
* Write the hold buffer to the output.
|
||
*/
|
||
if ( pAlloc )
|
||
{
|
||
i = binByteWrite( ioType, fd, fp, data, pAlloc, nBytes * count );
|
||
free( (char *)pAlloc );
|
||
}
|
||
else
|
||
i = binByteWrite( ioType, fd, fp, data, byteHold, nBytes * count );
|
||
return ( i );
|
||
}
|
||
|
||
static int /* Returns # of bytes write */
|
||
#ifdef __STDC__
|
||
binWriteCharLBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binWriteCharLBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Always char */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
int i, j; /* Counters */
|
||
unsigned char byteHold[BINMAXBUF]; /* Temp holding buffer */
|
||
unsigned char *pHold = byteHold;/* Pointer to holding buffer */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated hold buf*/
|
||
|
||
|
||
if ( nBytes == 1 ) /* sizeof( char ) assumed to be 1*/
|
||
return ( binByteWrite( ioType, fd, fp, data, buf, count ) );
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
( (pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL) )
|
||
BINERROR( BINEMALLOC, -1 );
|
||
|
||
|
||
/*
|
||
* Transfer the input data to the holding buffer in the right
|
||
* units. Sign-extend as necessary.
|
||
*/
|
||
memset( (void *)pHold, 0x00, nBytes * count);
|
||
if ( binTypeSigned[type] )
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
*pHold++ = *buf;
|
||
if ( (*buf++ & 0x70) != 0 ) /* sign bit set */
|
||
for ( j = 1; j < nBytes; j++ )
|
||
*pHold++ = 0xFF;/* Sign extend */
|
||
else
|
||
pHold += nBytes - 1;
|
||
}
|
||
else
|
||
for ( i = 0; i < count; i++, pHold += nBytes )
|
||
*pHold = *buf++;
|
||
|
||
|
||
/*
|
||
* Write the hold buffer to the output.
|
||
*/
|
||
if ( pAlloc )
|
||
{
|
||
i = binByteWrite( ioType, fd, fp, data, pAlloc, nBytes * count );
|
||
free( (char *)pAlloc );
|
||
}
|
||
else
|
||
i = binByteWrite( ioType, fd, fp, data, byteHold, nBytes * count );
|
||
return ( i );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* binReadIntMBF - Read MBF input into integers
|
||
* binReadIntLBF - Read LBF input into integers
|
||
* binWriteIntMBF - Write from integers to MBF output
|
||
* binWriteIntLBF - Write from integers to LBF output
|
||
*
|
||
* DESCRIPTION
|
||
* These functions read or write integers from or to MBF or LBF files.
|
||
* The basic shell of all four routines is identical.
|
||
*
|
||
* If the host's size of the item to be read or written is the same
|
||
* as the size in the file, and the byte order is the same, then
|
||
* all four routines default to using the read() or write() system
|
||
* call directly on the incomming buffer of data.
|
||
*
|
||
* Otherwise the packing of data differs between the host and the file
|
||
* and data must be copied to/from the byte array sent to the read()
|
||
* and write() system calls.
|
||
*
|
||
* The incomming buffer of data must be truncated or sign-extended as
|
||
* it is copied into the outgoing byte array. Code differs slightly
|
||
* between LBF and MBF hosts.
|
||
*
|
||
* All four of these functions depend upon the binTypeSize,
|
||
* binTypeRes, and binTypeSigned arrays for information on the type
|
||
* to be read or written:
|
||
*
|
||
* binTypeSize size of item, as stored by the host
|
||
* binTypeRes resolution of item (# of significant bytes)
|
||
* binTypeSigned signed type?
|
||
*
|
||
* On most machines, binTypeSize and binTypeRes are identical.
|
||
* The CRAY 'short' is an example of when they are not. A CRAY
|
||
* 'short' is stored in 8 bytes, but only the lower 3 bytes can
|
||
* be used. In this case, binTypeSize[SHORT] = 8, but
|
||
* binTypeRes[SHORT] = 3.
|
||
*
|
||
* We could use a great many more #ifdef's to remove lines like:
|
||
* buf += size - res;
|
||
* which is a waste of time when size and res are the same for a
|
||
* machine. However, adding #ifdef's makes getting the code
|
||
* working on a new machine more difficult, and creates a maintenance
|
||
* headache. The computation cost of such extra statements is
|
||
* low compared to the cost of the other byte-swapping loops so
|
||
* the execution time savings doesn't seem worth the increase in
|
||
* maintenance effort.
|
||
*/
|
||
|
||
static int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
binReadIntMBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binReadIntMBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Type to read */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
int i, j; /* Counters */
|
||
unsigned char byteHold[BINMAXBUF]; /* Byte buffer */
|
||
unsigned char *pHold = byteHold;/* Byte holder */
|
||
int res; /* Resolution of type */
|
||
int size; /* Size of type */
|
||
int issigned; /* Is type signed? */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated buffer */
|
||
unsigned char thisOne, that; /* Byte comparison holders */
|
||
|
||
|
||
size = binTypeSize[type]; /* Storage size of item */
|
||
res = binTypeRes[type]; /* Significant bytes of item */
|
||
issigned = binTypeSigned[type]; /* Whether signed or not */
|
||
|
||
|
||
if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
|
||
return ( binByteRead( ioType, fd, fp, data, buf, nBytes * count ));
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL))
|
||
BINERROR( BINEMALLOC, -1 );
|
||
if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
|
||
{
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( -1 );
|
||
}
|
||
|
||
|
||
/*
|
||
* Copy data from the holding buffer into the return buffer.
|
||
*/
|
||
if ( nBytes < res )
|
||
{
|
||
/*
|
||
* Holding buffer items require fewer bytes than the
|
||
* destination. We've got to sign-extend signed incomming
|
||
* data as we copy it to the destination.
|
||
*/
|
||
memset( (void *)buf, 0x00, size * count);
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
#ifdef MBF /* MBF host */
|
||
buf += size - res;
|
||
if ( issigned && (*pHold & 0x80) )
|
||
for ( j = res - nBytes; j; j-- )
|
||
*buf++ = 0xFF; /* Sign extend */
|
||
else
|
||
buf += res - nBytes;
|
||
for ( j = 0; j < nBytes; j++ )
|
||
*buf++ = *pHold++;
|
||
|
||
#else /* LBF host */
|
||
for ( j = nBytes - 1; j >= 0; j-- )
|
||
buf[j] = *pHold++;
|
||
if ( issigned && (*pHold & 0x80) )
|
||
{
|
||
buf += nBytes;
|
||
for ( j = res - nBytes; j; j-- )
|
||
*buf++ = 0xFF; /* Sign extend */
|
||
buf += size - res;
|
||
}
|
||
else
|
||
buf += size;
|
||
#endif
|
||
}
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( nBytes * count );
|
||
}
|
||
|
||
|
||
/*
|
||
* Holding buffer items require the same number, or more bytes
|
||
* than the destination. We've got to truncate incomming data
|
||
* as we copy it to the destination.
|
||
*/
|
||
thisOne = that = 0x00;
|
||
if ( binTypeSigned[type] )
|
||
that = 0xFF;
|
||
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
for ( j = 0; j < nBytes - res; j++, pHold++ )
|
||
{
|
||
if ( *pHold != thisOne && *pHold != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(pHold-j), nBytes*8, res*8 );
|
||
pHold += nBytes-res-j;
|
||
break;
|
||
}
|
||
}
|
||
#ifdef MBF /* MBF host */
|
||
buf += size - res;
|
||
for ( j = res; j; j-- )
|
||
*buf++ = *pHold++;
|
||
#else /* LBF host */
|
||
for ( j = res - 1; j >= 0; j-- )
|
||
buf[j] = *pHold++;
|
||
buf += size;
|
||
#endif
|
||
}
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( nBytes * count );
|
||
}
|
||
|
||
static int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
binReadIntLBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binReadIntLBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Type to read */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
int i, j; /* Counters */
|
||
unsigned char byteHold[BINMAXBUF]; /* Byte buffer */
|
||
unsigned char *pHold = byteHold;/* Byte holder */
|
||
int res; /* Resolution of type */
|
||
int size; /* Size of type */
|
||
int issigned; /* Is type signed? */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated buffer */
|
||
unsigned char thisOne, that; /* Byte comparison holders */
|
||
|
||
|
||
size = binTypeSize[type]; /* Storage size of item */
|
||
res = binTypeRes[type]; /* Significant bytes of item */
|
||
issigned = binTypeSigned[type]; /* Whether signed or not */
|
||
|
||
|
||
if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
|
||
return ( binByteRead( ioType, fd, fp, data, buf, nBytes * count ));
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)(nBytes*count) )) == NULL))
|
||
BINERROR( BINEMALLOC, -1 );
|
||
if ( binByteRead( ioType, fd, fp, data, pHold, nBytes * count ) == -1 )
|
||
{
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( -1 );
|
||
}
|
||
|
||
|
||
/*
|
||
* Copy data from the holding buffer into the return buffer.
|
||
*/
|
||
if ( nBytes < res )
|
||
{
|
||
/*
|
||
* Holding buffer items require fewer bytes than the
|
||
* destination. We've got to sign-extend signed incomming
|
||
* data as we copy it to the destination.
|
||
*/
|
||
memset( (void *)buf, 0x00, size * count);
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
#ifdef MBF /* MBF host */
|
||
buf += size - res;
|
||
if ( issigned && (*pHold & 0x80) )
|
||
for ( j = res - nBytes; j; j-- )
|
||
*buf++ = 0xFF; /* Sign extend */
|
||
else
|
||
buf += res - nBytes;
|
||
for ( j = nBytes - 1; j >= 0; j-- )
|
||
buf[j] = *pHold++;
|
||
buf += nBytes;
|
||
#else /* LBF host */
|
||
for ( j = nBytes; j; j-- )
|
||
*buf++ = *pHold++;
|
||
if ( issigned && (*(pHold-1) & 0x80) )
|
||
for ( j = res - nBytes; j; j-- )
|
||
*buf++ = 0xFF; /* Sign extend */
|
||
else
|
||
buf += res - nBytes;
|
||
buf += size - res;
|
||
#endif
|
||
}
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( nBytes * count );
|
||
}
|
||
|
||
/*
|
||
* Holding buffer items require the same number, or more bytes
|
||
* than the destination. We've got to truncate incomming data
|
||
* as we copy it to the destination.
|
||
*/
|
||
thisOne = that = 0x00;
|
||
if ( binTypeSigned[type] )
|
||
that = 0xFF;
|
||
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
#ifdef MBF /* MBF host */
|
||
buf += size - res;
|
||
for ( j = res - 1; j >= 0; j-- )
|
||
buf[j] = *pHold++;
|
||
buf += res;
|
||
#else /* LBF host */
|
||
for ( j = res; j; j-- )
|
||
*buf++ = *pHold++;
|
||
buf += size - res;
|
||
#endif
|
||
for ( j = 0; j < nBytes - res; j++, pHold++ )
|
||
{
|
||
if ( *pHold != thisOne && *pHold != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(pHold-j-res), nBytes*8, res*8 );
|
||
pHold += nBytes-res-j;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( nBytes * count );
|
||
}
|
||
|
||
static int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
binWriteIntMBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binWriteIntMBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Type to write */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
int i, j; /* Counters */
|
||
unsigned char byteHold[BINMAXBUF]; /* Byte buffer */
|
||
unsigned char *pHold = byteHold;/* Data buffer pointer */
|
||
int res; /* Resolution of type */
|
||
int size; /* Size of type */
|
||
int issigned; /* Is type signed? */
|
||
int n; /* # of bytes written */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated buffer */
|
||
unsigned char thisOne, that; /* Byte comparison holders */
|
||
|
||
size = binTypeSize[type]; /* Storage size of item */
|
||
res = binTypeRes[type]; /* Significant bytes of item */
|
||
issigned = binTypeSigned[type]; /* Whether signed or not */
|
||
n = nBytes * count;
|
||
|
||
|
||
if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
|
||
return ( binByteWrite( ioType, fd, fp, data, buf, n ));
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
|
||
BINERROR( BINEMALLOC, -1 );
|
||
|
||
if ( nBytes <= res )
|
||
{
|
||
/*
|
||
* Writing same or fewer bytes than stored by host.
|
||
* Truncate high-order bytes.
|
||
*/
|
||
thisOne = that = 0x00;
|
||
if ( binTypeSigned[type] )
|
||
that = 0xFF;
|
||
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
#ifdef MBF /* MBF host */
|
||
for ( j = 0; j < size - nBytes; j++, buf++ )
|
||
{
|
||
if ( *buf != thisOne && *buf != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(buf-j), res*8, nBytes*8 );
|
||
buf += size - nBytes - j;
|
||
break;
|
||
}
|
||
}
|
||
for ( j = nBytes; j; j-- )
|
||
*pHold++ = *buf++;
|
||
#else /* LBF host */
|
||
for ( j = nBytes - 1; j >= 0; j-- )
|
||
pHold[j] = *buf++;
|
||
pHold += nBytes;
|
||
|
||
for ( j = 0; j < size - nBytes; j++, buf++ )
|
||
{
|
||
if ( *buf != thisOne && *buf != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(buf-j-nBytes), res*8, nBytes*8 );
|
||
buf += size - nBytes - j;
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
if ( pAlloc )
|
||
{
|
||
i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
|
||
free( (char *)pAlloc );
|
||
}
|
||
else
|
||
i = binByteWrite( ioType, fd, fp, data, byteHold, n );
|
||
return ( i );
|
||
}
|
||
|
||
/*
|
||
* Writing more bytes than stored by host. Need to sign extend
|
||
* or pad with 0's.
|
||
*/
|
||
memset( (void *)pHold, 0x00, n);
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
#ifdef MBF /* MBF host */
|
||
if ( issigned && (*buf & 0x80) )
|
||
for ( j = nBytes - res; j; j-- )
|
||
*pHold++ = 0xFF; /* Sign extend */
|
||
else
|
||
pHold += nBytes - res;
|
||
buf += size - res;
|
||
for ( j = res; j; j-- )
|
||
*pHold++ = *buf++;
|
||
#else /* LBF host */
|
||
if ( issigned && (buf[res-1] & 0x80) )
|
||
for ( j = nBytes - res; j; j-- )
|
||
*pHold++ = 0xFF; /* Sign extend */
|
||
else
|
||
pHold += nBytes - res;
|
||
for ( j = res - 1; j >= 0; j-- )
|
||
pHold[j] = *buf++;
|
||
buf += size - res;
|
||
pHold += res;
|
||
#endif
|
||
}
|
||
|
||
if ( pAlloc )
|
||
{
|
||
i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
|
||
free( (char *)pAlloc );
|
||
}
|
||
else
|
||
i = binByteWrite( ioType, fd, fp, data, byteHold, n );
|
||
return ( i );
|
||
}
|
||
|
||
static int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
binWriteIntLBF( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binWriteIntLBF( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Type to write */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
int i, j; /* Counters */
|
||
unsigned char byteHold[BINMAXBUF]; /* Byte buffer */
|
||
unsigned char *pHold = byteHold;/* Data buffer pointer */
|
||
int res; /* Resolution of type */
|
||
int size; /* Size of type */
|
||
int issigned; /* Is type signed? */
|
||
int n; /* # of bytes written */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated buffer */
|
||
unsigned char thisOne, that; /* Byte comparison holders */
|
||
|
||
|
||
size = binTypeSize[type]; /* Storage size of item */
|
||
res = binTypeRes[type]; /* Significant bytes of item */
|
||
issigned = binTypeSigned[type]; /* Whether signed or not */
|
||
n = nBytes * count;
|
||
|
||
|
||
if ( size == nBytes && res == size && binFileBO == BINHOSTBO )
|
||
return ( binByteWrite( ioType, fd, fp, data, buf, n ));
|
||
|
||
if ( (nBytes * count > BINMAXBUF) &&
|
||
((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
|
||
BINERROR( BINEMALLOC, -1 );
|
||
|
||
|
||
if ( nBytes <= res )
|
||
{
|
||
/*
|
||
* Writing same or fewer bytes than stored by host.
|
||
* Truncate high-order bytes.
|
||
*/
|
||
thisOne = that = 0x00;
|
||
if ( binTypeSigned[type] )
|
||
that = 0xFF;
|
||
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
#ifdef MBF /* MBF host */
|
||
for ( j = 0; j < size - nBytes; j++, buf++ )
|
||
{
|
||
if ( *buf != thisOne && *buf != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(buf-j), res*8, nBytes*8 );
|
||
buf += size - nBytes - j;
|
||
break;
|
||
}
|
||
}
|
||
for ( j = nBytes - 1; j >= 0; j-- )
|
||
pHold[j] = *buf++;
|
||
pHold += nBytes;
|
||
#else /* LBF host */
|
||
for ( j = nBytes; j; j-- )
|
||
*pHold++ = *buf++;
|
||
for ( j = 0; j < size - nBytes; j++, buf++ )
|
||
{
|
||
if ( *buf != thisOne && *buf != that )
|
||
{
|
||
(*binErrFunc)( fd, binOp, BINEINTEGERTRUNC,
|
||
(buf-j-nBytes), res*8, nBytes*8 );
|
||
buf += size - nBytes - j;
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
if ( pAlloc )
|
||
{
|
||
i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
|
||
free( (char *)pAlloc );
|
||
}
|
||
else
|
||
i = binByteWrite( ioType, fd, fp, data, byteHold, n );
|
||
return ( i );
|
||
}
|
||
|
||
/*
|
||
* Writing more bytes than stored by host. Need to sign extend
|
||
* or pad with 0's.
|
||
*/
|
||
memset( (void *)pHold, 0x00, n);
|
||
for ( i = 0; i < count; i++ )
|
||
{
|
||
#ifdef MBF /* MBF host */
|
||
buf += size - res;
|
||
for ( j = res - 1; j >= 0; j-- )
|
||
pHold[j] = *buf++;
|
||
pHold += res;
|
||
if ( issigned && (*buf & 0x80) )
|
||
for ( j = nBytes - res; j; j-- )
|
||
*pHold++ = 0xFF; /* Sign extend */
|
||
else
|
||
pHold += nBytes - res;
|
||
#else /* LBF host */
|
||
for ( j = res; j; j-- )
|
||
*pHold++ = *buf++;
|
||
if ( issigned && (*(buf-1) & 0x80) )
|
||
for ( j = nBytes - res; j; j-- )
|
||
*pHold++ = 0xFF; /* Sign extend */
|
||
else
|
||
pHold += nBytes - res;
|
||
buf += size - res;
|
||
#endif
|
||
}
|
||
|
||
if ( pAlloc )
|
||
{
|
||
i = binByteWrite( ioType, fd, fp, data, pAlloc, n );
|
||
free( (char *)pAlloc );
|
||
}
|
||
else
|
||
i = binByteWrite( ioType, fd, fp, data, byteHold, n );
|
||
return ( i );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* binReadFloat - Read float from a input
|
||
* binWriteFloat - Write from float to output
|
||
*
|
||
* DESCRIPTION
|
||
* If the host and file floating point formats, sizes of those formats,
|
||
* and byte orders are the same, then a simple read or writesystem call
|
||
* is used.
|
||
*
|
||
* Otherwise, for reads, file data is read in to a holding array and
|
||
* passed off to binConvertFloat(), one at a time.
|
||
*
|
||
* For writes, host data is passed to binConvertFloat() to conver into
|
||
* a holding array, and then written to the file.
|
||
*
|
||
* NOTE: This code could be sped up by including binConvertFloat()
|
||
* code in-line and having different code for different file byte orders.
|
||
* However, in the interests of reducing the maintenance hassle for the
|
||
* rather complex code in binConvertFloat(), this has not been done.
|
||
*/
|
||
|
||
static int /* Returns # of bytes read */
|
||
#ifdef __STDC__
|
||
binReadFloat( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binReadFloat( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Input data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Type to read */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to read */
|
||
#endif
|
||
{
|
||
int i; /* Counter */
|
||
binFloatFormatCooked *host; /* Host's float format info */
|
||
binFloatFormatCooked *file; /* File's float format info */
|
||
unsigned char byteHold[BINMAXBUF]; /* Byte buffer */
|
||
unsigned char *pHold = byteHold;/* Data buffer pointer */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated buffer */
|
||
int size; /* Size of host type */
|
||
int n; /* # of bytes read */
|
||
|
||
|
||
size = binTypeSize[type];
|
||
host = binHostFloatFormat;
|
||
do
|
||
{
|
||
if ( host->bin_nbytes == size && host->bin_format.bin_subname )
|
||
break;
|
||
} while ( (++host)->bin_format.bin_number == BINHOSTFLOAT );
|
||
if ( host->bin_format.bin_number != BINHOSTFLOAT )
|
||
BINERROR( BINEFLOATUNSUPPORTED, -1 );
|
||
file = binFileFloatFormat;
|
||
i = file->bin_format.bin_number;
|
||
do
|
||
{
|
||
if ( file->bin_nbytes == nBytes && file->bin_format.bin_subname)
|
||
break;
|
||
} while ( (++file)->bin_format.bin_number == i );
|
||
if ( file->bin_format.bin_number != i )
|
||
BINERROR( BINEFLOATUNSUPPORTED, -1 );
|
||
n = nBytes * count;
|
||
|
||
|
||
if ( host == file && size == nBytes && binFileBO == BINHOSTBO )
|
||
return ( binByteRead( ioType, fd, fp, data, buf, n ) );
|
||
|
||
if ( (n > BINMAXBUF) &&
|
||
((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
|
||
BINERROR( BINEMALLOC, -1 );
|
||
if ( binByteRead( ioType, fd, fp, data, pHold, n ) == -1 )
|
||
{
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( -1 );
|
||
}
|
||
|
||
/* Convert from file format to host format. */
|
||
if ( binConvertFloat( fd, file, binFileBO, nBytes, pHold,
|
||
host, BINHOSTBO, size, buf, count ) == -1 )
|
||
{
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( -1 );
|
||
}
|
||
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
|
||
return ( n );
|
||
}
|
||
|
||
static int /* Returns # of bytes written */
|
||
#ifdef __STDC__
|
||
binWriteFloat( int ioType, int fd, FILE *fp, unsigned char *data,
|
||
unsigned char *buf, int type, int nBytes, int count )
|
||
#else
|
||
binWriteFloat( ioType, fd, fp, data, buf, type, nBytes, count )
|
||
int ioType; /* Use buffered or unbuffered I/O*/
|
||
int fd; /* File descriptor */
|
||
FILE *fp; /* File pointer */
|
||
unsigned char *data; /* Output data */
|
||
unsigned char *buf; /* Data buffer */
|
||
int type; /* Type to write */
|
||
int nBytes; /* # of bytes when in file */
|
||
int count; /* # of items to write */
|
||
#endif
|
||
{
|
||
unsigned char byteHold[BINMAXBUF]; /* Byte buffer */
|
||
unsigned char *pHold = byteHold;/* Data buffer pointer */
|
||
unsigned char *pAlloc = NULL; /* Dynamically allocated buffer */
|
||
binFloatFormatCooked *host; /* Host's float format info */
|
||
binFloatFormatCooked *file; /* File's float format info */
|
||
int size; /* Size of type */
|
||
int n; /* # of bytes read */
|
||
int i; /* Tmp */
|
||
|
||
|
||
size = binTypeSize[type];
|
||
host = binHostFloatFormat;
|
||
do
|
||
{
|
||
if ( host->bin_nbytes == size && host->bin_format.bin_subname )
|
||
break;
|
||
} while ( (++host)->bin_format.bin_number == BINHOSTFLOAT );
|
||
if ( host->bin_format.bin_number != BINHOSTFLOAT )
|
||
BINERROR( BINEFLOATUNSUPPORTED, -1 );
|
||
file = binFileFloatFormat;
|
||
i = file->bin_format.bin_number;
|
||
do
|
||
{
|
||
if ( file->bin_nbytes == nBytes && file->bin_format.bin_subname)
|
||
break;
|
||
} while ( (++file)->bin_format.bin_number == i );
|
||
if ( file->bin_format.bin_number != i )
|
||
BINERROR( BINEFLOATUNSUPPORTED, -1 );
|
||
n = nBytes * count;
|
||
|
||
|
||
if ( host == file && size == nBytes && binFileBO == BINHOSTBO )
|
||
return ( binByteWrite( ioType, fd, fp, data, buf, n ) );
|
||
|
||
if ( (n > BINMAXBUF) &&
|
||
((pAlloc = pHold = (unsigned char *)malloc( (unsigned int)n )) == NULL))
|
||
BINERROR( BINEMALLOC, -1 );
|
||
|
||
|
||
/* Convert from host format to file format. */
|
||
if ( binConvertFloat( fd, host, BINHOSTBO, size, buf,
|
||
file, binFileBO, nBytes, pHold, count ) == -1 )
|
||
{
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( -1 );
|
||
}
|
||
|
||
/* Write out the converted data. */
|
||
n = binByteWrite( ioType, fd, fp, data, pHold, n );
|
||
if ( pAlloc )
|
||
free( (char *)pAlloc );
|
||
return ( n );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* FUNCTION
|
||
* binConvertFloat - convert a float from one format to another
|
||
*
|
||
* DESCRIPTION
|
||
* This routine does the actual conversion of data in one floating
|
||
* point format into another. It handles differences in sizes of
|
||
* the exponent and mantissa fields, underflow and overflow conditions,
|
||
* exponent biasing, and whether or not the redundant most-significant
|
||
* bit in the mantissa is saved in the format.
|
||
*
|
||
* The procedure is thus...
|
||
*
|
||
* 1. Extract out the sign-bit from the source. It is assumed here
|
||
* that the sign-bit is the most-significant bit in the most-
|
||
* significant byte of the source data.
|
||
*
|
||
* 2. Extract out the exponent bits from the source. The exponent
|
||
* is built up into an UNSIGNED 32-BIT INT by shifting and masking.
|
||
* It is assumed that the exponent will fit into a 32-bit integer,
|
||
* and that the host actually supports such a thing. The exponent
|
||
* is then converted to a SIGNED 32-BIT INT and unbiased. It is
|
||
* assumed that the unbiased exponent will fit into a 32-bit int.
|
||
*
|
||
* 3. Conditions for extraction of the mantissa from the source are
|
||
* figured out. Primarily this involves checking if the source
|
||
* and destination formats both treat the redundant most-significant
|
||
* mantissa bit (the "implied bit") the same way. If they don't,
|
||
* then changes in the way the mantissa is copied in to the destination
|
||
* must be figured out. Along the way the signed exponent may be
|
||
* altered by adding or subtracting one due to the implied bit's
|
||
* existance or non-existance.
|
||
*
|
||
* 4. The exponent is checked for underflow and overflow. On underflow
|
||
* the destination float is set to 0 and we return. On overflow,
|
||
* the sign and exponent fields are set to the values appropriate
|
||
* for the destination format and the mantissa is not copied, thus
|
||
* leaving it zero. If all is OK, the exponent is biased by the
|
||
* desination bias.
|
||
*
|
||
* 5. The mantissa is then copied. This is non-trivial because the
|
||
* source and desination formats may have different numbers of
|
||
* bits in the mantissa, and may start the mantissa at different
|
||
* bit positions in the most-significant mantissa byte. So, what
|
||
* we have here is a non-aligned bit-copy operation.
|
||
*
|
||
* To make this easier (and faster?), the source data is copied,
|
||
* one byte at a time, in to a temporary ALIGNED byte array.
|
||
* During the copy process the implied bit is set or not-set if
|
||
* needed.
|
||
*
|
||
* The temp byte array data is then copied in to the destination
|
||
* byte array, with further shifting and masking taking place to
|
||
* align it appropriately for the destination format.
|
||
*
|
||
* 6. The exponent is then copied in to the destination and the sign
|
||
* bit set if the source was negative.
|
||
*
|
||
* NOTE: This code is NOT FAST! Sorry. The object was to write a
|
||
* generic floating point format converter that didn't have to change
|
||
* for different formats and different source and destination byte
|
||
* orders. This code could be sped up most easily by duplicating
|
||
* this routine four times, one for each combination of source and
|
||
* destination byte orders, then removing the unnecessary byte order
|
||
* if's. This has not been done initially because of the increase in
|
||
* the maintenance hassle of the code.
|
||
*
|
||
* Other speed-ups that could be done include:
|
||
* 1. Watching for the case where the source and desination
|
||
* formats are the same, but the byte order differs and
|
||
* then just do a byte swaped copy.
|
||
*
|
||
* 2. If the mantissa will fit into an int (whatever the size
|
||
* is on the host), copy it in to an int via shift's and
|
||
* masks, then copy it back out into the desination. This
|
||
* would save all the byte copy hassle for single-precision
|
||
* floats.
|
||
*/
|
||
|
||
#define MAXTMP 400 /* Max # of bytes in temps */
|
||
#define MAXMANT 100 /* Max # of bytes in temp mantissa*/
|
||
|
||
static int /* Returns status */
|
||
#ifdef __STDC__
|
||
binConvertFloat( int fd, binFloatFormatCooked *srcfmt, int srcbo, int nsrcbytes,
|
||
unsigned char *srcbytes, binFloatFormatCooked *dstfmt, int dstbo,
|
||
int ndstbytes, unsigned char *dstbytes, int count )
|
||
#else
|
||
binConvertFloat( fd, srcfmt, srcbo, nsrcbytes, srcbytes,
|
||
dstfmt, dstbo, ndstbytes, dstbytes, count )
|
||
int fd; /* File descriptor (for error handler)*/
|
||
binFloatFormatCooked *srcfmt; /* Source's float format info */
|
||
int srcbo; /* Source's byte order */
|
||
int nsrcbytes; /* # of bytes when in src */
|
||
unsigned char *srcbytes; /* Source data */
|
||
binFloatFormatCooked *dstfmt; /* Desintation's float format info*/
|
||
int dstbo; /* Destination's byte order */
|
||
int ndstbytes; /* # of bytes when in dst */
|
||
unsigned char *dstbytes; /* Destination data */
|
||
int count; /* Number of conversions to do */
|
||
#endif
|
||
{
|
||
int i, j, k; /* Counters and temps */
|
||
int n; /* Count of things */
|
||
|
||
int negative; /* Negative float? */
|
||
unsigned int exponent; /* Exponent */
|
||
int signed_exponent;/* Unbiased signed exponent */
|
||
unsigned char implied_bit; /* Implied bit of mantissa */
|
||
|
||
unsigned char *src; /* Source bytes pointer */
|
||
unsigned char *dst; /* Destination bytes pointer */
|
||
unsigned char *tmp; /* Temporary uchar pointer */
|
||
unsigned char tmpmant[MAXMANT];/* Temporary mantissa array */
|
||
unsigned char tmpsrc[MAXTMP];/* Temporary src float bytes array*/
|
||
unsigned char tmpdst[MAXTMP];/* Temporary src float bytes array*/
|
||
unsigned char *allocsrc; /* Allocated tmpsrc pointer */
|
||
unsigned char *allocdst; /* Allocated tmpdst pointer */
|
||
|
||
int start_byte; /* Starting byte of mantissa */
|
||
unsigned char mask1; /* First mantissa byte mask */
|
||
unsigned char mask2; /* Second mantissa byte mask */
|
||
unsigned char byte1_mask; /* Special mask for 1st src byte*/
|
||
int shift; /* Amount to shift mantissa bytes*/
|
||
int shift8; /* 8 - shift */
|
||
|
||
|
||
src = srcbytes;
|
||
dst = dstbytes;
|
||
allocsrc = NULL;
|
||
allocdst = NULL;
|
||
|
||
|
||
/*
|
||
* Check the source format's flags to see if there is any special
|
||
* pre-processing of the source bytes that needs to be done.
|
||
*/
|
||
if ( srcfmt->bin_format.bin_flags & BINVAXBO )
|
||
{
|
||
/*
|
||
* Source float uses the VAX's LBF/MBF mix byte ordering.
|
||
* Floating point values are ordered as a list of 16-bit
|
||
* quantities, from most-significant to least-significant.
|
||
* Within a 16-bit quantity, the first byte is the least-
|
||
* significant and the second the most-significant.
|
||
*
|
||
* For example, a single precision float ('f' format)
|
||
* is a 4-byte quantity:
|
||
*
|
||
* 7 0
|
||
* byte 0 EMMMMMMM high mantissa bits
|
||
* byte 1 SEEEEEEE
|
||
* byte 2 MMMMMMMM low mantissa bits
|
||
* byte 3 MMMMMMMM middle mantissa bits
|
||
*
|
||
* To handle VAX byte ordering of floats, we copy the source
|
||
* bytes in to a temporary byte array, swapping every two
|
||
* bytes, then set the source byte order to the opposite of
|
||
* that selected. The generic conversion algorithm below
|
||
* can handle it from there.
|
||
*/
|
||
src = tmpsrc;
|
||
n = nsrcbytes * count;
|
||
if ( ( n > MAXTMP ) &&
|
||
((src = allocsrc = (unsigned char *)malloc( (unsigned int)n )) == NULL ) )
|
||
BINERROR( BINEMALLOC, -1 );
|
||
|
||
n /= 2;
|
||
tmp = srcbytes;
|
||
do
|
||
{
|
||
*src++ = tmp[1];
|
||
*src++ = tmp[0];
|
||
tmp += 2;
|
||
} while ( --n );
|
||
src = tmpsrc;
|
||
if ( allocsrc )
|
||
src = allocsrc;
|
||
srcbo = (srcbo == BINLBF) ? BINMBF : BINLBF;
|
||
}
|
||
|
||
|
||
/*
|
||
* Check the destination format's flags to see if there is any special
|
||
* post-processing of the destination bytes that needs to be setup.
|
||
*/
|
||
if ( dstfmt->bin_format.bin_flags & BINVAXBO )
|
||
{
|
||
/*
|
||
* Destination float uses the VAX's LBF/MBF mix byte ordering.
|
||
* See the comment above for details.
|
||
*
|
||
* To handle VAX byte ordering of floats, we set the
|
||
* destination pointer to point to a temp array and set the
|
||
* destination byte order to the opposite of that selected.
|
||
* When we've completed the conversion, we'll copy from
|
||
* the temp array in to the real destination, doing byte
|
||
* swapping along the way.
|
||
*/
|
||
dst = tmpdst;
|
||
n = ndstbytes * count;
|
||
if ( ( n > MAXTMP ) &&
|
||
( (dst = allocdst = (unsigned char *)malloc( (unsigned int)n )) == NULL ) )
|
||
BINERROR( BINEMALLOC, -1 );
|
||
dstbo = (dstbo == BINLBF) ? BINMBF : BINLBF;
|
||
}
|
||
|
||
|
||
/*
|
||
* Zero out the dst float as a starting point.
|
||
*/
|
||
memset( (void *)dst, 0x00, ndstbytes * count);
|
||
|
||
|
||
/*
|
||
* Loop through the conversions to do.
|
||
*/
|
||
n = count;
|
||
do
|
||
{
|
||
/*
|
||
* Check the sign bit.
|
||
* Assume sign bit is high bit in most-significant byte.
|
||
*/
|
||
if ( srcbo == BINMBF )
|
||
{
|
||
if ( (src[0] & 0x80) == 0 )
|
||
negative = FALSE;
|
||
else
|
||
negative = TRUE;
|
||
}
|
||
else
|
||
{
|
||
if ( (src[nsrcbytes-1] & 0x80) == 0 )
|
||
negative = FALSE;
|
||
else
|
||
negative = TRUE;
|
||
}
|
||
|
||
/*
|
||
* Extract and unbias the exponent.
|
||
* Assume won't overflow unsigned int.
|
||
*/
|
||
if ( srcbo == BINMBF )
|
||
{
|
||
i = nsrcbytes - 1 - srcfmt->bin_expStartByte;
|
||
k = nsrcbytes - 1 - srcfmt->bin_expEndByte;
|
||
exponent = src[i--] >> srcfmt->bin_expShift;
|
||
for ( j = (8-srcfmt->bin_expShift); i > k; j += 8 )
|
||
exponent |= ((unsigned int)src[i--]) << j;
|
||
exponent |= ((unsigned int)src[i] & srcfmt->bin_expEndMask) <<j;
|
||
}
|
||
else
|
||
{
|
||
i = srcfmt->bin_expStartByte;
|
||
k = srcfmt->bin_expEndByte;
|
||
exponent = src[i++] >> srcfmt->bin_expShift;
|
||
for ( j = (8-srcfmt->bin_expShift); i < k; j += 8 )
|
||
exponent |= ((unsigned int)src[i++]) << j;
|
||
exponent |= ((unsigned int)src[i] & srcfmt->bin_expEndMask) <<j;
|
||
}
|
||
if ( exponent == 0 )
|
||
{
|
||
/*
|
||
* Original float's biased exponent was zero.
|
||
* By definition, regardless of implied bit handling
|
||
* or exponent biasing, this is a zero float. Leave
|
||
* the dst float all zeros.
|
||
*/
|
||
src += nsrcbytes;
|
||
dst += ndstbytes;
|
||
continue;
|
||
}
|
||
signed_exponent = exponent - srcfmt->bin_format.bin_expBias;
|
||
|
||
/*
|
||
* Set up for copying the mantissa into the temporary array.
|
||
*/
|
||
shift = srcfmt->bin_expShift;
|
||
if ( srcfmt->bin_format.bin_mantImplied != dstfmt->bin_format.bin_mantImplied )
|
||
{
|
||
/*
|
||
* Dest and src formats don't both handle the implied
|
||
* bit the same.
|
||
*
|
||
* If the src format has one, but the dst doesn't,
|
||
* remove the bit during the copy and subtract one
|
||
* from the exponent.
|
||
*
|
||
* If the dst format has one, but the src format
|
||
* doesn't, add the bit during the copy and add one
|
||
* to the exponent.
|
||
*/
|
||
if ( srcfmt->bin_format.bin_mantImplied )
|
||
{
|
||
/* Source has implied bit. Drop for dst.*/
|
||
if ( shift == 0 )
|
||
{
|
||
shift = 7;
|
||
mask1 = 0x7F;
|
||
mask2 = 0x80;
|
||
start_byte = srcfmt->bin_expStartByte-1;
|
||
}
|
||
else
|
||
{
|
||
shift--;
|
||
mask1 = (~srcfmt->bin_expStartMask) >>1;
|
||
mask2 = ~mask1;
|
||
start_byte = srcfmt->bin_expStartByte;
|
||
}
|
||
implied_bit = 0;
|
||
signed_exponent--;
|
||
if ( shift != 0 )
|
||
byte1_mask = mask1;
|
||
else
|
||
byte1_mask = mask2;
|
||
}
|
||
else
|
||
{
|
||
/* Destination has implied bit. Add from src.*/
|
||
if ( shift == 7 )
|
||
{
|
||
shift = 0;
|
||
start_byte = srcfmt->bin_expStartByte+1;
|
||
byte1_mask = 0x7F;
|
||
}
|
||
else
|
||
{
|
||
shift++;
|
||
mask2 = srcfmt->bin_expStartMask<<1;
|
||
mask1 = ~mask2;
|
||
start_byte = srcfmt->bin_expStartByte;
|
||
byte1_mask = ~srcfmt->bin_expStartMask;
|
||
}
|
||
implied_bit = 0x80;
|
||
signed_exponent++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* The dst and src formats both treat the implied
|
||
* bit the same.
|
||
*/
|
||
mask2 = srcfmt->bin_expStartMask;
|
||
mask1 = ~mask2;
|
||
start_byte = srcfmt->bin_expStartByte;
|
||
implied_bit = 0;
|
||
if ( shift != 0 )
|
||
byte1_mask = mask1;
|
||
else
|
||
byte1_mask = mask2;
|
||
}
|
||
|
||
/*
|
||
* Bias the exponent to the dst format and check for
|
||
* overflow and underflow.
|
||
* Assume won't overflow int32.
|
||
*/
|
||
signed_exponent += dstfmt->bin_format.bin_expBias;
|
||
if ( signed_exponent < 0 )
|
||
{
|
||
/*
|
||
* Underflow. Float in src had an exponent too
|
||
* small to represent in the dst's format. Leave
|
||
* the dst float all zero's.
|
||
*/
|
||
src += nsrcbytes;
|
||
dst += ndstbytes;
|
||
|
||
/*
|
||
* Report the error
|
||
*/
|
||
(*binErrFunc)( fd, binOp, BINEFLOATUNDERFLOW,
|
||
&srcbytes[(count-n)*nsrcbytes],
|
||
srcfmt->bin_format.bin_expBits,
|
||
dstfmt->bin_format.bin_expBits );
|
||
continue;
|
||
}
|
||
|
||
exponent = signed_exponent;
|
||
if ( (exponent & ~dstfmt->bin_expMask) != 0 )
|
||
{
|
||
/*
|
||
* Overflow. Float in src had an exponent too
|
||
* large to represent in the dst's format. Set
|
||
* the dst float to its overflow exponent and
|
||
* sign. Leave the mantissa zeroes.
|
||
*/
|
||
exponent = dstfmt->bin_format.bin_expOverflow;
|
||
negative = dstfmt->bin_format.bin_signOverflow;;
|
||
|
||
/*
|
||
* Report the error
|
||
*/
|
||
(*binErrFunc)( fd, binOp, BINEFLOATOVERFLOW,
|
||
&srcbytes[(count-n)*nsrcbytes],
|
||
srcfmt->bin_format.bin_expBits,
|
||
dstfmt->bin_format.bin_expBits );
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Zero out temporary mantissa byte array. This
|
||
* handles the filling in of zeros for mantissa
|
||
* bytes in the dst format that are not provided by
|
||
* the src format.
|
||
*/
|
||
memset( (void *)tmpmant, 0x00, MAXMANT);
|
||
|
||
|
||
/*
|
||
* Copy the src format bytes into the temporary array.
|
||
* Bytes in the array are "left-justified" to bring
|
||
* the most significant mantissa bit (perhaps the
|
||
* implied bit) in to the most significant bit of
|
||
* the first byte, and so on down the line.
|
||
*
|
||
* Note: the temporary array is in MBF format
|
||
* regardless of the source format byte order.
|
||
*/
|
||
tmp = tmpmant;
|
||
if ( shift != 0 )
|
||
{
|
||
shift8 = 8 - shift;
|
||
if ( srcbo == BINMBF )
|
||
{
|
||
k = nsrcbytes - 1;
|
||
j = k - start_byte;
|
||
*tmp++ = ((src[j]&byte1_mask)<<shift8) |
|
||
((src[j+1]&mask2)>>shift) |
|
||
implied_bit;
|
||
for ( i = j+1; i < k; i++ )
|
||
*tmp++ = ((src[i] & mask1)<<shift8) |
|
||
((src[i+1] & mask2) >> shift);
|
||
*tmp = (src[i] & mask1) << shift8;
|
||
}
|
||
else
|
||
{
|
||
*tmp++ = ((src[start_byte] & byte1_mask)<<shift8) |
|
||
((src[start_byte-1] & mask2)>>shift) |
|
||
implied_bit;
|
||
for ( i = start_byte - 1; i > 0; i-- )
|
||
*tmp++ = ((src[i] & mask1)<<shift8) |
|
||
((src[i-1] & mask2) >> shift);
|
||
*tmp = (src[0] & mask1) << shift8;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( srcbo == BINMBF )
|
||
{
|
||
*tmp++ = (src[nsrcbytes-start_byte] & byte1_mask) | implied_bit;
|
||
for ( i = nsrcbytes-start_byte+1; i < nsrcbytes; i++ )
|
||
*tmp++ = src[i];
|
||
}
|
||
else
|
||
{
|
||
*tmp++ = (src[start_byte-1] & byte1_mask) | implied_bit;
|
||
for ( i = start_byte - 2; i >= 0; i-- )
|
||
*tmp++ = src[i];
|
||
}
|
||
}
|
||
tmp = tmpmant;
|
||
|
||
/*
|
||
* Copy the temporary array into the dst's mantissa.
|
||
*/
|
||
shift = dstfmt->bin_expShift;
|
||
if ( shift != 0 )
|
||
{
|
||
mask2 = dstfmt->bin_expStartMask;
|
||
mask1 = ~mask2;
|
||
shift8= 8 - shift;
|
||
if ( dstbo == BINMBF )
|
||
{
|
||
j = ndstbytes - 1;
|
||
for ( i = j - dstfmt->bin_expStartByte; i < j; i++)
|
||
{
|
||
dst[i] |= (*tmp >> shift8)&mask1;
|
||
dst[i+1] |= (*tmp++<< shift)&mask2;
|
||
}
|
||
dst[i] |= (*tmp >> shift8) & mask1;
|
||
}
|
||
else
|
||
{
|
||
for ( i = dstfmt->bin_expStartByte; i > 0; i-- )
|
||
{
|
||
dst[i] |= (*tmp >> shift8)&mask1;
|
||
dst[i-1] |= (*tmp++<< shift)&mask2;
|
||
}
|
||
dst[0] |= (*tmp >> shift8) & mask1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( dstbo == BINMBF )
|
||
for ( i = ndstbytes-dstfmt->bin_expStartByte; i < ndstbytes; i++ )
|
||
dst[i] = *tmp++;
|
||
else
|
||
for ( i = dstfmt->bin_expStartByte-1; i >= 0; i-- )
|
||
dst[i] = *tmp++;
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* Build the exponent and add in the sign.
|
||
*/
|
||
if ( dstbo == BINMBF )
|
||
{
|
||
i = ndstbytes - 1 - dstfmt->bin_expStartByte;
|
||
j = ndstbytes - 1 - dstfmt->bin_expEndByte;
|
||
dst[i--] |= (exponent << dstfmt->bin_expShift) &
|
||
dstfmt->bin_expStartMask;
|
||
exponent >>= (8 - dstfmt->bin_expShift);
|
||
while ( i >= j )
|
||
{
|
||
dst[i--] |= exponent & 0xFF;
|
||
exponent >>= 8;
|
||
}
|
||
dst[0] &= dstfmt->bin_expEndMask;
|
||
if ( negative )
|
||
dst[0] |= 0x80;
|
||
}
|
||
else
|
||
{
|
||
i = dstfmt->bin_expStartByte;
|
||
j = dstfmt->bin_expEndByte;
|
||
dst[i++] |= (exponent << dstfmt->bin_expShift) &
|
||
dstfmt->bin_expStartMask;
|
||
exponent >>= (8 - dstfmt->bin_expShift);
|
||
while ( i <= j )
|
||
{
|
||
dst[i++] = exponent & 0xFF;
|
||
exponent >>= 8;
|
||
}
|
||
dst[i-1] &= dstfmt->bin_expEndMask;
|
||
if ( negative )
|
||
dst[ndstbytes-1] |= 0x80;
|
||
}
|
||
|
||
src += nsrcbytes;
|
||
dst += ndstbytes;
|
||
} while ( --n );
|
||
|
||
|
||
/*
|
||
* Check the destination format's flags to see if there is any special
|
||
* post-processing of the destination bytes that needs to be done.
|
||
*/
|
||
if ( dstfmt->bin_format.bin_flags & BINVAXBO )
|
||
{
|
||
/*
|
||
* Destination float uses the VAX's LBF/MBF mix byte ordering.
|
||
*
|
||
* To handle VAX byte ordering of floats, we copy the temporary
|
||
* destination bytes (set up at the top of this function)
|
||
* in to the destination byte array, swapping every two
|
||
* bytes.
|
||
*/
|
||
if ( allocdst )
|
||
{
|
||
dst = allocdst;
|
||
i = count * ndstbytes / 2;
|
||
do
|
||
{
|
||
*dstbytes++ = dst[1];
|
||
*dstbytes++ = dst[0];
|
||
dst += 2;
|
||
} while ( --i );
|
||
free( (char *)allocdst );
|
||
}
|
||
else
|
||
{
|
||
dst = tmpdst;
|
||
i = count * ndstbytes / 2;
|
||
do
|
||
{
|
||
*dstbytes++ = dst[1];
|
||
*dstbytes++ = dst[0];
|
||
dst += 2;
|
||
} while ( --i );
|
||
}
|
||
}
|
||
|
||
if ( allocsrc )
|
||
free( (char *)allocsrc );
|
||
|
||
return ( 0 );
|
||
}
|