693 lines
16 KiB
C
Executable File
693 lines
16 KiB
C
Executable File
#include "mutils.h"
|
|
|
|
/* Note: all the blob realated routines are adapted from ImageMagick */
|
|
|
|
/*
|
|
** attaches a blob to the MutilsBlob structure
|
|
*/
|
|
void mutils_attach_blob(MutilsBlob *blob_info,void *blob,size_t length)
|
|
{
|
|
if (blob == (MutilsBlob *) NULL)
|
|
return;
|
|
|
|
blob_info->data=(unsigned char *) blob;
|
|
blob_info->length=length;
|
|
blob_info->offset=0;
|
|
}
|
|
|
|
/* duplicate the given MutilsBlob structure */
|
|
/* returns NULL on failure */
|
|
/**
|
|
* @brief Duplicates the given blob
|
|
* @param blob Blob to duplicate
|
|
* @return blob The duplicated blob on success, NULL on failure
|
|
*
|
|
*/
|
|
MutilsBlob *mutils_clone_blobinfo(MutilsBlob *blob)
|
|
{
|
|
MutilsBlob
|
|
*clone_info;
|
|
|
|
clone_info=(MutilsBlob *) mutils_acquire_memory(sizeof(MutilsBlob));
|
|
if (clone_info == (MutilsBlob *) NULL)
|
|
{
|
|
mutils_error("%s (%d) - unable to clone MutilsBlob, memory allocation failed\n",MUTILS_CFL);
|
|
return(NULL);
|
|
}
|
|
if (blob == (MutilsBlob *) NULL)
|
|
{
|
|
memset(clone_info,0,sizeof(MutilsBlob));
|
|
return(clone_info);
|
|
}
|
|
|
|
*clone_info=(*blob);
|
|
return(clone_info);
|
|
}
|
|
|
|
/**
|
|
* @brief rewind a blob
|
|
* @param blob
|
|
*
|
|
* Rewinds a blob after processing it
|
|
*/
|
|
void mutils_rewind_blob(MutilsBlob *blob)
|
|
{
|
|
if (!blob)
|
|
return;
|
|
blob->offset=0;
|
|
}
|
|
|
|
/**
|
|
* allocate memory for blob and and the data member
|
|
* @param data_len - the length of the data in bytes
|
|
* @return - pointer to blob on SUCCESS, NULL on failure
|
|
*/
|
|
MutilsBlob *mutils_allocate_blob(int data_len)
|
|
{
|
|
MutilsBlob
|
|
*blob=NULL;
|
|
|
|
if (data_len <= 0)
|
|
return(NULL);
|
|
|
|
/* allocate memory for blob */
|
|
blob=mutils_clone_blobinfo(NULL);
|
|
if (blob == NULL)
|
|
return(NULL);
|
|
|
|
/* allocate memory for data */
|
|
blob->length=data_len;
|
|
blob->data=(unsigned char *) mutils_acquire_memory(data_len+1);
|
|
if (blob->data == NULL)
|
|
{
|
|
mutils_destroy_blob(blob);
|
|
return(NULL);
|
|
}
|
|
|
|
return(blob);
|
|
}
|
|
|
|
|
|
/*
|
|
** detaches a blob from the BlobInfo structure.
|
|
*/
|
|
void mutils_detach_blob(MutilsBlob *blob)
|
|
{
|
|
if (blob == NULL)
|
|
return;
|
|
|
|
blob->length=0;
|
|
blob->offset=0;
|
|
blob->data=(unsigned char *) NULL;
|
|
}
|
|
|
|
/**
|
|
* creates a MutilsBlob object. allocates memory for data, copies the passed
|
|
* data, update the length and returns the blob
|
|
* @param data The data to copy to blob's data member
|
|
* @param data_len The number of bytes of data
|
|
* @return MutilsBlob on success NULL on failure
|
|
*/
|
|
MutilsBlob *mutils_data_to_blob(unsigned char *data,int data_len)
|
|
{
|
|
MutilsBlob
|
|
*blob;
|
|
|
|
if (data == (unsigned char *) NULL)
|
|
return(NULL);
|
|
|
|
blob=mutils_clone_blobinfo(NULL);
|
|
if (blob == (MutilsBlob *) NULL)
|
|
{
|
|
(void) fprintf(stderr,"%s (%d) unable to create blob, memory allocation problem\n",__FILE__,__LINE__);
|
|
return((MutilsBlob *) NULL);
|
|
}
|
|
blob->length=data_len;
|
|
blob->data=(unsigned char *) mutils_acquire_memory(blob->length+1);
|
|
if (blob->data == NULL)
|
|
{
|
|
(void) fprintf(stderr,"Unable to create blob data, memory allocation problem\n");
|
|
mutils_destroy_blob(blob);
|
|
return((void *) NULL);
|
|
}
|
|
|
|
memcpy(blob->data,data,blob->length);
|
|
|
|
return(blob);
|
|
}
|
|
|
|
/*
|
|
** returns the contents of a file as a blob.
|
|
** NULL on failure.
|
|
*/
|
|
MutilsBlob *mutils_file_to_blob(char *filename)
|
|
{
|
|
MutilsBlob
|
|
*blob;
|
|
|
|
long
|
|
count=0;
|
|
|
|
size_t
|
|
length;
|
|
|
|
int
|
|
fd;
|
|
|
|
struct stat
|
|
statbuf;
|
|
|
|
if (filename == NULL)
|
|
return(NULL);
|
|
|
|
fd=open(filename,O_RDONLY | O_BINARY);
|
|
if (fd == -1)
|
|
{
|
|
(void) fprintf(stderr,"Unable to open file %s\n",filename);
|
|
return((void *) NULL);
|
|
}
|
|
|
|
length=(size_t) (fstat(fd,&statbuf)) < 0 ? 0 : statbuf.st_size;
|
|
blob=mutils_clone_blobinfo(NULL);
|
|
if (blob == (MutilsBlob *) NULL)
|
|
{
|
|
(void )close(fd);
|
|
(void) fprintf(stderr,"unable to create blob, memory allocation problem\n");
|
|
return((MutilsBlob *) NULL);
|
|
}
|
|
blob->length=length;
|
|
blob->data=(unsigned char *) mutils_acquire_memory(blob->length+1);
|
|
if (blob->data == NULL)
|
|
{
|
|
(void) fprintf(stderr,"Unable to create blob data, memory allocation problem\n");
|
|
mutils_destroy_blob(blob);
|
|
return((void *) NULL);
|
|
}
|
|
|
|
count=read(fd,blob->data,length);
|
|
(void) close(fd);
|
|
|
|
if ((size_t) count != length)
|
|
{
|
|
mutils_destroy_blob(blob);
|
|
return((void *) NULL);
|
|
}
|
|
|
|
return(blob);
|
|
}
|
|
|
|
/*
|
|
** deallocates memory associated with an BlobInfo structure
|
|
*/
|
|
void mutils_destroy_blob(MutilsBlob *blob)
|
|
{
|
|
if (blob == NULL)
|
|
return;
|
|
|
|
if (blob->data)
|
|
(void) free(blob->data);
|
|
mutils_liberate_memory((void **) &blob);
|
|
}
|
|
|
|
/*
|
|
** converts a least-significant byte first buffer of integers to
|
|
** most-significant byte first.
|
|
*/
|
|
void mutils_msb_order_long(char *p,const size_t length)
|
|
{
|
|
register char
|
|
c,
|
|
*q,
|
|
*sp;
|
|
|
|
if (p == NULL)
|
|
return;
|
|
|
|
q=p+length;
|
|
while (p < q)
|
|
{
|
|
sp=p+3;
|
|
c=(*sp);
|
|
*sp=(*p);
|
|
*p++=c;
|
|
sp=p+1;
|
|
c=(*sp);
|
|
*sp=(*p);
|
|
*p++=c;
|
|
p+=2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** converts a least-significant byte first buffer of integers to
|
|
** most-significant byte first.
|
|
*/
|
|
void mutils_msb_order_short(char *p,const size_t length)
|
|
{
|
|
register char
|
|
c,
|
|
*q;
|
|
|
|
if (p == NULL)
|
|
return;
|
|
|
|
q=p+length;
|
|
while (p < q)
|
|
{
|
|
c=(*p);
|
|
*p=(*(p+1));
|
|
p++;
|
|
*p++=c;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** reads data from the blob and returns it. It returns the number of bytes
|
|
** read.
|
|
** blob - MutilsBlob
|
|
** length - number of bytes to read from blob
|
|
** data - returns
|
|
**
|
|
** returns > 0 on sucess, -1 on failure
|
|
*/
|
|
int mutils_read_blob(MutilsBlob *blob,const size_t length,void *data)
|
|
{
|
|
int
|
|
count,
|
|
n=0;
|
|
|
|
if (blob == (MutilsBlob *) NULL)
|
|
return(-1);
|
|
|
|
if (blob->data != (unsigned char *) NULL)
|
|
{
|
|
count=MUTILS_MIN(length,blob->length - blob->offset);
|
|
if (count > 0)
|
|
{
|
|
(void) memcpy(data,blob->data + blob->offset,count);
|
|
blob->offset += count;
|
|
}
|
|
/*
|
|
if (count < length)
|
|
return(-1);
|
|
*/
|
|
return(count);
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
** reads a single byte from blob and returns it.
|
|
** returns -1 on error
|
|
*/
|
|
int mutils_read_blob_byte(MutilsBlob *blob)
|
|
{
|
|
size_t
|
|
count;
|
|
|
|
unsigned char
|
|
buffer[1];
|
|
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
count=mutils_read_blob(blob,1,(unsigned char *) buffer);
|
|
if (count == 0)
|
|
return(-1);
|
|
|
|
return(*buffer);
|
|
}
|
|
|
|
/*
|
|
** reads a long value as a 32 bit quantity in least-significant byte first
|
|
**order.
|
|
*/
|
|
unsigned long mutils_read_blob_lsb_long(MutilsBlob *blob)
|
|
{
|
|
unsigned char
|
|
buffer[4];
|
|
|
|
unsigned long
|
|
value;
|
|
|
|
if (blob == NULL)
|
|
return ((unsigned long) ~0);
|
|
|
|
value=mutils_read_blob(blob,4,(unsigned char *) buffer);
|
|
if (value == 0)
|
|
return ((unsigned long) ~0);
|
|
|
|
value=buffer[3] << 24;
|
|
value|=buffer[2] << 16;
|
|
value|=buffer[1] << 8;
|
|
value|=buffer[0];
|
|
return(value);
|
|
}
|
|
|
|
/*
|
|
** reads a short value as a 16 bit quantity in least-significant byte first
|
|
* order.
|
|
*/
|
|
unsigned short mutils_read_blob_lsb_short(MutilsBlob *blob)
|
|
{
|
|
unsigned char
|
|
buffer[2];
|
|
|
|
unsigned short
|
|
value;
|
|
|
|
if (blob == (MutilsBlob *) NULL)
|
|
return((unsigned short) ~0);
|
|
|
|
value=mutils_read_blob(blob,2,(unsigned char *) buffer);
|
|
if (value == 0)
|
|
return((unsigned short) ~0);
|
|
|
|
value=buffer[1] << 8;
|
|
value|=buffer[0];
|
|
|
|
return(value);
|
|
}
|
|
|
|
/**
|
|
* @brief reads a long value as a 32 bit quantity in most-significant byte
|
|
* firstorder.
|
|
* @param blob The blob
|
|
* @param err_no If no error err_no is set to 0 other wise it is set to
|
|
* -1
|
|
* @param The read value as unsigned long
|
|
*
|
|
* The caller should always check the err_no instead of the return code,
|
|
* because there's no other way to return a number in case of error
|
|
*/
|
|
unsigned long mutils_read_blob_msb_long(MutilsBlob *blob,int *err_no)
|
|
{
|
|
unsigned char
|
|
buffer[4];
|
|
|
|
unsigned long
|
|
value;
|
|
|
|
*err_no=0;
|
|
|
|
if (blob == (MutilsBlob *) NULL)
|
|
{
|
|
mutils_error("%s (%d) - mutils_read_blob_msb_long() empty blob\n",
|
|
MUTILS_CFL);
|
|
*err_no=(-1);
|
|
return((unsigned long) ~0);
|
|
}
|
|
|
|
value=mutils_read_blob(blob,4,(unsigned char *) buffer);
|
|
if (value == 0)
|
|
{
|
|
mutils_error("%s (%d) - mutils_read_blob_msb_long() could not read 4 bytes from blob\n",MUTILS_CFL);
|
|
*err_no=(-1);
|
|
return((unsigned long) ~0);
|
|
}
|
|
/*
|
|
** We can not return ~0 on error because if the value ffffff is read,
|
|
** the return code will indicate it's an error
|
|
*/
|
|
/* return((unsigned long) ~0);*/
|
|
|
|
value=(unsigned long) buffer[0] << 24;
|
|
value|=buffer[1] << 16;
|
|
value|=buffer[2] << 8;
|
|
value|=buffer[3];
|
|
|
|
return(value);
|
|
}
|
|
|
|
/**
|
|
* @brief reads a short value as a 16 bit quantity in most-significant byte
|
|
* firstorder.
|
|
* @param blob The blob
|
|
* @param err_no If no error err_no is set to 0 other wise it is set to
|
|
* -1
|
|
* @return The read value as unsigned short
|
|
*
|
|
* The caller should always check the err_no instead of the return code,
|
|
* because there's no other way to return a number in case of error
|
|
*/
|
|
unsigned short mutils_read_blob_msb_short(MutilsBlob *blob,int *err_no)
|
|
{
|
|
unsigned char
|
|
buffer[2];
|
|
|
|
unsigned short
|
|
value;
|
|
|
|
*err_no=0;
|
|
if (blob == NULL)
|
|
{
|
|
mutils_error("%s (%d) - mutils_read_blob_msb_short() empty blob\n",
|
|
MUTILS_CFL);
|
|
*err_no=(-1);
|
|
return((unsigned short) ~0);
|
|
}
|
|
|
|
value=mutils_read_blob(blob,2,(unsigned char *) buffer);
|
|
if (value == 0)
|
|
{
|
|
mutils_error("%s (%d) - mutils_read_blob_msb_short() could not read 2 bytes from blob\n",MUTILS_CFL);
|
|
*err_no=(-1);
|
|
return((unsigned short) ~0);
|
|
}
|
|
|
|
/*
|
|
** We can not return ~0 on error because if the value ffff is read,
|
|
** the return code will indicate it's an error
|
|
*/
|
|
/* return((unsigned short) ~0);*/
|
|
|
|
value=(unsigned short) (buffer[0] << 8);
|
|
value |= buffer[1];
|
|
|
|
return(value);
|
|
}
|
|
|
|
/* reads characters from a blob until a new line or cr is read*/
|
|
/* the string is null terminated */
|
|
char *mutils_read_blob_string(MutilsBlob *blob,char *string,int slen)
|
|
{
|
|
int
|
|
c,
|
|
i;
|
|
|
|
if (blob == NULL)
|
|
return(NULL);
|
|
|
|
for (i=0; i < slen; i++)
|
|
{
|
|
c=mutils_read_blob_byte(blob);
|
|
if (c == -1)
|
|
return((char *) NULL);
|
|
string[i]=c;
|
|
if ((string[i] == '\n') || (string[i] == '\r'))
|
|
break;
|
|
}
|
|
string[i]='\0';
|
|
return(string);
|
|
}
|
|
|
|
/* returns current size of the blob */
|
|
/* -1 on error */
|
|
int mutils_size_blob(MutilsBlob *blob)
|
|
{
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
if (blob->data != (unsigned char *) NULL)
|
|
return(blob->length);
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/* returns the current value of the blob position */
|
|
/* -1 on failure */
|
|
int mutils_tell_blob(MutilsBlob *blob)
|
|
{
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
if (blob->data != (unsigned char *) NULL)
|
|
return(blob->offset);
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/**
|
|
* @brief Writes length bytes of data to blob
|
|
* @param blob The blob to fill with data
|
|
* @param length Length of data
|
|
* @param data Data to write to blob
|
|
*
|
|
* blob->data must have at least blob->length bytes of data pre-allocated.
|
|
* If we need more than that, memory will be allocated dynamically.
|
|
*
|
|
* blob->offset is incremented with the amount of data written to blob
|
|
*
|
|
* This code is adapted from ImageMagick. ImageMagick's version reallocate
|
|
* data bultiple of 8 bytes. This one allocates exact number of bytes as
|
|
* needed.
|
|
*
|
|
*/
|
|
int mutils_write_blob(MutilsBlob *blob,const size_t length,const void *data)
|
|
{
|
|
int
|
|
reallocate_bytes=0;
|
|
|
|
if (blob == (MutilsBlob *) NULL)
|
|
return(-1);
|
|
|
|
if (blob->data != (unsigned char *) NULL)
|
|
{
|
|
if (length > (blob->length - blob->offset))
|
|
{
|
|
reallocate_bytes=(length - (blob->length - blob->offset));
|
|
mutils_info("%s (%d) out of memory, re-allocating %d bytes\n",
|
|
MUTILS_CFL,reallocate_bytes);
|
|
/* find out how many bytes we need to re-allocate */
|
|
blob->length += reallocate_bytes;
|
|
mutils_reacquire_memory((void **) &blob->data,blob->length);
|
|
if (blob->data == (unsigned char *) NULL)
|
|
{
|
|
mutils_detach_blob(blob);
|
|
return(-1);
|
|
}
|
|
}
|
|
(void) memcpy(blob->data + blob->offset,data,length);
|
|
blob->offset += length;
|
|
if (blob->offset > (off_t) blob->length)
|
|
blob->length=blob->offset;
|
|
return(length);
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
** write an integer to a blob. It returns the number of bytes written
|
|
** and -1 on failure
|
|
*/
|
|
size_t mutils_write_blob_byte(MutilsBlob *blob,const long value)
|
|
{
|
|
|
|
unsigned char
|
|
buffer[1];
|
|
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
buffer[0]=(unsigned char) value;
|
|
return(mutils_write_blob(blob,1,buffer));
|
|
}
|
|
/*
|
|
** writes a long value as a 32 bit quantity in least-significant byte first
|
|
** order. returns the number of unsigned longs written. -1 on error
|
|
*/
|
|
int mutils_write_blob_lsb_long(MutilsBlob *blob,const unsigned long value)
|
|
{
|
|
unsigned char
|
|
buffer[4];
|
|
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
buffer[0]=(unsigned char) value;
|
|
buffer[1]=(unsigned char) (value >> 8);
|
|
buffer[2]=(unsigned char) (value >> 16);
|
|
buffer[3]=(unsigned char) (value >> 24);
|
|
|
|
return(mutils_write_blob(blob,4,buffer));
|
|
}
|
|
|
|
/*
|
|
** writes a long value as a 16 bit quantity in least-significant byte first
|
|
** order. returns the number of unsigned longs written. -1 on failure
|
|
*/
|
|
int mutils_write_blob_lsb_short(MutilsBlob *blob,const unsigned long value)
|
|
{
|
|
unsigned char
|
|
buffer[2];
|
|
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
buffer[0]=(unsigned char) value;
|
|
buffer[1]=(unsigned char) (value >> 8);
|
|
|
|
return(mutils_write_blob(blob,2,buffer));
|
|
}
|
|
|
|
/*
|
|
** writes a long value as a 32 bit quantity in most-significant byte first
|
|
** order. returns the number of unsigned longs written. -1 on failure
|
|
*/
|
|
int mutils_write_blob_msb_long(MutilsBlob *blob,const unsigned long value)
|
|
{
|
|
unsigned char
|
|
buffer[4];
|
|
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
buffer[0]=(unsigned char) (value >> 24);
|
|
buffer[1]=(unsigned char) (value >> 16);
|
|
buffer[2]=(unsigned char) (value >> 8);
|
|
buffer[3]=(unsigned char) value;
|
|
|
|
return(mutils_write_blob(blob,4,buffer));
|
|
|
|
}
|
|
|
|
/*
|
|
** writes a long value as a 16 bit quantity in most-significant byte first
|
|
** order. returns the number of unsigned longs written. -1 on failure
|
|
*/
|
|
int mutils_write_blob_msb_short(MutilsBlob *blob,const unsigned long value)
|
|
{
|
|
unsigned char
|
|
buffer[2];
|
|
|
|
if (blob == NULL)
|
|
return(-1);
|
|
|
|
buffer[0]=(unsigned char) (value >> 8);
|
|
buffer[1]=(unsigned char) value;
|
|
|
|
return(mutils_write_blob(blob,2,buffer));
|
|
}
|
|
|
|
/*
|
|
** write a string to a blob. It returns the number of characters written
|
|
*/
|
|
size_t mutils_write_blob_string(MutilsBlob *blob,const char *string)
|
|
{
|
|
if (string == NULL)
|
|
return(0);
|
|
|
|
if (blob == NULL)
|
|
return(0);
|
|
|
|
return(mutils_write_blob(blob,strlen(string),string));
|
|
}
|
|
|
|
|
|
|
|
void mutils_hex_dump_blob(FILE *fp,MutilsBlob *blob)
|
|
{
|
|
if (blob && blob->data)
|
|
{
|
|
if (blob->length)
|
|
mutils_hex_dump(fp,blob->data,blob->length);
|
|
}
|
|
else
|
|
{
|
|
(void) fprintf(stderr,"Empty blob\n");
|
|
}
|
|
}
|