convert.c (7278B)
1 /* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> 2 * See LICENSE file for license details. 3 */ 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include "ixp_local.h" 8 9 int _IXP_ASSERT_VERSION; 10 11 enum { 12 SByte = 1, 13 SWord = 2, 14 SDWord = 4, 15 SQWord = 8, 16 }; 17 18 static void 19 ixp_puint(IxpMsg *msg, uint size, uint32_t *val) { 20 uint8_t *pos; 21 int v; 22 23 if(msg->pos + size <= msg->end) { 24 pos = (uint8_t*)msg->pos; 25 switch(msg->mode) { 26 case MsgPack: 27 v = *val; 28 switch(size) { 29 case SDWord: 30 pos[3] = v>>24; 31 pos[2] = v>>16; 32 case SWord: 33 pos[1] = v>>8; 34 case SByte: 35 pos[0] = v; 36 break; 37 } 38 case MsgUnpack: 39 v = 0; 40 switch(size) { 41 case SDWord: 42 v |= pos[3]<<24; 43 v |= pos[2]<<16; 44 case SWord: 45 v |= pos[1]<<8; 46 case SByte: 47 v |= pos[0]; 48 break; 49 } 50 *val = v; 51 } 52 } 53 msg->pos += size; 54 } 55 56 /** 57 * Function: ixp_pu8 58 * Function: ixp_pu16 59 * Function: ixp_pu32 60 * Function: ixp_pu64 61 * 62 * These functions pack or unpack an unsigned integer of the 63 * specified size. 64 * 65 * If P<msg>->mode is MsgPack, the value pointed to by P<val> is 66 * packed into the buffer at P<msg>->pos. If P<msg>->mode is 67 * MsgUnpack, the packed value at P<msg>->pos is loaded into the 68 * location pointed to by P<val>. In both cases, P<msg>->pos is 69 * advanced by the number of bytes read or written. If the call 70 * would advance P<msg>->pos beyond P<msg>->end, P<msg>->pos is 71 * advanced, but nothing is modified. 72 * 73 * See also: 74 * T<IxpMsg> 75 */ 76 void 77 ixp_pu8(IxpMsg *msg, uint8_t *val) { 78 uint32_t v; 79 80 v = *val; 81 ixp_puint(msg, SByte, &v); 82 *val = (uint8_t)v; 83 } 84 void 85 ixp_pu16(IxpMsg *msg, uint16_t *val) { 86 uint32_t v; 87 88 v = *val; 89 ixp_puint(msg, SWord, &v); 90 *val = (uint16_t)v; 91 } 92 void 93 ixp_pu32(IxpMsg *msg, uint32_t *val) { 94 ixp_puint(msg, SDWord, val); 95 } 96 void 97 ixp_pu64(IxpMsg *msg, uint64_t *val) { 98 uint32_t vl, vb; 99 100 vl = (uint)*val; 101 vb = (uint)(*val>>32); 102 ixp_puint(msg, SDWord, &vl); 103 ixp_puint(msg, SDWord, &vb); 104 *val = vl | ((uint64_t)vb<<32); 105 } 106 107 /** 108 * Function: ixp_pstring 109 * 110 * Packs or unpacks a UTF-8 encoded string. The packed 111 * representation of the string consists of a 16-bit unsigned 112 * integer followed by the contents of the string. The unpacked 113 * representation is a nul-terminated character array. 114 * 115 * If P<msg>->mode is MsgPack, the string pointed to by P<s> is 116 * packed into the buffer at P<msg>->pos. If P<msg>->mode is 117 * MsgUnpack, the address pointed to by P<s> is loaded with a 118 * malloc(3) allocated, nul-terminated representation of the 119 * string packed at P<msg>->pos. In either case, P<msg>->pos is 120 * advanced by the number of bytes read or written. If the 121 * action would advance P<msg>->pos beyond P<msg>->end, 122 * P<msg>->pos is still advanced but no other action is taken. 123 * 124 * See also: 125 * T<IxpMsg>, F<ixp_pstrings>, F<ixp_pdata> 126 */ 127 void 128 ixp_pstring(IxpMsg *msg, char **s) { 129 uint16_t len; 130 131 if(msg->mode == MsgPack) 132 len = strlen(*s); 133 ixp_pu16(msg, &len); 134 135 if(msg->pos + len <= msg->end) { 136 if(msg->mode == MsgUnpack) { 137 *s = emalloc(len + 1); 138 memcpy(*s, msg->pos, len); 139 (*s)[len] = '\0'; 140 }else 141 memcpy(msg->pos, *s, len); 142 } 143 msg->pos += len; 144 } 145 146 /** 147 * Function: ixp_pstrings 148 * 149 * Packs or unpacks an array of UTF-8 encoded strings. The packed 150 * representation consists of a 16-bit element count followed by 151 * an array of strings as packed by F<ixp_pstring>. The unpacked 152 * representation is an array of nul-terminated character arrays. 153 * 154 * If P<msg>->mode is MsgPack, P<*num> strings in the array 155 * pointed to by P<strings> are packed into the buffer at 156 * P<msg>->pos. If P<msg>->mode is MsgUnpack, P<*num> is loaded 157 * with the number of strings unpacked, the array at 158 * P<*strings> is loaded with pointers to the unpacked strings, 159 * and P<(*strings)[0]> must be freed by the user. In either 160 * case, P<msg>->pos is advanced by the number of bytes read or 161 * written. If the action would advance P<msg>->pos beyond 162 * P<msg>->end, P<msg>->pos is still advanced, but no other 163 * action is taken. If P<*num> is greater than P<max>, 164 * P<msg>->pos is set beyond P<msg>->end and no other action is 165 * taken. 166 * 167 * See also: 168 * P<IxpMsg>, P<ixp_pstring>, P<ixp_pdata> 169 */ 170 void 171 ixp_pstrings(IxpMsg *msg, uint16_t *num, char *strings[], uint max) { 172 char *s; 173 uint i, size; 174 uint16_t len; 175 176 ixp_pu16(msg, num); 177 if(*num > max) { 178 msg->pos = msg->end+1; 179 return; 180 } 181 182 SET(s); 183 if(msg->mode == MsgUnpack) { 184 s = msg->pos; 185 size = 0; 186 for(i=0; i < *num; i++) { 187 ixp_pu16(msg, &len); 188 msg->pos += len; 189 size += len; 190 if(msg->pos > msg->end) 191 return; 192 } 193 msg->pos = s; 194 size += *num; 195 s = emalloc(size); 196 } 197 198 for(i=0; i < *num; i++) { 199 if(msg->mode == MsgPack) 200 len = strlen(strings[i]); 201 ixp_pu16(msg, &len); 202 203 if(msg->mode == MsgUnpack) { 204 memcpy(s, msg->pos, len); 205 strings[i] = (char*)s; 206 s += len; 207 msg->pos += len; 208 *s++ = '\0'; 209 }else 210 ixp_pdata(msg, &strings[i], len); 211 } 212 } 213 214 /** 215 * Function: ixp_pdata 216 * 217 * Packs or unpacks a raw character buffer of size P<len>. 218 * 219 * If P<msg>->mode is MsgPack, buffer pointed to by P<data> is 220 * packed into the buffer at P<msg>->pos. If P<msg>->mode is 221 * MsgUnpack, the address pointed to by P<s> is loaded with a 222 * malloc(3) allocated buffer with the contents of the buffer at 223 * P<msg>->pos. In either case, P<msg>->pos is advanced by the 224 * number of bytes read or written. If the action would advance 225 * P<msg>->pos beyond P<msg>->end, P<msg>->pos is still advanced 226 * but no other action is taken. 227 * 228 * See also: 229 * T<IxpMsg>, F<ixp_pstring> 230 */ 231 void 232 ixp_pdata(IxpMsg *msg, char **data, uint len) { 233 if(msg->pos + len <= msg->end) { 234 if(msg->mode == MsgUnpack) { 235 *data = emalloc(len); 236 memcpy(*data, msg->pos, len); 237 }else 238 memcpy(msg->pos, *data, len); 239 } 240 msg->pos += len; 241 } 242 243 /** 244 * Function: ixp_pfcall 245 * Function: ixp_pqid 246 * Function: ixp_pqids 247 * Function: ixp_pstat 248 * Function: ixp_sizeof_stat 249 * 250 * These convenience functions pack or unpack the contents of 251 * libixp structures into their wire format. They behave as if 252 * F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>, F<ixp_pu64>, and 253 * F<ixp_pstring> were called for each member of the structure 254 * in question. ixp_pqid is to ixp_pqid as F<ixp_pstrings> is to 255 * ixp_pstring. 256 * 257 * ixp_sizeof_stat returns the size of the packed represention 258 * of P<stat>. 259 * 260 * See also: 261 * T<IxpMsg>, F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>, 262 * F<ixp_pu64>, F<ixp_pstring>, F<ixp_pstrings> 263 */ 264 void 265 ixp_pqid(IxpMsg *msg, IxpQid *qid) { 266 ixp_pu8(msg, &qid->type); 267 ixp_pu32(msg, &qid->version); 268 ixp_pu64(msg, &qid->path); 269 } 270 271 void 272 ixp_pqids(IxpMsg *msg, uint16_t *num, IxpQid qid[], uint max) { 273 int i; 274 275 ixp_pu16(msg, num); 276 if(*num > max) { 277 msg->pos = msg->end+1; 278 return; 279 } 280 281 for(i = 0; i < *num; i++) 282 ixp_pqid(msg, &qid[i]); 283 } 284 285 void 286 ixp_pstat(IxpMsg *msg, IxpStat *stat) { 287 uint16_t size; 288 289 if(msg->mode == MsgPack) 290 size = ixp_sizeof_stat(stat) - 2; 291 292 ixp_pu16(msg, &size); 293 ixp_pu16(msg, &stat->type); 294 ixp_pu32(msg, &stat->dev); 295 ixp_pqid(msg, &stat->qid); 296 ixp_pu32(msg, &stat->mode); 297 ixp_pu32(msg, &stat->atime); 298 ixp_pu32(msg, &stat->mtime); 299 ixp_pu64(msg, &stat->length); 300 ixp_pstring(msg, &stat->name); 301 ixp_pstring(msg, &stat->uid); 302 ixp_pstring(msg, &stat->gid); 303 ixp_pstring(msg, &stat->muid); 304 }