Crypt-SecretBuffer
view release on metacpan or search on metacpan
secret_buffer_parse.c view on Meta::CPAN
secret_buffer *sb;
secret_buffer_span *span;
/* Is the sv a Span object? */
if ((span= secret_buffer_span_from_magic(sv, 0)) && SvTYPE(SvRV(sv)) == SVt_PVHV) {
SV **sb_sv= hv_fetchs((HV*)SvRV(sv), "buf", 1);
sb= secret_buffer_from_magic(*sb_sv, SECRET_BUFFER_MAGIC_OR_DIE);
return secret_buffer_parse_init(parse, sb, span->pos, span->lim, span->encoding);
}
/* Is the sv a SecretBuffer? */
else if ((sb= secret_buffer_from_magic(sv, 0))) {
return secret_buffer_parse_init(parse, sb, 0, sb->len, SECRET_BUFFER_ENCODING_ISO8859_1);
}
/* It needs to at least be defined */
else if (SvOK(sv)) {
STRLEN len;
char *buf= SvPV(sv, len);
Zero(parse, 1, secret_buffer_parse);
parse->pos= (U8*) buf;
parse->lim= (U8*) buf + len;
parse->encoding= SvUTF8(sv)? SECRET_BUFFER_ENCODING_UTF8 : SECRET_BUFFER_ENCODING_ISO8859_1;
return true;
}
else {
Zero(parse, 1, secret_buffer_parse);
parse->error= "Not a Span, SecretBuffer, or defined scalar";
return false;
}
}
/* Scan for a pattern which may be a regex or literal string.
* Regexes are currently limited to a single charclass.
*/
bool secret_buffer_match(secret_buffer_parse *parse, SV *pattern, int flags) {
dTHX;
REGEXP *rx= (REGEXP*)SvRX(pattern);
secret_buffer_parse pat_parse;
/* Is the pattern a regexp-ref? */
if (rx) {
secret_buffer_charset *cset= secret_buffer_charset_from_regexpref(pattern);
return secret_buffer_match_charset(parse, cset, flags);
}
/* load up a parse struct with the pos, lim, and encoding */
if (!secret_buffer_parse_init_from_sv(&pat_parse, pattern))
croak("%s", pat_parse.error);
/* Remove edge case of zero-length pattern (always matches) */
if (pat_parse.pos >= pat_parse.lim) {
if ((flags & SECRET_BUFFER_MATCH_REVERSE))
parse->pos= parse->lim;
else
parse->lim= parse->pos;
return !(flags & SECRET_BUFFER_MATCH_NEGATE);
}
/* Remove edge case of zero-length subject (never matches) */
if (parse->pos >= parse->lim) {
return (flags & SECRET_BUFFER_MATCH_NEGATE);
}
/* Since unicode iteration of the pattern is a hassle and might happen lots of times,
* convert it to either plain bytes or array of U32 codepoints.
*/
if (pat_parse.encoding != SECRET_BUFFER_ENCODING_ISO8859_1) {
int dst_enc=
/* these can be transcoded to bytes */
(pat_parse.encoding == SECRET_BUFFER_ENCODING_ASCII
|| pat_parse.encoding == SECRET_BUFFER_ENCODING_HEX
|| pat_parse.encoding == SECRET_BUFFER_ENCODING_BASE64)
? SECRET_BUFFER_ENCODING_ISO8859_1
: SECRET_BUFFER_ENCODING_I32;
SSize_t dst_len= secret_buffer_sizeof_transcode(&pat_parse, dst_enc);
if (dst_len < 0)
croak("transcode of pattern failed: %s", pat_parse.error);
/* No need to transcode SECRET_BUFFER_ENCODING_ASCII, but the above size check
* verified it is clean 7-bit, which is the whole point of that encoding.
*/
if (pat_parse.encoding == SECRET_BUFFER_ENCODING_ASCII
/* Likewise, if SECRET_BUFFER_ENCODING_UTF8's I32 len is exactly 4x the number of
* original bytes, that means every byte became a character, which means every
* character could fit in a byte. */
|| (pat_parse.encoding == SECRET_BUFFER_ENCODING_UTF8
&& dst_len == (pat_parse.lim - pat_parse.pos) * 4)
) {
pat_parse.encoding= SECRET_BUFFER_ENCODING_ISO8859_1;
} else {
/* create a temporary secret buffer to hold the transcode */
secret_buffer *tmp= secret_buffer_new(0, NULL);
secret_buffer_parse pat_orig= pat_parse;
secret_buffer_set_len(tmp, dst_len);
if (!secret_buffer_parse_init(&pat_parse, tmp, 0, dst_len, dst_enc))
croak("transcode of pattern failed: %s", pat_parse.error);
/* Transcode the pattern */
if (!secret_buffer_transcode(&pat_orig, (secret_buffer_parse_rw*) &pat_parse))
croak("transcode of pattern failed: %s", pat_orig.error? pat_orig.error : pat_parse.error);
}
}
/* In some cases it would also be nice to transcode the subject first, but the
* final state of the parse struct carries information back to the caller and
* needs to refer to original positions of characters. */
/* Now dipatch to sb_parse_match_str_X */
if (pat_parse.encoding == SECRET_BUFFER_ENCODING_ISO8859_1) {
size_t pat_len= pat_parse.lim - pat_parse.pos;
return sb_parse_match_str_U8(parse, pat_parse.pos, pat_len, flags);
} else { /* must be _I32 encoding, from above */
size_t pat_len= (pat_parse.lim - pat_parse.pos) >> 2;
return sb_parse_match_str_I32(parse, (I32*) pat_parse.pos, pat_len, flags);
}
}
/* Scan for a pattern which is a set of characters */
bool secret_buffer_match_charset(secret_buffer_parse *parse, secret_buffer_charset *cset, int flags) {
if (parse->pos >= parse->lim) // empty range
return false;
// byte matching gets to use a more efficient algorithm
return parse->encoding == SECRET_BUFFER_ENCODING_ISO8859_1
? sb_parse_match_charset_bytes(parse, cset, flags)
: sb_parse_match_charset_codepoints(parse, cset, flags);
}
secret_buffer_parse.c view on Meta::CPAN
if (dst->pos + (shift < 16? 4 : 0) != dst->lim) {
dst->error= "miscalculated buffer length";
return false;
}
// write leftover accumulated bits
if (shift < 16) {
U8 *writable= (U8*) dst->pos;
if (dst->pos + 4 > dst->lim) {
dst->error= "miscalculated buffer length";
return false;
}
dst->pos += 4;
writable[0] = base64_alphabet[0x3F & (accum >> 18)];
writable[1] = base64_alphabet[0x3F & (accum >> 12)];
writable[2] = shift? '=' : base64_alphabet[0x3F & (accum >> 6)];
writable[3] = '=';
}
}
else {
while (src->pos < src->lim) {
int len, cp= sb_parse_next_codepoint(src);
if (cp < 0)
return false; // error is already set
len= sb_parse_encode_codepoint(dst, cp);
if (len < 0)
return false; // error is already set
}
if (dst->pos != dst->lim) {
dst->error= "miscalculated buffer length";
return false;
}
}
return true;
}
bool
secret_buffer_copy_to(secret_buffer_parse *src, SV *dst_sv, int encoding, bool append) {
dTHX;
secret_buffer_parse_rw dst;
secret_buffer *dst_sbuf= NULL;
SSize_t need_bytes;
bool dst_wide= false;
Zero(&dst, 1, secret_buffer_parse_rw);
// Encoding may be -1 to indicate the user didn't specify, in which case we use the
// same encoding as the source, unless the destination is a perl scalar (handled below)
dst.encoding= encoding >= 0? encoding : src->encoding;
if (sv_isobject(dst_sv)) {
// if object, must be a SecretBuffer
dst_sbuf= secret_buffer_from_magic(dst_sv, SECRET_BUFFER_MAGIC_OR_DIE);
}
else {
// Going to overwrite the scalar, or if its a scalar-ref, overwrite that.
if (SvROK(dst_sv) && !sv_isobject(dst_sv) && SvTYPE(SvRV(dst_sv)) <= SVt_PVMG)
dst_sv= SvRV(dst_sv);
// Refuse to overwrite any other kind of ref
if (SvTYPE(dst_sv) > SVt_PVMG || SvROK(dst_sv)) {
src->error= "Can only copy_to scalars or scalar-refs";
return false;
}
// If the source encoding is a type of unicode, and the destination encoding is not
// specified, then write wide characters (utf-8) to the perl scalar and flag it as utf8
if (encoding < 0 && SECRET_BUFFER_ENCODING_IS_UNICODE(src->encoding)) {
dst.encoding= SECRET_BUFFER_ENCODING_UTF8;
dst_wide= true;
}
}
// Determine how many bytes we need
need_bytes= secret_buffer_sizeof_transcode(src, dst.encoding);
if (need_bytes < 0)
return false;
// Prepare the buffers for that many bytes
if (dst_sbuf) {
// For destination SecretBuffer, set length to 0 unless appending, then
// ensure enough allocated space for need_bytes, then transcode and update
// the length in the block below.
if (!append)
secret_buffer_set_len(dst_sbuf, 0); /* clears secrets */
secret_buffer_alloc_at_least(dst_sbuf, dst_sbuf->len + need_bytes);
dst.pos= (U8*) dst_sbuf->data + dst_sbuf->len;
dst.lim= dst.pos + need_bytes;
}
else {
// For destination SV, set length to 0 unless appending, then force it to
// be bytes or utf-8, then grow it to ensure room for additional `need_bytes`.
U8* ptr;
STRLEN len;
// If overwriting, set the length to 0 before forcing to bytes or utf8
if (!append)
sv_setpvn(dst_sv, "", 0);
// force it to the type required
if (dst_wide) SvPVutf8(dst_sv, len);
else SvPVbyte(dst_sv, len);
// grow it to the required length, for writing
sv_grow(dst_sv, (append? len : 0) + need_bytes + 1);
ptr= (U8*) SvPVX_mutable(dst_sv) + len;
// don't forget the NUL terminator
ptr[need_bytes]= '\0';
dst.pos= ptr;
dst.lim= dst.pos + need_bytes;
}
if (!secret_buffer_transcode(src, &dst)) {
if (!src->error) src->error= dst.error;
return false;
}
/* update the lengths */
if (dst_sbuf) {
dst_sbuf->len += need_bytes;
}
else {
SvCUR_set(dst_sv, SvCUR(dst_sv) + need_bytes);
SvSETMAGIC(dst_sv);
}
return true;
}
/* Append DER length octets (ASN.1 Length field, definite form only).
*
* DER rules:
* - If len <= 127: single byte [0x00..0x7F]
* - Else: first byte is 0x80 | N, where N is # of following length bytes (big-endian),
( run in 0.970 second using v1.01-cache-2.11-cpan-e1769b4cff6 )