#include "mutils.h" /* ** bunch of useful functions taken from my libmutils library ** muquit@muquit.com May-21-2015 */ /* ** Note: all the blob realated routines are adapted from some ** old version of ImageMagick many years ago! */ void mutils_liberate_memory(void **memory) { if (memory == NULL) return; if (*memory) free(*memory); *memory=(void *) NULL; } void mutils_liberate(void **memory) { if (memory == NULL) return; if (*memory) free(*memory); *memory=(void *) NULL; } void mutils_free_zero(void *buf,int size) { if (buf) { memset(buf,0,size); mutils_liberate_memory(&buf); } } /** * @brief same as mutils_acquire_memory */ void *mutils_acquire_memory(size_t size) { void *ptr; if (size == 0) { (void) fprintf(stderr,"%s (%d) - allocation size is specified as 0\n",MUTILS_CFL); return(NULL); } ptr=malloc(size); if (ptr) { memset(ptr,0,size); } return(ptr); } /* ** changes the size of the memory and returns a pointer to the (possibly ** moved) block. The contents will be unchanged up to the lesser of the new ** and old sizes. */ void mutils_reacquire_memory(void **memory,const size_t size) { void *allocation; if (memory == NULL) return; if (*memory == (void *) NULL) { *memory=mutils_acquire_memory(size); return; } allocation=realloc(*memory,size); if (allocation == (void *) NULL) mutils_liberate_memory((void **) memory); *memory=allocation; } /* 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) { (void) fprintf(stderr,"%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(const 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 = (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; 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) { (void) fprintf(stderr,"%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) { (void) fprintf(stderr,"%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) { (void) fprintf(stderr,"%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) { (void) fprintf(stderr,"%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. If length if 0, return 0 * @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 (length == 0) return(0); if (blob->data != (unsigned char *) NULL) { if (length > (blob->length - blob->offset)) { reallocate_bytes=(length - (blob->length - blob->offset)); /* 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)); } /** * convert a hex string to it's binary format. * @param hex_string - The hex string to convert * @param len - length of the hex string * @param *olen - The length of the binary string - returns * * @return pointer to a unsigned char holding the binary version of the * hex string. returns NULL on failure. The caller should check * olen (> 0) before using the binary * * @note Memory is allocated for the retured unsigned char pointer * The caller is responsible to free it * * The format of the hex string can be any of: * 0xde:ad:be:ef:ca:fe * de:ad:be:ef:ca:fe * de-ad-be-ef-ca-fe * 0xde-ad-be-ef-ca-fe * de:ad-be_ef:ca:fe * * The converted binary value will be: de ad be ef ca fe * * It will only convert valid hex strings to binary, for example, if * the string is like: de:gh:ad:ff:bb:kk:cc * The binary value will contain: de ad ff bb cc * Note, gh and kk are ignored */ unsigned char *mutils_hex_to_bin(const char *hex_string,int len,int *olen) { int j=0; int bin_len=0, n=0, i; unsigned char value, *out; const char *cp=hex_string; *olen = 0; if (! hex_string || ! len) return(NULL); if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) { cp += 2; n=2; } /* ** allocate half of hex_string as the length of binary. ** we may be allocated more than needed as : - etc may be ** part of the hex string */ bin_len=(len >> 1); if (bin_len <= 0) return(NULL); out=(unsigned char *) malloc(bin_len*sizeof(unsigned char)); memset(out,0,bin_len); for (i=n; i < len; i += 2) { if (hex_string[i] == '\n' || hex_string[i] == '\r' || hex_string[i] == ' ' || hex_string[i] == '\t' || hex_string[i] == ':' || hex_string[i] == '-' || hex_string[i] == '_') { i--; continue; } if (isxdigit(hex_string[i]) && isxdigit(hex_string[i+1])) { value=(mutils_hex_char_to_bin (hex_string[i]) << 4) & 0xf0; value |= (mutils_hex_char_to_bin(hex_string[i+1]) & 0x0f); out[j++]=value; } } *olen=j; return(out); } unsigned char mutils_hex_char_to_bin(char x) { if (x >= '0' && x <= '9') return(x - '0'); x=toupper(x); return((x - 'A') + 10); } void mutils_hex_print(FILE *fp,unsigned char *bytes,int len) { int i; for (i=0; i < len; i++) { (void) fprintf(fp,"%02x ",bytes[i]); if ((i % 16) == 15) fprintf(fp, "\n"); } (void) fprintf(fp,"\n"); (void)fflush(fp); }