summaryrefslogtreecommitdiff
path: root/pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'pack.c')
-rw-r--r--pack.c256
1 files changed, 147 insertions, 109 deletions
diff --git a/pack.c b/pack.c
index a0f96aa262..ccb5143834 100644
--- a/pack.c
+++ b/pack.c
@@ -19,6 +19,36 @@
+(((x)>>24)&0xFF) \
+(((x)&0x0000FF00)<<8) \
+(((x)&0x00FF0000)>>8) )
+
+#ifdef DYNAMIC_ENDIAN
+#ifdef ntohs
+#undef ntohs
+#undef ntohl
+#undef htons
+#undef htonl
+#endif
+static int
+endian()
+{
+ static int init = 0;
+ static int endian_value;
+ char *p;
+
+ if (init) return endian_value;
+ init = 1;
+ p = (char*)&init;
+ return endian_value = p[0]?0:1;
+}
+
+#define ntohs(x) (endian()?(x):swaps(x))
+#define ntohl(x) (endian()?(x):swapl(x))
+#define htons(x) (endian()?(x):swaps(x))
+#define htonl(x) (endian()?(x):swapl(x))
+#define htovs(x) (endian()?swaps(x):(x))
+#define htovl(x) (endian()?swapl(x):(x))
+#define vtohs(x) (endian()?swaps(x):(x))
+#define vtohl(x) (endian()?swapl(x):(x))
+#else
#ifdef WORDS_BIGENDIAN
#ifndef ntohs
#define ntohs(x) (x)
@@ -42,13 +72,15 @@
#define vtohs(x) (x)
#define vtohl(x) (x)
#endif
+#endif
extern VALUE cString, cArray;
+#ifndef atof
double atof();
+#endif
static char *toofew = "too few arguments";
-int strtoul();
static void encodes();
static VALUE
@@ -58,11 +90,11 @@ pack_pack(ary, fmt)
{
static char *nul10 = "\0\0\0\0\0\0\0\0\0\0";
static char *spc10 = " ";
- char *p, *pend;
+ UCHAR *p, *pend;
VALUE res, from;
char type;
int items, len, idx;
- char *ptr;
+ UCHAR *ptr;
int plen;
Check_Type(fmt, T_STRING);
@@ -84,7 +116,7 @@ pack_pack(ary, fmt)
p++;
}
else if (isdigit(*p)) {
- len = strtoul(p, &p, 10);
+ len = strtoul(p, (char**)&p, 10);
}
else {
len = 1;
@@ -117,13 +149,10 @@ pack_pack(ary, fmt)
str_cat(res, ptr, plen);
len -= plen;
while (len >= 10) {
- if (type == 'A')
- str_cat(res, spc10, 10);
- else
- str_cat(res, nul10, 10);
+ str_cat(res, (type == 'A')?spc10:nul10, 10);
len -= 10;
}
- str_cat(res, nul10, len);
+ str_cat(res, (type == 'A')?spc10:nul10, len);
}
break;
@@ -290,7 +319,7 @@ pack_pack(ary, fmt)
case 'n':
while (len-- > 0) {
- short s;
+ unsigned short s;
from = NEXTFROM;
if (NIL_P(from)) s = 0;
@@ -304,7 +333,7 @@ pack_pack(ary, fmt)
case 'N':
while (len-- > 0) {
- long l;
+ unsigned long l;
from = NEXTFROM;
if (NIL_P(from)) l = 0;
@@ -316,6 +345,34 @@ pack_pack(ary, fmt)
}
break;
+ case 'v':
+ while (len-- > 0) {
+ unsigned short s;
+
+ from = NEXTFROM;
+ if (NIL_P(from)) s = 0;
+ else {
+ s = NUM2INT(from);
+ }
+ s = htovs(s);
+ str_cat(res, &s, sizeof(short));
+ }
+ break;
+
+ case 'V':
+ while (len-- > 0) {
+ unsigned long l;
+
+ from = NEXTFROM;
+ if (NIL_P(from)) l = 0;
+ else {
+ l = NUM2INT(from);
+ }
+ l = htovl(l);
+ str_cat(res, &l, sizeof(long));
+ }
+ break;
+
case 'f':
case 'F':
while (len-- > 0) {
@@ -356,34 +413,6 @@ pack_pack(ary, fmt)
}
break;
- case 'v':
- while (len-- > 0) {
- short s;
-
- from = NEXTFROM;
- if (NIL_P(from)) s = 0;
- else {
- s = NUM2INT(from);
- }
- s = htovs(s);
- str_cat(res, &s, sizeof(short));
- }
- break;
-
- case 'V':
- while (len-- > 0) {
- long l;
-
- from = NEXTFROM;
- if (NIL_P(from)) l = 0;
- else {
- l = NUM2INT(from);
- }
- l = htovl(l);
- str_cat(res, &l, sizeof(long));
- }
- break;
-
case 'x':
grow:
while (len >= 10) {
@@ -445,11 +474,11 @@ pack_pack(ary, fmt)
static void
encodes(str, s, len)
struct RString *str;
- char *s;
+ UCHAR *s;
int len;
{
char hunk[4];
- char *p, *pend;
+ UCHAR *p, *pend;
*hunk = len + ' ';
str_cat(str, hunk, 1);
@@ -477,8 +506,8 @@ pack_unpack(str, fmt)
struct RString *str, *fmt;
{
static char *hexdigits = "0123456789abcdef0123456789ABCDEFx";
- char *s, *send;
- char *p, *pend;
+ UCHAR *s, *send;
+ UCHAR *p, *pend;
VALUE ary;
char type;
int len;
@@ -498,7 +527,7 @@ pack_unpack(str, fmt)
p++;
}
else if (isdigit(*p)) {
- len = strtoul(p, &p, 10);
+ len = strtoul(p, (char**)&p, 10);
}
else {
len = (type != '@');
@@ -512,14 +541,19 @@ pack_unpack(str, fmt)
case 'A':
if (len > send - s) len = send - s;
{
- char *t = s + len - 1;
+ int end = len;
+ UCHAR *t = s + len - 1;
while (t >= s) {
if (*t != ' ' && *t != '\0') break;
t--;
len--;
}
+ ary_push(ary, str_new(s, len));
+ s += end;
}
+ break;
+
case 'a':
if (len > send - s) len = send - s;
ary_push(ary, str_new(s, len));
@@ -529,50 +563,51 @@ pack_unpack(str, fmt)
case 'b':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 8)
len = (send - s) * 8;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 7) bits >>= 1;
else bits = *s++;
*t++ = (bits & 1) ? '1' : '0';
}
- *t = '\0';
}
break;
case 'B':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 8)
len = (send - s) * 8;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 7) bits <<= 1;
else bits = *s++;
*t++ = (bits & 128) ? '1' : '0';
}
- *t = '\0';
}
break;
case 'h':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 2)
len = (send - s) * 2;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 1)
@@ -581,19 +616,19 @@ pack_unpack(str, fmt)
bits = *s++;
*t++ = hexdigits[bits & 15];
}
- *t = '\0';
}
break;
case 'H':
{
VALUE bitstr;
- char *t;
+ UCHAR *t;
int bits, i;
if (p[-1] == '*' || len > (send - s) * 2)
len = (send - s) * 2;
- ary_push(ary, bitstr = str_new(0, len + 1));
+ bits = 0;
+ ary_push(ary, bitstr = str_new(0, len));
t = RSTRING(bitstr)->ptr;
for (i=0; i<len; i++) {
if (i & 1)
@@ -602,7 +637,6 @@ pack_unpack(str, fmt)
bits = *s++;
*t++ = hexdigits[(bits >> 4) & 15];
}
- *t = '\0';
}
break;
@@ -611,9 +645,7 @@ pack_unpack(str, fmt)
len = send - s;
while (len-- > 0) {
int c = *s++;
-#ifdef __CHAR_UNSIGNED__
if (c > (char)127) c-=256;
-#endif
ary_push(ary, INT2FIX(c));
}
break;
@@ -622,7 +654,7 @@ pack_unpack(str, fmt)
if (len > send - s)
len = send - s;
while (len-- > 0) {
- unsigned char c = *s++;
+ UCHAR c = *s++;
ary_push(ary, INT2FIX(c));
}
break;
@@ -639,12 +671,12 @@ pack_unpack(str, fmt)
break;
case 'S':
- if (len >= (send - s) / sizeof(unsigned short))
- len = (send - s) / sizeof(unsigned short);
+ if (len >= (send - s) / sizeof(short))
+ len = (send - s) / sizeof(short);
while (len-- > 0) {
unsigned short tmp;
- memcpy(&tmp, s, sizeof(unsigned short));
- s += sizeof(unsigned short);
+ memcpy(&tmp, s, sizeof(short));
+ s += sizeof(short);
ary_push(ary, INT2FIX(tmp));
}
break;
@@ -661,12 +693,12 @@ pack_unpack(str, fmt)
break;
case 'I':
- if (len >= (send - s) / sizeof(unsigned int))
- len = (send - s) / sizeof(unsigned int);
+ if (len >= (send - s) / sizeof(int))
+ len = (send - s) / sizeof(int);
while (len-- > 0) {
unsigned int tmp;
- memcpy(&tmp, s, sizeof(unsigned int));
- s += sizeof(unsigned int);
+ memcpy(&tmp, s, sizeof(int));
+ s += sizeof(int);
ary_push(ary, int2inum(tmp));
}
break;
@@ -683,13 +715,13 @@ pack_unpack(str, fmt)
break;
case 'L':
- if (len >= (send - s) / sizeof(unsigned long))
- len = (send - s) / sizeof(unsigned long);
+ if (len >= (send - s) / sizeof(long))
+ len = (send - s) / sizeof(long);
while (len-- > 0) {
unsigned long tmp;
- memcpy(&tmp, s, sizeof(unsigned long));
- s += sizeof(unsigned long);
- ary_push(ary, int2inum(tmp));
+ memcpy(&tmp, s, sizeof(long));
+ s += sizeof(long);
+ ary_push(ary, uint2inum(tmp));
}
break;
@@ -697,11 +729,11 @@ pack_unpack(str, fmt)
if (len >= (send - s) / sizeof(short))
len = (send - s) / sizeof(short);
while (len-- > 0) {
- short tmp;
+ unsigned short tmp;
memcpy(&tmp, s, sizeof(short));
s += sizeof(short);
tmp = ntohs(tmp);
- ary_push(ary, int2inum(tmp));
+ ary_push(ary, uint2inum(tmp));
}
break;
@@ -709,16 +741,40 @@ pack_unpack(str, fmt)
if (len >= (send - s) / sizeof(long))
len = (send - s) / sizeof(long);
while (len-- > 0) {
- long tmp;
+ unsigned long tmp;
memcpy(&tmp, s, sizeof(long));
s += sizeof(long);
tmp = ntohl(tmp);
- ary_push(ary, int2inum(tmp));
+ ary_push(ary, uint2inum(tmp));
+ }
+ break;
+
+ case 'v':
+ if (len >= (send - s) / sizeof(short))
+ len = (send - s) / sizeof(short);
+ while (len-- > 0) {
+ unsigned short tmp;
+ memcpy(&tmp, s, sizeof(short));
+ s += sizeof(short);
+ tmp = vtohs(tmp);
+ ary_push(ary, uint2inum(tmp));
+ }
+ break;
+
+ case 'V':
+ if (len >= (send - s) / sizeof(long))
+ len = (send - s) / sizeof(long);
+ while (len-- > 0) {
+ unsigned long tmp;
+ memcpy(&tmp, s, sizeof(long));
+ s += sizeof(long);
+ tmp = vtohl(tmp);
+ ary_push(ary, uint2inum(tmp));
}
break;
- case 'F':
case 'f':
+ case 'F':
if (len >= (send - s) / sizeof(float))
len = (send - s) / sizeof(float);
while (len-- > 0) {
@@ -741,34 +797,10 @@ pack_unpack(str, fmt)
}
break;
- case 'v':
- if (len >= (send - s) / sizeof(short))
- len = (send - s) / sizeof(short);
- while (len-- > 0) {
- short tmp;
- memcpy(&tmp, s, sizeof(short));
- s += sizeof(short);
- tmp = vtohs(tmp);
- ary_push(ary, int2inum(tmp));
- }
- break;
-
- case 'V':
- if (len >= (send - s) / sizeof(long))
- len = (send - s) / sizeof(long);
- while (len-- > 0) {
- long tmp;
- memcpy(&tmp, s, sizeof(long));
- s += sizeof(long);
- tmp = vtohl(tmp);
- ary_push(ary, int2inum(tmp));
- }
- break;
-
case 'u':
{
VALUE str = str_new(0, (send - s)*3/4);
- char *ptr = RSTRING(str)->ptr;
+ UCHAR *ptr = RSTRING(str)->ptr;
int total = 0;
while (s < send && *s > ' ' && *s < 'a') {
@@ -778,8 +810,14 @@ pack_unpack(str, fmt)
hunk[3] = '\0';
len = (*s++ - ' ') & 077;
total += len;
+ if (total > RSTRING(str)->len) {
+ len -= total - RSTRING(str)->len;
+ total = RSTRING(str)->len;
+ }
while (len > 0) {
+ int mlen = len > 3 ? 3 : len;
+
if (s < send && *s >= ' ')
a = (*s++ - ' ') & 077;
else
@@ -799,13 +837,13 @@ pack_unpack(str, fmt)
hunk[0] = a << 2 | b >> 4;
hunk[1] = b << 4 | c >> 2;
hunk[2] = c << 6 | d;
- memcpy(ptr, hunk, len > 3 ? 3 : len);
- ptr += 3;
- len -= 3;
+ memcpy(ptr, hunk, mlen);
+ ptr += mlen;
+ len -= mlen;
}
- if (*s == '\n' || *s == '\r')
- s++;
- else if (s+1 == send || s[1] == '\n' || s[1] == '\r')
+ if (*s == '\r') s++;
+ if (*s == '\n') s++;
+ else if (s < send && (s+1 == send || s[1] == '\n'))
s += 2; /* possible checksum byte */
}
RSTRING(str)->len = total;