1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#define NEED_newSVpvn_flags_GLOBAL
#include "ppport.h"
#include <stdint.h>
#include "define.h"
#include "type.h"
/* Int */
int32_t unpack_int(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos)
{
if (UNLIKELY(len - *pos < 4))
croak("unpack_int: input too short. Data corrupted?");
int32_t result = (int32_t)ntohl(*(uint32_t*)(input+*pos));
*pos += 4;
return result;
}
STRLEN pack_int(pTHX_ SV *dest, int32_t number)
{
union {
int32_t number;
unsigned char bytes[4];
} int_or_bytes;
int_or_bytes.number = htonl(number);
sv_catpvn(dest, (char*)int_or_bytes.bytes, 4);
return SvCUR(dest)-4;
}
void set_packed_int(pTHX_ SV *dest, STRLEN pos, int32_t number)
{
STRLEN len;
char *ptr;
union {
int32_t number;
unsigned char bytes[4];
} int_or_bytes;
int_or_bytes.number = htonl(number);
ptr = SvPV(dest, len);
assert(pos <= len-4);
memcpy(ptr+pos, int_or_bytes.bytes, 4);
}
/* Short */
int unpack_short_nocroak(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos, uint16_t *out)
{
if (UNLIKELY(len - *pos < 2))
return -1;
*out = ntohs(*(uint16_t*)(input+*pos));
*pos += 2;
return 0;
}
uint16_t unpack_short(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos)
{
uint16_t out;
if (UNLIKELY(unpack_short_nocroak(aTHX_ input, len, pos, &out) != 0))
croak("unpack_short: invalid input");
return out;
}
void pack_short(pTHX_ SV *dest, uint16_t number)
{
union {
uint16_t number;
unsigned char bytes[2];
} short_or_bytes;
short_or_bytes.number = htons(number);
sv_catpvn(dest, (char*)short_or_bytes.bytes, 2);
}
/* Bytes */
int unpack_bytes(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos, unsigned char **output, STRLEN *outlen)
{
int32_t bytes_length = unpack_int(aTHX_ input, len, pos);
if (bytes_length < 0) {
return 1;
}
if (UNLIKELY(len - *pos < bytes_length))
croak("unpack_bytes: input too short. Data corrupted?");
*output = input + *pos;
*outlen = bytes_length;
*pos += bytes_length;
return 0;
}
SV *unpack_bytes_sv(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos)
{
unsigned char *bytes;
STRLEN bytes_len;
if (unpack_bytes(aTHX_ input, len, pos, &bytes, &bytes_len) == 0) {
return newSVpvn((char*)bytes, bytes_len);
} else {
return &PL_sv_undef;
}
}
/* String */
int unpack_string_nocroak(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos, char **output, STRLEN *outlen)
{
uint16_t string_length = unpack_short(aTHX_ input, len, pos);
if (UNLIKELY(len - *pos < string_length))
return -1;
*output = (char*)(input + *pos);
*outlen = string_length;
*pos += string_length;
return 0;
}
void unpack_string(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos, char **output, STRLEN *outlen)
{
if (UNLIKELY(unpack_string_nocroak(aTHX_ input, len, pos, output, outlen)) != 0)
croak("unpack_string: input invalid");
}
SV *unpack_string_sv(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos)
{
char *string;
STRLEN str_len;
unpack_string(aTHX_ input, len, pos, &string, &str_len);
return newSVpvn_utf8(string, str_len, 1);
}
SV *unpack_string_sv_hash(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos, U32 *hashout)
{
char *string;
STRLEN str_len;
unpack_string(aTHX_ input, len, pos, &string, &str_len);
PERL_HASH((*hashout), string, str_len);
return newSVpvn_utf8(string, str_len, 1);
}
|