This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
As 2/3rds (or 3/4s) of the SV head structure is rewritten, it doesn't
[perl5.git] / ext / Encode / Encode.xs
index 6e24039..77d53af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- $Id: Encode.xs,v 1.45 2002/05/07 16:22:42 dankogai Exp dankogai $
+ $Id: Encode.xs,v 2.0 2004/05/16 20:55:15 dankogai Exp $
  */
 
 #define PERL_NO_GET_CONTEXT
@@ -59,7 +59,7 @@ call_failure(SV * routine, U8 * done, U8 * dest, U8 * orig)
 
 static SV *
 encode_method(pTHX_ encode_t * enc, encpage_t * dir, SV * src,
-             int check)
+             int check, STRLEN * offset, SV * term, int * retcode)
 {
     STRLEN slen;
     U8 *s = (U8 *) SvPV(src, slen);
@@ -72,20 +72,34 @@ encode_method(pTHX_ encode_t * enc, encpage_t * dir, SV * src,
     SV *dst = sv_2mortal(newSV(slen+1));
     U8 *d = (U8 *)SvPVX(dst);
     STRLEN dlen = SvLEN(dst)-1;
-    int code;
+    int code = 0;
+    STRLEN trmlen = 0;
+    U8 *trm = term ? (U8*) SvPV(term, trmlen) : NULL;
+
+    if (offset) {
+      s += *offset;
+      if (slen > *offset){ /* safeguard against slen overflow */
+         slen -= *offset;
+      }else{
+         slen = 0;
+      }
+      tlen = slen;
+    }
 
-    if (!slen){
+    if (slen == 0){
        SvCUR_set(dst, 0);
        SvPOK_only(dst);
        goto ENCODE_END;
     }
 
-    while( (code = do_encode(dir, s, &slen, d, dlen, &dlen, !check)) ) 
+    while( (code = do_encode(dir, s, &slen, d, dlen, &dlen, !check,
+                            trm, trmlen)) ) 
     {
        SvCUR_set(dst, dlen+ddone);
        SvPOK_only(dst);
        
-       if (code == ENCODE_FALLBACK || code == ENCODE_PARTIAL){
+       if (code == ENCODE_FALLBACK || code == ENCODE_PARTIAL ||
+           code == ENCODE_FOUND_TERM) {
            break;
        }
        switch (code) {
@@ -233,16 +247,166 @@ encode_method(pTHX_ encode_t * enc, encpage_t * dir, SV * src,
     }
 #endif
 
+    if (offset) 
+      *offset += sdone + slen;
+
  ENCODE_END:
     *SvEND(dst) = '\0';
+    if (retcode) *retcode = code;
     return dst;
 }
 
+MODULE = Encode                PACKAGE = Encode::utf8  PREFIX = Method_
+
+PROTOTYPES: DISABLE
+
+void
+Method_renew(obj)
+SV *   obj
+CODE:
+{
+    XSRETURN(1);
+}
+
+void
+Method_decode_xs(obj,src,check = 0)
+SV *   obj
+SV *   src
+int    check
+CODE:
+{
+    STRLEN slen;
+    U8 *s = (U8 *) SvPV(src, slen);
+    U8 *e = (U8 *) SvEND(src);
+    SV *dst = newSV(slen>0?slen:1); /* newSV() abhors 0 -- inaba */
+    SvPOK_only(dst);
+    SvCUR_set(dst,0);
+    if (SvUTF8(src)) {
+       s = utf8_to_bytes(s,&slen);
+       if (s) {
+           SvCUR_set(src,slen);
+           SvUTF8_off(src);
+           e = s+slen;
+       }
+       else {
+           croak("Cannot decode string with wide characters");
+       }
+    }
+    while (s < e) {
+       if (UTF8_IS_INVARIANT(*s) || UTF8_IS_START(*s)) {
+           U8 skip = UTF8SKIP(s);
+           if ((s + skip) > e) {
+               /* Partial character - done */
+               break;
+           }
+           else if (is_utf8_char(s)) {
+               /* Whole char is good */
+               sv_catpvn(dst,(char *)s,skip);
+               s += skip;
+               continue;
+           }
+           else {
+               /* starts ok but isn't "good" */
+           }
+       }
+       else {
+           /* Invalid start byte */
+       }
+       /* If we get here there is something wrong with alleged UTF-8 */
+       if (check & ENCODE_DIE_ON_ERR){
+           Perl_croak(aTHX_ ERR_DECODE_NOMAP, "utf8", (UV)*s);
+           XSRETURN(0);
+       }
+       if (check & ENCODE_WARN_ON_ERR){
+           Perl_warner(aTHX_ packWARN(WARN_UTF8),
+                       ERR_DECODE_NOMAP, "utf8", (UV)*s);
+        }
+       if (check & ENCODE_RETURN_ON_ERR) {
+               break;
+       }
+        if (check & (ENCODE_PERLQQ|ENCODE_HTMLCREF|ENCODE_XMLCREF)){
+           SV* perlqq = newSVpvf("\\x%02" UVXf, (UV)*s);
+           sv_catsv(dst, perlqq);
+           SvREFCNT_dec(perlqq);
+       } else {
+           sv_catpv(dst, FBCHAR_UTF8);
+       }
+       s++;
+    }
+    *SvEND(dst) = '\0';
+
+    /* Clear out translated part of source unless asked not to */
+    if (check && !(check & ENCODE_LEAVE_SRC)){
+       slen = e-s;
+       if (slen) {
+           sv_setpvn(src, (char*)s, slen);
+       }
+       SvCUR_set(src, slen);
+    }
+    SvUTF8_on(dst);
+    ST(0) = sv_2mortal(dst);
+    XSRETURN(1);
+}
+
+void
+Method_encode_xs(obj,src,check = 0)
+SV *   obj
+SV *   src
+int    check
+CODE:
+{
+    STRLEN slen;
+    U8 *s = (U8 *) SvPV(src, slen);
+    U8 *e = (U8 *) SvEND(src);
+    SV *dst = newSV(slen>0?slen:1); /* newSV() abhors 0 -- inaba */
+    if (SvUTF8(src)) {
+        /* Already encoded - trust it and just copy the octets */
+       sv_setpvn(dst,(char *)s,(e-s));
+       s = e;
+    }
+    else {
+       /* Native bytes - can always encode */
+       U8 *d = (U8 *) SvGROW(dst, 2*slen+1); /* +1 or assertion will botch */
+       while (s < e) {
+           UV uv = NATIVE_TO_UNI((UV) *s++);
+            if (UNI_IS_INVARIANT(uv))
+               *d++ = (U8)UTF_TO_NATIVE(uv);
+            else {
+               *d++ = (U8)UTF8_EIGHT_BIT_HI(uv);
+                *d++ = (U8)UTF8_EIGHT_BIT_LO(uv);
+            }
+       }
+        SvCUR_set(dst, d- (U8 *)SvPVX(dst));
+       *SvEND(dst) = '\0';
+    }
+
+    /* Clear out translated part of source unless asked not to */
+    if (check && !(check & ENCODE_LEAVE_SRC)){
+       slen = e-s;
+       if (slen) {
+           sv_setpvn(src, (char*)s, slen);
+       }
+       SvCUR_set(src, slen);
+    }
+    SvPOK_only(dst);
+    SvUTF8_off(dst);
+    ST(0) = sv_2mortal(dst);
+    XSRETURN(1);
+}
+
 MODULE = Encode                PACKAGE = Encode::XS    PREFIX = Method_
 
 PROTOTYPES: ENABLE
 
 void
+Method_renew(obj)
+SV *   obj
+CODE:
+{
+    XSRETURN(1);
+}
+
+void
 Method_name(obj)
 SV *   obj
 CODE:
@@ -253,6 +417,33 @@ CODE:
 }
 
 void
+Method_cat_decode(obj, dst, src, off, term, check = 0)
+SV *   obj
+SV *   dst
+SV *   src
+SV *   off
+SV *   term
+int    check
+CODE:
+{
+    encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
+    STRLEN offset = (STRLEN)SvIV(off);
+    int code = 0;
+    if (SvUTF8(src)) {
+       sv_utf8_downgrade(src, FALSE);
+    }
+    sv_catsv(dst, encode_method(aTHX_ enc, enc->t_utf8, src, check,
+                               &offset, term, &code));
+    SvIVX(off) = (IV)offset;
+    if (code == ENCODE_FOUND_TERM) {
+       ST(0) = &PL_sv_yes;
+    }else{
+       ST(0) = &PL_sv_no;
+    }
+    XSRETURN(1);
+}
+
+void
 Method_decode(obj,src,check = 0)
 SV *   obj
 SV *   src
@@ -260,7 +451,11 @@ int        check
 CODE:
 {
     encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
-    ST(0) = encode_method(aTHX_ enc, enc->t_utf8, src, check);
+    if (SvUTF8(src)) {
+       sv_utf8_downgrade(src, FALSE);
+    }
+    ST(0) = encode_method(aTHX_ enc, enc->t_utf8, src, check,
+                         NULL, Nullsv, NULL);
     SvUTF8_on(ST(0));
     XSRETURN(1);
 }
@@ -274,7 +469,8 @@ CODE:
 {
     encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
     sv_utf8_upgrade(src);
-    ST(0) = encode_method(aTHX_ enc, enc->f_utf8, src, check);
+    ST(0) = encode_method(aTHX_ enc, enc->f_utf8, src, check,
+                         NULL, Nullsv, NULL);
     XSRETURN(1);
 }