jabberd2  2.2.16
util/serial.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 /* these are useful utilities for data serialisation */
00022 
00023 #include "util.h"
00024 
00025 /*
00026  * ser_string_get() and ser_int_get() retrieve a string (null-terminated) or
00027  * an int (sizeof(int) chars) from source, and store it in dest. source is a
00028  * pointer into buf, and will be updated before the call returns.
00029  * buf is a pointer to the start of the source buffer, and len is the length
00030  * of the buffer. if retrieving the data would take us pass the end of the
00031  * array, a non-zero value will be returned. if the call succeeds, 0 is
00032  * returned.
00033  */
00034 
00035 int ser_string_get(char **dest, int *source, const char *buf, int len)
00036 {
00037     const char *end, *c;
00038 
00039     /* end of the buffer */
00040     end = buf + ((sizeof(char) * (len - 1)));
00041 
00042     /* make sure we have a \0 before the end of the buffer */
00043     c = &(buf[*source]);
00044     while(c <= end && *c != '\0') c++;
00045     if(c > end)
00046         /* we ran past the end, fail */
00047         return 1;
00048 
00049     /* copy the string */
00050     *dest = strdup(&(buf[*source]));
00051 
00052     /* and move the pointer */
00053     *source += strlen(*dest) + 1;
00054 
00055     return 0;
00056 }
00057 
00058 int ser_int_get(int *dest, int *source, const char *buf, int len)
00059 {
00060     union
00061     {
00062         char c[sizeof(int)];
00063         int i;
00064     } u;
00065     int i;
00066 
00067     /* we need sizeof(int) bytes */
00068     if(&(buf[*source]) + sizeof(int) > buf + (sizeof(char) * len))
00069         return 1;
00070 
00071     /* copy the bytes into the union. we do it this way to avoid alignment problems */
00072     for(i = 0; i < sizeof(int); i++)
00073     {
00074         u.c[i] = buf[*source];
00075         (*source)++;
00076     }
00077     *dest = u.i;
00078 
00079     return 0;
00080 }
00081 
00082 /*
00083  * ser_string_set() and ser_int_set() stores the string or int referenced by
00084  * source into buf, starting at dest. len holds the current length of the
00085  * buffer. if storing the data would overrun the end of the buffer, the buffer
00086  * will be grown to accomodate. buf, dest and len will be updated.
00087  */
00088 
00089 /* shamelessy stolen from nad.c */
00090 
00091 #define BLOCKSIZE 1024
00092 
00094 static int _ser_realloc(void **oblocks, int len)
00095 {
00096     void *nblocks;
00097     int nlen;
00098 
00099     /* round up to standard block sizes */
00100     nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE;
00101 
00102     /* keep trying till we get it */
00103     while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1);
00104     *oblocks = nblocks;
00105     return nlen;
00106 }
00107 
00109 #define SER_SAFE(blocks, size, len) if((size) > len) len = _ser_realloc((void**)&(blocks),(size));
00110 
00111 void ser_string_set(char *source, int *dest, char **buf, int *len)
00112 {
00113     int need = sizeof(char) * (strlen(source) + 1);
00114 
00115     /* make more space if necessary */
00116     SER_SAFE(*buf, *dest + need, *len);
00117 
00118     /* copy it in */
00119     strcpy(*buf + *dest, source);
00120 
00121     /* and shift the pointer */
00122     *dest += need;
00123 }
00124 
00125 void ser_int_set(int source, int *dest, char **buf, int *len)
00126 {
00127     union
00128     {
00129         char c[sizeof(int)];
00130         int i;
00131     } u;
00132     int i;
00133 
00134     /* make more space if necessary */
00135     SER_SAFE(*buf, *dest + sizeof(int), *len)
00136 
00137     /* copy it in */
00138     u.i = source;
00139     for(i = 0; i < sizeof(int); i++)
00140         (*buf)[*dest + i] = u.c[i];
00141 
00142     /* and shift the pointer */
00143     *dest += sizeof(int);
00144 }