pack.c
来自「GNet是一个简单的网络库。它是目标定向的」· C语言 代码 · 共 1,001 行 · 第 1/2 页
C
1,001 行
/* GNet - Networking library * Copyright (C) 2000, 2001 David Helder * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include "pack.h"#include <string.h>static guint strlenn(char* str, guint n);static void flipmemcpy(char* dst, char* src, guint n);#define MEMCPY(D,S,N) \ do { \ if ((N) == 1) \ *((char*) (D)) = *((char*) (S)); \ else if ((N) == 2) \ { \ ((char*) (D))[0] = ((char*) (S))[0]; \ ((char*) (D))[1] = ((char*) (S))[1]; \ } \ else if ((N) == 4) \ { \ ((char*) (D))[0] = ((char*) (S))[0]; \ ((char*) (D))[1] = ((char*) (S))[1]; \ ((char*) (D))[2] = ((char*) (S))[2]; \ ((char*) (D))[3] = ((char*) (S))[3]; \ } \ else \ { \ memcpy((D), (S), (N)); \ } \ } while(0)#define FLIPMEMCPY(D,S,N) \ do { \ if ((N) == 1) \ *((char*) (D)) = *((char*) (S)); \ else if ((N) == 2) \ { \ ((char*) (D))[0] = ((char*) (S))[1]; \ ((char*) (D))[1] = ((char*) (S))[0]; \ } \ else if ((N) == 4) \ { \ ((char*) (D))[0] = ((char*) (S))[3]; \ ((char*) (D))[1] = ((char*) (S))[2]; \ ((char*) (D))[2] = ((char*) (S))[1]; \ ((char*) (D))[3] = ((char*) (S))[0]; \ } \ else \ { \ flipmemcpy((D), (S), (N)); \ } \ } while(0)static guintstrlenn(char* str, guint n){ guint len = 0; while (*str++ && len < n) ++len; return len;}static void flipmemcpy(char* dst, char* src, guint n){ int nn = n; for (; n; --n) *dst++ = src[nn-n];}# if (G_BYTE_ORDER == G_LITTLE_ENDIAN)# define LEMEMCPY(D,S,N) MEMCPY(D,S,N)# define BEMEMCPY(D,S,N) FLIPMEMCPY(D,S,N)# else# define BEMEMCPY(D,S,N) MEMCPY(D,S,N)# define LEMEMCPY(D,S,N) FLIPMEMCPY(D,S,N)# endif/* **************************************** *//* SIZE of type *//* TYPE is actual data type, VTYPE is type according to vargs, TYPESTD is the standard type (in endian or standard mode) */#define SIZE(TYPENATIVE, VTYPE, TYPESTD) \ do { \ if (mult == 0) mult = 1; \ n += mult * (!sizemode ? sizeof(TYPENATIVE) : sizeof(TYPESTD)); \ for (; mult != 0; mult--) { TYPENATIVE t = (TYPENATIVE) va_arg (args, VTYPE); t=t;} \ /* mult = 0; */ \ } while(0)/* PACK does MEMCPY regardless of endian *//* TYPE is actual data type, VTYPE is type according to vargs */#define PACK(TYPE, VTYPE) \ do { \ for (mult=(mult?mult:1); mult; --mult) \ { \ TYPE t; \ g_return_val_if_fail (n + sizeof(TYPE) <= len, -1); \ t = (TYPE) va_arg (args, VTYPE); \ MEMCPY(buffer, (char*) &t, sizeof(TYPE)); \ buffer += sizeof(TYPE); \ n += sizeof(TYPE); \ } \ mult = 0; \ } while(0)/* PACK2 does memcpy based on endian */#define PACK2(TYPENATIVE, VTYPE, TYPESTD) \ do { \ for (mult=(mult?mult:1); mult; --mult) \ { \ if (sizemode == 0) \ { \ TYPENATIVE t; \ g_return_val_if_fail (n + sizeof(TYPENATIVE) <= len, -1); \ t = (TYPENATIVE) va_arg (args, VTYPE); \ MEMCPY(buffer, (char*) &t, sizeof(TYPENATIVE)); \ buffer += sizeof(TYPENATIVE); \ n += sizeof(TYPENATIVE); \ } \ else if (sizemode == 1) \ { \ TYPESTD t; \ g_return_val_if_fail (n + sizeof(TYPESTD) <= len, -1); \ t = (TYPESTD) va_arg (args, VTYPE); \ LEMEMCPY(buffer, (char*) &t, sizeof(TYPESTD)); \ buffer += sizeof(TYPESTD); \ n += sizeof(TYPESTD); \ } \ else if (sizemode == 2) \ { \ TYPESTD t; \ g_return_val_if_fail (n + sizeof(TYPESTD) <= len, -1); \ t = (TYPESTD) va_arg (args, VTYPE); \ BEMEMCPY(buffer, (char*) &t, sizeof(TYPESTD)); \ buffer += sizeof(TYPESTD); \ n += sizeof(TYPESTD); \ } \ } \ mult = 0; \ } while(0)/* **************************************** *//** * gnet_pack: * @format: Pack format * @buffer: Buffer to pack to * @len: Length of buffer * @Varargs: Variables to pack from * * The pack format string is a list of types. Each type is * represented by a character. Most types can be prefixed by an * integer, which represents how many times it is repeated (eg, * "4i2b" is equivalent to "iiiibb". * * Native size/order is the default. If the first character of * FORMAT is < then little endian order and standard size are used. * If the first character is > or !, then big endian (or network) * order and standard size are used. Standard sizes are 1 byte for * chars, 2 bytes for shorts, and 4 bytes for ints and longs. * x is a pad byte. The pad byte is the NULL character. * * b/B are signed/unsigned chars * * h/H are signed/unsigned shorts * * i/I are signed/unsigned ints * * l/L are signed/unsigned longs * * f/D are floats/doubles (always native order/size) * * v is a void pointer (always native size) * * s is a zero-terminated string. REPEAT is repeat. * * S is a zero-padded string of maximum length REPEAT. We write * up-to a NULL character or REPEAT characters, whichever comes * first. We then write NULL characters up to a total of REPEAT * characters. Special case: If REPEAT is not specified, we write * the string as a non-NULL-terminated string (note that it can't be * unpacked easily then). * * r is a byte array of NEXT bytes. NEXT is the next argument and is * an integer. REPEAT is repeat. (r is from "raw") * * R is a byte array of REPEAT bytes. REPEAT must be specified. * * p is a Pascal string. The string passed is a NULL-termiated * string of less than 256 character. The string writen is a * non-NULL-terminated string with a byte before the string storing * the string length. REPEAT is repeat. * * Mnemonics: (B)yte, s(H)ort, (I)nteger, (F)loat, (D)ouble, (V)oid * pointer, (S)tring, (R)aw * * pack was mostly inspired by Python's pack, with some awareness of * Perl's pack. We don't do Python 0-repeat-is-alignment. Submit a * patch if you really want it. * * Returns: bytes packed; -1 if error. * **/gintgnet_pack (const gchar* format, gchar* buffer, const guint len, ...){ va_list args; gint rv; va_start (args, len); rv = gnet_vpack (format, buffer, len, args); va_end (args); return rv;}/** * gnet_pack_strdup * @format: Pack format (see gnet_pack) * @buffer: Pointer to buffer to allocate and pack to * @Varargs: Variables to pack from * * Packs the arguments into an allocated buffer. Caller is * responsible for deallocating the buffer. * * Returns: bytes packed; -1 if error. * **/gintgnet_pack_strdup (const gchar* format, gchar** buffer, ...){ va_list args; gint size; gint rv; g_return_val_if_fail (format, -1); g_return_val_if_fail (buffer, -1); /* Get size */ va_start (args, buffer); size = gnet_vcalcsize (format, args); va_end (args); g_return_val_if_fail (size >= 0, -1); if (size == 0) { *buffer = NULL; return 0; } *buffer = g_new (gchar, size); /* Pack */ va_start (args, buffer); rv = gnet_vpack (format, *buffer, size, args); va_end (args); return rv;}/* **************************************** *//** * gnet_calcsize: * @format: Pack format * @Varargs: Variables * * Calculate the size of the buffer needed to pack the given format. * All arguments should be passed. * * Returns: number of bytes required to pack; -1 if error. * **/gintgnet_calcsize (const gchar* format, ...){ va_list args; gint size; va_start (args, format); size = gnet_vcalcsize (format, args); va_end (args); return size;}/** * gnet_vcalcsize: * @format: Pack format * @args: var args * * Var arg interface to gnet_calcsize(). Size gnet_calcsize() for * additional information. * * Returns: number of bytes required to pack; -1 if error. * **/gintgnet_vcalcsize (const gchar* format, va_list args){ guint n = 0; gchar* p = (gchar*) format; gint mult = 0; gint sizemode = 0; /* 1 = little, 2 = big */ if (!format) return 0; switch (*p) { case '@': ++p; break; case '<': sizemode = 1; ++p; break; case '>': case '!': sizemode = 2; ++p; break; } for (; *p; ++p) { switch (*p) { case 'x': { n += mult?mult:1; mult = 0; break; } case 'b': { SIZE(gint8, int, gint8); break; } case 'B': { SIZE(guint8, unsigned int, guint8); break; } case 'h': { SIZE(short, int, gint16); break; } case 'H': { SIZE(unsigned short, unsigned int, guint16); break; } case 'i': { SIZE(int, int, gint32); break; } case 'I': { SIZE(unsigned int, unsigned int, guint32); break; } case 'l': { SIZE(long, int, gint32); break; } case 'L': { SIZE(unsigned long, unsigned int, guint32); break; } case 'f': { SIZE(float, double, float); break; } case 'd': { SIZE(double, double, double); break; } case 'v': { SIZE(void*, void*, void*); break; } case 's': { for (mult=(mult?mult:1); mult; --mult) { char* s; s = va_arg (args, char*); g_return_val_if_fail (s, -1); n += strlen(s) + 1; } mult = 0; break; } case 'S': { if (mult != 0) n += mult; else { char* s; s = va_arg (args, char*); n += strlen(s); } mult = 0; break; } case 'r': { for (mult=(mult?mult:1); mult; --mult) { char* s; int ln; s = va_arg (args, char*); g_return_val_if_fail (s, -1); ln = va_arg (args, int); n += ln; } mult = 0; break; } case 'R': { char* s; s = va_arg (args, char*); g_return_val_if_fail (s, -1); g_return_val_if_fail (mult, -1); n += mult; mult = 0; break; } case 'p': { for (mult=(mult?mult:1); mult; --mult) { char* s; int slen; s = va_arg (args, char*); g_return_val_if_fail (s, -1); slen = strlen(s); n += slen + 1; } mult = 0; break; } case '0':case '1':case '2':case '3':case '4': case '5':case '6':case '7':case '8':case '9': { mult *= 10; mult += (*p - '0'); break; } case ' ':case '\t':case '\n': break; default: g_return_val_if_fail (FALSE, -1); } } return n;}/** * gnet_vpack: * @format: Pack format (see gnet_pack) * @buffer: Buffer to pack to * @len: Length of buffer * @args: var args * * Var arg interface to gnet_pack(). See gnet_pack() for format * information. * * Returns: bytes packed; -1 if error. * **/gintgnet_vpack (const gchar* format, gchar* buffer, const guint len, va_list args){ guint n = 0; gchar* p = (gchar*) format; guint mult = 0; gint sizemode = 0; /* 1 = little, 2 = big */ g_return_val_if_fail (format, -1); g_return_val_if_fail (buffer, -1); g_return_val_if_fail (len, -1); switch (*p) { case '@': ++p; break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?