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 )