143003dfeSmillert #define PERL_NO_GET_CONTEXT 243003dfeSmillert #include "EXTERN.h" 343003dfeSmillert #include "perl.h" 443003dfeSmillert #include "XSUB.h" 543003dfeSmillert #define U8 U8 643003dfeSmillert 743003dfeSmillert #define OUR_DEFAULT_FB "Encode::PERLQQ" 8eac174f2Safresh1 #define OUR_STOP_AT_PARTIAL "Encode::STOP_AT_PARTIAL" 9eac174f2Safresh1 #define OUR_LEAVE_SRC "Encode::LEAVE_SRC" 10eac174f2Safresh1 11eac174f2Safresh1 /* This will be set during BOOT */ 12eac174f2Safresh1 static unsigned int encode_stop_at_partial = 0; 13eac174f2Safresh1 static unsigned int encode_leave_src = 0; 1443003dfeSmillert 15e5157e49Safresh1 #if defined(USE_PERLIO) 1643003dfeSmillert 1743003dfeSmillert /* Define an encoding "layer" in the perliol.h sense. 1843003dfeSmillert 1943003dfeSmillert The layer defined here "inherits" in an object-oriented sense from 2043003dfeSmillert the "perlio" layer with its PerlIOBuf_* "methods". The 2143003dfeSmillert implementation is particularly efficient as until Encode settles 2243003dfeSmillert down there is no point in tryint to tune it. 2343003dfeSmillert 2443003dfeSmillert The layer works by overloading the "fill" and "flush" methods. 2543003dfeSmillert 2643003dfeSmillert "fill" calls "SUPER::fill" in perl terms, then calls the encode OO 2743003dfeSmillert perl API to convert the encoded data to UTF-8 form, then copies it 2843003dfeSmillert back to the buffer. The "base class's" read methods then see the 2943003dfeSmillert UTF-8 data. 3043003dfeSmillert 3143003dfeSmillert "flush" transforms the UTF-8 data deposited by the "base class's 3243003dfeSmillert write method in the buffer back into the encoded form using the 3343003dfeSmillert encode OO perl API, then copies data back into the buffer and calls 3443003dfeSmillert "SUPER::flush. 3543003dfeSmillert 3643003dfeSmillert Note that "flush" is _also_ called for read mode - we still do the 3743003dfeSmillert (back)-translate so that the base class's "flush" sees the 3843003dfeSmillert correct number of encoded chars for positioning the seek 3943003dfeSmillert pointer. (This double translation is the worst performance issue - 4043003dfeSmillert particularly with all-perl encode engine.) 4143003dfeSmillert 4243003dfeSmillert */ 4343003dfeSmillert 4443003dfeSmillert #include "perliol.h" 4543003dfeSmillert 4643003dfeSmillert typedef struct { 4743003dfeSmillert PerlIOBuf base; /* PerlIOBuf stuff */ 4843003dfeSmillert SV *bufsv; /* buffer seen by layers above */ 4943003dfeSmillert SV *dataSV; /* data we have read from layer below */ 5043003dfeSmillert SV *enc; /* the encoding object */ 5143003dfeSmillert SV *chk; /* CHECK in Encode methods */ 5243003dfeSmillert int flags; /* Flags currently just needs lines */ 5343003dfeSmillert int inEncodeCall; /* trap recursive encode calls */ 5443003dfeSmillert } PerlIOEncode; 5543003dfeSmillert 5643003dfeSmillert #define NEEDS_LINES 1 5743003dfeSmillert 58b8851fccSafresh1 static const MGVTBL PerlIOEncode_tag = { 0, 0, 0, 0, 0, 0, 0, 0 }; 59b8851fccSafresh1 60b8851fccSafresh1 static SV * 6143003dfeSmillert PerlIOEncode_getarg(pTHX_ PerlIO * f, CLONE_PARAMS * param, int flags) 6243003dfeSmillert { 6343003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 64b8851fccSafresh1 SV *sv; 6548950c12Ssthen PERL_UNUSED_ARG(flags); 66b8851fccSafresh1 /* During cloning, return an undef token object so that _pushed() knows 67b8851fccSafresh1 * that it should not call methods and wait for _dup() to actually dup the 68b8851fccSafresh1 * encoding object. */ 69b8851fccSafresh1 if (param) { 70b8851fccSafresh1 sv = newSV(0); 71b8851fccSafresh1 sv_magicext(sv, NULL, PERL_MAGIC_ext, &PerlIOEncode_tag, 0, 0); 72b8851fccSafresh1 return sv; 73b8851fccSafresh1 } 74b8851fccSafresh1 sv = &PL_sv_undef; 7543003dfeSmillert if (e->enc) { 7643003dfeSmillert dSP; 7743003dfeSmillert /* Not 100% sure stack swap is right thing to do during dup ... */ 7843003dfeSmillert PUSHSTACKi(PERLSI_MAGIC); 7943003dfeSmillert ENTER; 8043003dfeSmillert SAVETMPS; 8143003dfeSmillert PUSHMARK(sp); 8243003dfeSmillert XPUSHs(e->enc); 8343003dfeSmillert PUTBACK; 8443003dfeSmillert if (call_method("name", G_SCALAR) == 1) { 8543003dfeSmillert SPAGAIN; 8643003dfeSmillert sv = newSVsv(POPs); 8743003dfeSmillert PUTBACK; 8843003dfeSmillert } 8943003dfeSmillert FREETMPS; 9043003dfeSmillert LEAVE; 9143003dfeSmillert POPSTACK; 9243003dfeSmillert } 9343003dfeSmillert return sv; 9443003dfeSmillert } 9543003dfeSmillert 96b8851fccSafresh1 static IV 9743003dfeSmillert PerlIOEncode_pushed(pTHX_ PerlIO * f, const char *mode, SV * arg, PerlIO_funcs *tab) 9843003dfeSmillert { 9943003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 10043003dfeSmillert dSP; 10143003dfeSmillert IV code = PerlIOBuf_pushed(aTHX_ f, mode, Nullsv,tab); 10243003dfeSmillert SV *result = Nullsv; 10343003dfeSmillert 104b8851fccSafresh1 if (SvTYPE(arg) >= SVt_PVMG 105b8851fccSafresh1 && mg_findext(arg, PERL_MAGIC_ext, &PerlIOEncode_tag)) { 106b8851fccSafresh1 e->enc = NULL; 107b8851fccSafresh1 e->chk = NULL; 108b8851fccSafresh1 e->inEncodeCall = 0; 109b8851fccSafresh1 return code; 110b8851fccSafresh1 } 111b8851fccSafresh1 11243003dfeSmillert PUSHSTACKi(PERLSI_MAGIC); 11343003dfeSmillert ENTER; 11443003dfeSmillert SAVETMPS; 11543003dfeSmillert 11643003dfeSmillert PUSHMARK(sp); 11743003dfeSmillert XPUSHs(arg); 11843003dfeSmillert PUTBACK; 11943003dfeSmillert if (call_pv("Encode::find_encoding", G_SCALAR) != 1) { 12043003dfeSmillert /* should never happen */ 12143003dfeSmillert Perl_die(aTHX_ "Encode::find_encoding did not return a value"); 12243003dfeSmillert return -1; 12343003dfeSmillert } 12443003dfeSmillert SPAGAIN; 12543003dfeSmillert result = POPs; 12643003dfeSmillert PUTBACK; 12743003dfeSmillert 12843003dfeSmillert if (!SvROK(result) || !SvOBJECT(SvRV(result))) { 12943003dfeSmillert e->enc = Nullsv; 1300dc2eaceSmillert if (ckWARN_d(WARN_IO)) 13143003dfeSmillert Perl_warner(aTHX_ packWARN(WARN_IO), "Cannot find encoding \"%" SVf "\"", 13243003dfeSmillert arg); 13343003dfeSmillert errno = EINVAL; 13443003dfeSmillert code = -1; 13543003dfeSmillert } 13643003dfeSmillert else { 13743003dfeSmillert 13843003dfeSmillert /* $enc->renew */ 13943003dfeSmillert PUSHMARK(sp); 14043003dfeSmillert XPUSHs(result); 14143003dfeSmillert PUTBACK; 14243003dfeSmillert if (call_method("renew",G_SCALAR|G_EVAL) != 1 || SvTRUE(ERRSV)) { 1430dc2eaceSmillert if (ckWARN_d(WARN_IO)) 14443003dfeSmillert Perl_warner(aTHX_ packWARN(WARN_IO), "\"%" SVf "\" does not support renew method", 14543003dfeSmillert arg); 14643003dfeSmillert } 14743003dfeSmillert else { 14843003dfeSmillert SPAGAIN; 14943003dfeSmillert result = POPs; 15043003dfeSmillert PUTBACK; 15143003dfeSmillert } 15243003dfeSmillert e->enc = newSVsv(result); 15343003dfeSmillert PUSHMARK(sp); 15443003dfeSmillert XPUSHs(e->enc); 15543003dfeSmillert PUTBACK; 15643003dfeSmillert if (call_method("needs_lines",G_SCALAR|G_EVAL) != 1 || SvTRUE(ERRSV)) { 1570dc2eaceSmillert if (ckWARN_d(WARN_IO)) 15843003dfeSmillert Perl_warner(aTHX_ packWARN(WARN_IO), "\"%" SVf "\" does not support needs_lines", 15943003dfeSmillert arg); 16043003dfeSmillert } 16143003dfeSmillert else { 16243003dfeSmillert SPAGAIN; 16343003dfeSmillert result = POPs; 16443003dfeSmillert PUTBACK; 16543003dfeSmillert if (SvTRUE(result)) { 16643003dfeSmillert e->flags |= NEEDS_LINES; 16743003dfeSmillert } 16843003dfeSmillert } 16943003dfeSmillert PerlIOBase(f)->flags |= PERLIO_F_UTF8; 17043003dfeSmillert } 17143003dfeSmillert 17243003dfeSmillert e->chk = newSVsv(get_sv("PerlIO::encoding::fallback", 0)); 173eac174f2Safresh1 if (SvROK(e->chk)) 174eac174f2Safresh1 Perl_croak(aTHX_ "PerlIO::encoding::fallback must be an integer"); 175eac174f2Safresh1 SvUV_set(e->chk, ((SvUV(e->chk) & ~encode_leave_src) | encode_stop_at_partial)); 17643003dfeSmillert e->inEncodeCall = 0; 17743003dfeSmillert 17843003dfeSmillert FREETMPS; 17943003dfeSmillert LEAVE; 18043003dfeSmillert POPSTACK; 18143003dfeSmillert return code; 18243003dfeSmillert } 18343003dfeSmillert 184b8851fccSafresh1 static IV 18543003dfeSmillert PerlIOEncode_popped(pTHX_ PerlIO * f) 18643003dfeSmillert { 18743003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 18843003dfeSmillert if (e->enc) { 18943003dfeSmillert SvREFCNT_dec(e->enc); 19043003dfeSmillert e->enc = Nullsv; 19143003dfeSmillert } 19243003dfeSmillert if (e->bufsv) { 19343003dfeSmillert SvREFCNT_dec(e->bufsv); 19443003dfeSmillert e->bufsv = Nullsv; 19543003dfeSmillert } 19643003dfeSmillert if (e->dataSV) { 19743003dfeSmillert SvREFCNT_dec(e->dataSV); 19843003dfeSmillert e->dataSV = Nullsv; 19943003dfeSmillert } 20043003dfeSmillert if (e->chk) { 20143003dfeSmillert SvREFCNT_dec(e->chk); 20243003dfeSmillert e->chk = Nullsv; 20343003dfeSmillert } 20443003dfeSmillert return 0; 20543003dfeSmillert } 20643003dfeSmillert 207b8851fccSafresh1 static STDCHAR * 20843003dfeSmillert PerlIOEncode_get_base(pTHX_ PerlIO * f) 20943003dfeSmillert { 21043003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 21143003dfeSmillert if (!e->base.bufsiz) 21243003dfeSmillert e->base.bufsiz = 1024; 21343003dfeSmillert if (!e->bufsv) { 21443003dfeSmillert e->bufsv = newSV(e->base.bufsiz); 2159f11ffb7Safresh1 SvPVCLEAR(e->bufsv); 21643003dfeSmillert } 21743003dfeSmillert e->base.buf = (STDCHAR *) SvPVX(e->bufsv); 21843003dfeSmillert if (!e->base.ptr) 21943003dfeSmillert e->base.ptr = e->base.buf; 22043003dfeSmillert if (!e->base.end) 22143003dfeSmillert e->base.end = e->base.buf; 22243003dfeSmillert if (e->base.ptr < e->base.buf 22343003dfeSmillert || e->base.ptr > e->base.buf + SvLEN(e->bufsv)) { 22443003dfeSmillert Perl_warn(aTHX_ " ptr %p(%p)%p", e->base.buf, e->base.ptr, 22543003dfeSmillert e->base.buf + SvLEN(e->bufsv)); 22643003dfeSmillert abort(); 22743003dfeSmillert } 22843003dfeSmillert if (SvLEN(e->bufsv) < e->base.bufsiz) { 22943003dfeSmillert SSize_t poff = e->base.ptr - e->base.buf; 23043003dfeSmillert SSize_t eoff = e->base.end - e->base.buf; 23143003dfeSmillert e->base.buf = (STDCHAR *) SvGROW(e->bufsv, e->base.bufsiz); 23243003dfeSmillert e->base.ptr = e->base.buf + poff; 23343003dfeSmillert e->base.end = e->base.buf + eoff; 23443003dfeSmillert } 23543003dfeSmillert if (e->base.ptr < e->base.buf 23643003dfeSmillert || e->base.ptr > e->base.buf + SvLEN(e->bufsv)) { 23743003dfeSmillert Perl_warn(aTHX_ " ptr %p(%p)%p", e->base.buf, e->base.ptr, 23843003dfeSmillert e->base.buf + SvLEN(e->bufsv)); 23943003dfeSmillert abort(); 24043003dfeSmillert } 24143003dfeSmillert return e->base.buf; 24243003dfeSmillert } 24343003dfeSmillert 244b8851fccSafresh1 static IV 24543003dfeSmillert PerlIOEncode_fill(pTHX_ PerlIO * f) 24643003dfeSmillert { 24743003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 24843003dfeSmillert dSP; 24943003dfeSmillert IV code = 0; 25043003dfeSmillert PerlIO *n; 25143003dfeSmillert SSize_t avail; 25243003dfeSmillert 25343003dfeSmillert if (PerlIO_flush(f) != 0) 25443003dfeSmillert return -1; 25543003dfeSmillert n = PerlIONext(f); 25643003dfeSmillert if (!PerlIO_fast_gets(n)) { 25743003dfeSmillert /* Things get too messy if we don't have a buffer layer 25843003dfeSmillert push a :perlio to do the job */ 25943003dfeSmillert char mode[8]; 26043003dfeSmillert n = PerlIO_push(aTHX_ n, &PerlIO_perlio, PerlIO_modestr(f,mode), Nullsv); 26143003dfeSmillert if (!n) { 26243003dfeSmillert Perl_die(aTHX_ "panic: cannot push :perlio for %p",f); 26343003dfeSmillert } 26443003dfeSmillert } 26543003dfeSmillert PUSHSTACKi(PERLSI_MAGIC); 26643003dfeSmillert ENTER; 26743003dfeSmillert SAVETMPS; 26843003dfeSmillert retry: 26943003dfeSmillert avail = PerlIO_get_cnt(n); 27043003dfeSmillert if (avail <= 0) { 27143003dfeSmillert avail = PerlIO_fill(n); 27243003dfeSmillert if (avail == 0) { 27343003dfeSmillert avail = PerlIO_get_cnt(n); 27443003dfeSmillert } 27543003dfeSmillert else { 27643003dfeSmillert if (!PerlIO_error(n) && PerlIO_eof(n)) 27743003dfeSmillert avail = 0; 27843003dfeSmillert } 27943003dfeSmillert } 28043003dfeSmillert if (avail > 0 || (e->flags & NEEDS_LINES)) { 28143003dfeSmillert STDCHAR *ptr = PerlIO_get_ptr(n); 28243003dfeSmillert SSize_t use = (avail >= 0) ? avail : 0; 28343003dfeSmillert SV *uni; 28443003dfeSmillert char *s = NULL; 28543003dfeSmillert STRLEN len = 0; 28643003dfeSmillert e->base.ptr = e->base.end = (STDCHAR *) NULL; 28743003dfeSmillert (void) PerlIOEncode_get_base(aTHX_ f); 28843003dfeSmillert if (!e->dataSV) 289*3d61058aSafresh1 e->dataSV = newSV_type(SVt_PV); 290*3d61058aSafresh1 else if (SvTYPE(e->dataSV) < SVt_PV) { 29143003dfeSmillert sv_upgrade(e->dataSV,SVt_PV); 29243003dfeSmillert } 29343003dfeSmillert if (e->flags & NEEDS_LINES) { 29443003dfeSmillert /* Encoding needs whole lines (e.g. iso-2022-*) 29543003dfeSmillert search back from end of available data for 29643003dfeSmillert and line marker 29743003dfeSmillert */ 29843003dfeSmillert STDCHAR *nl = ptr+use-1; 29943003dfeSmillert while (nl >= ptr) { 30043003dfeSmillert if (*nl == '\n') { 30143003dfeSmillert break; 30243003dfeSmillert } 30343003dfeSmillert nl--; 30443003dfeSmillert } 30543003dfeSmillert if (nl >= ptr && *nl == '\n') { 30643003dfeSmillert /* found a line - take up to and including that */ 30743003dfeSmillert use = (nl+1)-ptr; 30843003dfeSmillert } 30943003dfeSmillert else if (avail > 0) { 31043003dfeSmillert /* No line, but not EOF - append avail to the pending data */ 31143003dfeSmillert sv_catpvn(e->dataSV, (char*)ptr, use); 31243003dfeSmillert PerlIO_set_ptrcnt(n, ptr+use, 0); 31343003dfeSmillert goto retry; 31443003dfeSmillert } 31543003dfeSmillert else if (!SvCUR(e->dataSV)) { 31643003dfeSmillert goto end_of_file; 31743003dfeSmillert } 31843003dfeSmillert } 3199f11ffb7Safresh1 if (!SvCUR(e->dataSV)) 3209f11ffb7Safresh1 SvPVCLEAR(e->dataSV); 32143003dfeSmillert if (use + SvCUR(e->dataSV) > e->base.bufsiz) { 32243003dfeSmillert if (e->flags & NEEDS_LINES) { 32343003dfeSmillert /* Have to grow buffer */ 32443003dfeSmillert e->base.bufsiz = use + SvCUR(e->dataSV); 32543003dfeSmillert PerlIOEncode_get_base(aTHX_ f); 32643003dfeSmillert } 32743003dfeSmillert else { 32843003dfeSmillert use = e->base.bufsiz - SvCUR(e->dataSV); 32943003dfeSmillert } 33043003dfeSmillert } 33143003dfeSmillert sv_catpvn(e->dataSV,(char*)ptr,use); 33243003dfeSmillert SvUTF8_off(e->dataSV); 33343003dfeSmillert PUSHMARK(sp); 33443003dfeSmillert XPUSHs(e->enc); 33543003dfeSmillert XPUSHs(e->dataSV); 33643003dfeSmillert XPUSHs(e->chk); 33743003dfeSmillert PUTBACK; 33843003dfeSmillert if (call_method("decode", G_SCALAR) != 1) { 33943003dfeSmillert Perl_die(aTHX_ "panic: decode did not return a value"); 34043003dfeSmillert } 34143003dfeSmillert SPAGAIN; 34243003dfeSmillert uni = POPs; 34343003dfeSmillert PUTBACK; 344e9ce3842Safresh1 /* No cows allowed. */ 345e9ce3842Safresh1 if (SvTHINKFIRST(e->dataSV)) SvPV_force_nolen(e->dataSV); 34643003dfeSmillert /* Now get translated string (forced to UTF-8) and use as buffer */ 34743003dfeSmillert if (SvPOK(uni)) { 34843003dfeSmillert s = SvPVutf8(uni, len); 34943003dfeSmillert #ifdef PARANOID_ENCODE_CHECKS 35043003dfeSmillert if (len && !is_utf8_string((U8*)s,len)) { 35143003dfeSmillert Perl_warn(aTHX_ "panic: decode did not return UTF-8 '%.*s'",(int) len,s); 35243003dfeSmillert } 35343003dfeSmillert #endif 35443003dfeSmillert } 35543003dfeSmillert if (len > 0) { 35643003dfeSmillert /* Got _something */ 35743003dfeSmillert /* if decode gave us back dataSV then data may vanish when 35843003dfeSmillert we do ptrcnt adjust - so take our copy now. 35943003dfeSmillert (The copy is a pain - need a put-it-here option for decode.) 36043003dfeSmillert */ 36143003dfeSmillert sv_setpvn(e->bufsv,s,len); 36243003dfeSmillert e->base.ptr = e->base.buf = (STDCHAR*)SvPVX(e->bufsv); 36343003dfeSmillert e->base.end = e->base.ptr + SvCUR(e->bufsv); 36443003dfeSmillert PerlIOBase(f)->flags |= PERLIO_F_RDBUF; 36543003dfeSmillert SvUTF8_on(e->bufsv); 36643003dfeSmillert 36743003dfeSmillert /* Adjust ptr/cnt not taking anything which 36843003dfeSmillert did not translate - not clear this is a win */ 36943003dfeSmillert /* compute amount we took */ 370e9ce3842Safresh1 if (!SvPOKp(e->dataSV)) (void)SvPV_force_nolen(e->dataSV); 37143003dfeSmillert use -= SvCUR(e->dataSV); 37243003dfeSmillert PerlIO_set_ptrcnt(n, ptr+use, (avail-use)); 37356d68f1eSafresh1 /* and as we did not take it, it isn't pending */ 37443003dfeSmillert SvCUR_set(e->dataSV,0); 37543003dfeSmillert } else { 37643003dfeSmillert /* Got nothing - assume partial character so we need some more */ 37743003dfeSmillert /* Make sure e->dataSV is a normal SV before re-filling as 37843003dfeSmillert buffer alias will change under us 37943003dfeSmillert */ 38043003dfeSmillert s = SvPV(e->dataSV,len); 38143003dfeSmillert sv_setpvn(e->dataSV,s,len); 38243003dfeSmillert PerlIO_set_ptrcnt(n, ptr+use, (avail-use)); 38343003dfeSmillert goto retry; 38443003dfeSmillert } 38543003dfeSmillert } 38643003dfeSmillert else { 38743003dfeSmillert end_of_file: 38843003dfeSmillert code = -1; 38943003dfeSmillert if (avail == 0) 39043003dfeSmillert PerlIOBase(f)->flags |= PERLIO_F_EOF; 39143003dfeSmillert else 392b8851fccSafresh1 { 39343003dfeSmillert PerlIOBase(f)->flags |= PERLIO_F_ERROR; 394b8851fccSafresh1 Perl_PerlIO_save_errno(aTHX_ f); 395b8851fccSafresh1 } 39643003dfeSmillert } 39743003dfeSmillert FREETMPS; 39843003dfeSmillert LEAVE; 39943003dfeSmillert POPSTACK; 40043003dfeSmillert return code; 40143003dfeSmillert } 40243003dfeSmillert 403b8851fccSafresh1 static IV 40443003dfeSmillert PerlIOEncode_flush(pTHX_ PerlIO * f) 40543003dfeSmillert { 40643003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 40743003dfeSmillert IV code = 0; 40843003dfeSmillert 40943003dfeSmillert if (e->bufsv) { 41043003dfeSmillert dSP; 41143003dfeSmillert SV *str; 41243003dfeSmillert char *s; 41343003dfeSmillert STRLEN len; 41443003dfeSmillert SSize_t count = 0; 41543003dfeSmillert if ((PerlIOBase(f)->flags & PERLIO_F_WRBUF) && (e->base.ptr > e->base.buf)) { 41643003dfeSmillert if (e->inEncodeCall) return 0; 41743003dfeSmillert /* Write case - encode the buffer and write() to layer below */ 41843003dfeSmillert PUSHSTACKi(PERLSI_MAGIC); 41943003dfeSmillert ENTER; 42043003dfeSmillert SAVETMPS; 42143003dfeSmillert PUSHMARK(sp); 42243003dfeSmillert XPUSHs(e->enc); 42343003dfeSmillert SvCUR_set(e->bufsv, e->base.ptr - e->base.buf); 42443003dfeSmillert SvUTF8_on(e->bufsv); 42543003dfeSmillert XPUSHs(e->bufsv); 42643003dfeSmillert XPUSHs(e->chk); 42743003dfeSmillert PUTBACK; 42843003dfeSmillert e->inEncodeCall = 1; 42943003dfeSmillert if (call_method("encode", G_SCALAR) != 1) { 43043003dfeSmillert e->inEncodeCall = 0; 43143003dfeSmillert Perl_die(aTHX_ "panic: encode did not return a value"); 43243003dfeSmillert } 43343003dfeSmillert e->inEncodeCall = 0; 43443003dfeSmillert SPAGAIN; 43543003dfeSmillert str = POPs; 43643003dfeSmillert PUTBACK; 43743003dfeSmillert s = SvPV(str, len); 43843003dfeSmillert count = PerlIO_write(PerlIONext(f),s,len); 43943003dfeSmillert if ((STRLEN)count != len) { 44043003dfeSmillert code = -1; 44143003dfeSmillert } 44243003dfeSmillert FREETMPS; 44343003dfeSmillert LEAVE; 44443003dfeSmillert POPSTACK; 44543003dfeSmillert if (PerlIO_flush(PerlIONext(f)) != 0) { 44643003dfeSmillert code = -1; 44743003dfeSmillert } 448e9ce3842Safresh1 if (!SvPOKp(e->bufsv) || SvTHINKFIRST(e->bufsv)) 449e9ce3842Safresh1 (void)SvPV_force_nolen(e->bufsv); 450e9ce3842Safresh1 if ((STDCHAR *)SvPVX(e->bufsv) != e->base.buf) { 451b8851fccSafresh1 e->base.ptr = (STDCHAR *)SvEND(e->bufsv); 452b8851fccSafresh1 e->base.end = (STDCHAR *)SvPVX(e->bufsv) + (e->base.end-e->base.buf); 453e9ce3842Safresh1 e->base.buf = (STDCHAR *)SvPVX(e->bufsv); 454e9ce3842Safresh1 } 455e9ce3842Safresh1 (void)PerlIOEncode_get_base(aTHX_ f); 45643003dfeSmillert if (SvCUR(e->bufsv)) { 45743003dfeSmillert /* Did not all translate */ 45843003dfeSmillert e->base.ptr = e->base.buf+SvCUR(e->bufsv); 45943003dfeSmillert return code; 46043003dfeSmillert } 46143003dfeSmillert } 46243003dfeSmillert else if ((PerlIOBase(f)->flags & PERLIO_F_RDBUF)) { 46343003dfeSmillert /* read case */ 46443003dfeSmillert /* if we have any untranslated stuff then unread that first */ 46543003dfeSmillert /* FIXME - unread is fragile is there a better way ? */ 46643003dfeSmillert if (e->dataSV && SvCUR(e->dataSV)) { 46743003dfeSmillert s = SvPV(e->dataSV, len); 46843003dfeSmillert count = PerlIO_unread(PerlIONext(f),s,len); 46943003dfeSmillert if ((STRLEN)count != len) { 47043003dfeSmillert code = -1; 47143003dfeSmillert } 47243003dfeSmillert SvCUR_set(e->dataSV,0); 47343003dfeSmillert } 47443003dfeSmillert /* See if there is anything left in the buffer */ 47543003dfeSmillert if (e->base.ptr < e->base.end) { 47643003dfeSmillert if (e->inEncodeCall) return 0; 47743003dfeSmillert /* Bother - have unread data. 47843003dfeSmillert re-encode and unread() to layer below 47943003dfeSmillert */ 48043003dfeSmillert PUSHSTACKi(PERLSI_MAGIC); 48143003dfeSmillert ENTER; 48243003dfeSmillert SAVETMPS; 483*3d61058aSafresh1 str = newSV_type_mortal(SVt_PV); 48443003dfeSmillert SvPV_set(str, (char*)e->base.ptr); 48543003dfeSmillert SvLEN_set(str, 0); 48643003dfeSmillert SvCUR_set(str, e->base.end - e->base.ptr); 48743003dfeSmillert SvPOK_only(str); 48843003dfeSmillert SvUTF8_on(str); 48943003dfeSmillert PUSHMARK(sp); 49043003dfeSmillert XPUSHs(e->enc); 49143003dfeSmillert XPUSHs(str); 49243003dfeSmillert XPUSHs(e->chk); 49343003dfeSmillert PUTBACK; 49443003dfeSmillert e->inEncodeCall = 1; 49543003dfeSmillert if (call_method("encode", G_SCALAR) != 1) { 49643003dfeSmillert e->inEncodeCall = 0; 49743003dfeSmillert Perl_die(aTHX_ "panic: encode did not return a value"); 49843003dfeSmillert } 49943003dfeSmillert e->inEncodeCall = 0; 50043003dfeSmillert SPAGAIN; 50143003dfeSmillert str = POPs; 50243003dfeSmillert PUTBACK; 50343003dfeSmillert s = SvPV(str, len); 50443003dfeSmillert count = PerlIO_unread(PerlIONext(f),s,len); 50543003dfeSmillert if ((STRLEN)count != len) { 50643003dfeSmillert code = -1; 50743003dfeSmillert } 50843003dfeSmillert FREETMPS; 50943003dfeSmillert LEAVE; 51043003dfeSmillert POPSTACK; 51143003dfeSmillert } 51243003dfeSmillert } 51343003dfeSmillert e->base.ptr = e->base.end = e->base.buf; 51443003dfeSmillert PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF); 51543003dfeSmillert } 51643003dfeSmillert return code; 51743003dfeSmillert } 51843003dfeSmillert 519b8851fccSafresh1 static IV 52043003dfeSmillert PerlIOEncode_close(pTHX_ PerlIO * f) 52143003dfeSmillert { 52243003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 52343003dfeSmillert IV code; 52443003dfeSmillert if (PerlIOBase(f)->flags & PERLIO_F_RDBUF) { 52543003dfeSmillert /* Discard partial character */ 52643003dfeSmillert if (e->dataSV) { 52743003dfeSmillert SvCUR_set(e->dataSV,0); 52843003dfeSmillert } 52943003dfeSmillert /* Don't back decode and unread any pending data */ 53043003dfeSmillert e->base.ptr = e->base.end = e->base.buf; 53143003dfeSmillert } 53243003dfeSmillert code = PerlIOBase_close(aTHX_ f); 53343003dfeSmillert if (e->bufsv) { 53443003dfeSmillert /* This should only fire for write case */ 53543003dfeSmillert if (e->base.buf && e->base.ptr > e->base.buf) { 53643003dfeSmillert Perl_croak(aTHX_ "Close with partial character"); 53743003dfeSmillert } 53843003dfeSmillert SvREFCNT_dec(e->bufsv); 53943003dfeSmillert e->bufsv = Nullsv; 54043003dfeSmillert } 54143003dfeSmillert e->base.buf = NULL; 54243003dfeSmillert e->base.ptr = NULL; 54343003dfeSmillert e->base.end = NULL; 54443003dfeSmillert PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF); 54543003dfeSmillert return code; 54643003dfeSmillert } 54743003dfeSmillert 548b8851fccSafresh1 static Off_t 54943003dfeSmillert PerlIOEncode_tell(pTHX_ PerlIO * f) 55043003dfeSmillert { 55143003dfeSmillert PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); 552ca22dbdeSmillert /* Unfortunately the only way to get a position is to (re-)translate, 553ca22dbdeSmillert the UTF8 we have in buffer and then ask layer below 55443003dfeSmillert */ 55543003dfeSmillert PerlIO_flush(f); 55643003dfeSmillert if (b->buf && b->ptr > b->buf) { 55743003dfeSmillert Perl_croak(aTHX_ "Cannot tell at partial character"); 55843003dfeSmillert } 55943003dfeSmillert return PerlIO_tell(PerlIONext(f)); 56043003dfeSmillert } 56143003dfeSmillert 562b8851fccSafresh1 static PerlIO * 56343003dfeSmillert PerlIOEncode_dup(pTHX_ PerlIO * f, PerlIO * o, 56443003dfeSmillert CLONE_PARAMS * params, int flags) 56543003dfeSmillert { 56643003dfeSmillert if ((f = PerlIOBase_dup(aTHX_ f, o, params, flags))) { 56743003dfeSmillert PerlIOEncode *fe = PerlIOSelf(f, PerlIOEncode); 56843003dfeSmillert PerlIOEncode *oe = PerlIOSelf(o, PerlIOEncode); 56943003dfeSmillert if (oe->enc) { 57043003dfeSmillert fe->enc = PerlIO_sv_dup(aTHX_ oe->enc, params); 57143003dfeSmillert } 572b8851fccSafresh1 if (oe->chk) { 573b8851fccSafresh1 fe->chk = PerlIO_sv_dup(aTHX_ oe->chk, params); 574b8851fccSafresh1 } 57543003dfeSmillert } 57643003dfeSmillert return f; 57743003dfeSmillert } 57843003dfeSmillert 579b8851fccSafresh1 static SSize_t 58043003dfeSmillert PerlIOEncode_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) 58143003dfeSmillert { 58243003dfeSmillert PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode); 58343003dfeSmillert if (e->flags & NEEDS_LINES) { 58443003dfeSmillert SSize_t done = 0; 58543003dfeSmillert const char *ptr = (const char *) vbuf; 58643003dfeSmillert const char *end = ptr+count; 58743003dfeSmillert while (ptr < end) { 58843003dfeSmillert const char *nl = ptr; 58943003dfeSmillert while (nl < end && *nl++ != '\n') /* empty body */; 59043003dfeSmillert done = PerlIOBuf_write(aTHX_ f, ptr, nl-ptr); 59143003dfeSmillert if (done != nl-ptr) { 59243003dfeSmillert if (done > 0) { 59343003dfeSmillert ptr += done; 59443003dfeSmillert } 59543003dfeSmillert break; 59643003dfeSmillert } 59743003dfeSmillert ptr += done; 59843003dfeSmillert if (ptr[-1] == '\n') { 59943003dfeSmillert if (PerlIOEncode_flush(aTHX_ f) != 0) { 60043003dfeSmillert break; 60143003dfeSmillert } 60243003dfeSmillert } 60343003dfeSmillert } 60443003dfeSmillert return (SSize_t) (ptr - (const char *) vbuf); 60543003dfeSmillert } 60643003dfeSmillert else { 60743003dfeSmillert return PerlIOBuf_write(aTHX_ f, vbuf, count); 60843003dfeSmillert } 60943003dfeSmillert } 61043003dfeSmillert 611b8851fccSafresh1 static PERLIO_FUNCS_DECL(PerlIO_encode) = { 61243003dfeSmillert sizeof(PerlIO_funcs), 61343003dfeSmillert "encoding", 61443003dfeSmillert sizeof(PerlIOEncode), 61543003dfeSmillert PERLIO_K_BUFFERED|PERLIO_K_DESTRUCT, 61643003dfeSmillert PerlIOEncode_pushed, 61743003dfeSmillert PerlIOEncode_popped, 61843003dfeSmillert PerlIOBuf_open, 61943003dfeSmillert NULL, /* binmode - always pop */ 62043003dfeSmillert PerlIOEncode_getarg, 62143003dfeSmillert PerlIOBase_fileno, 62243003dfeSmillert PerlIOEncode_dup, 62343003dfeSmillert PerlIOBuf_read, 62443003dfeSmillert PerlIOBuf_unread, 62543003dfeSmillert PerlIOEncode_write, 62643003dfeSmillert PerlIOBuf_seek, 62743003dfeSmillert PerlIOEncode_tell, 62843003dfeSmillert PerlIOEncode_close, 62943003dfeSmillert PerlIOEncode_flush, 63043003dfeSmillert PerlIOEncode_fill, 63143003dfeSmillert PerlIOBase_eof, 63243003dfeSmillert PerlIOBase_error, 63343003dfeSmillert PerlIOBase_clearerr, 63443003dfeSmillert PerlIOBase_setlinebuf, 63543003dfeSmillert PerlIOEncode_get_base, 63643003dfeSmillert PerlIOBuf_bufsiz, 63743003dfeSmillert PerlIOBuf_get_ptr, 63843003dfeSmillert PerlIOBuf_get_cnt, 63943003dfeSmillert PerlIOBuf_set_ptrcnt, 64043003dfeSmillert }; 64143003dfeSmillert #endif /* encode layer */ 64243003dfeSmillert 64343003dfeSmillert MODULE = PerlIO::encoding PACKAGE = PerlIO::encoding 64443003dfeSmillert 64543003dfeSmillert PROTOTYPES: ENABLE 64643003dfeSmillert 64743003dfeSmillert BOOT: 64843003dfeSmillert { 64943003dfeSmillert /* 65043003dfeSmillert * we now "use Encode ()" here instead of 65143003dfeSmillert * PerlIO/encoding.pm. This avoids SEGV when ":encoding()" 65243003dfeSmillert * is invoked without prior "use Encode". -- dankogai 65343003dfeSmillert */ 65443003dfeSmillert PUSHSTACKi(PERLSI_MAGIC); 655eac174f2Safresh1 if (!get_cvs(OUR_STOP_AT_PARTIAL, 0)) { 65643003dfeSmillert /* The SV is magically freed by load_module */ 657b8851fccSafresh1 load_module(PERL_LOADMOD_NOIMPORT, newSVpvs("Encode"), Nullsv, Nullsv); 658e5157e49Safresh1 assert(sp == PL_stack_sp); 65943003dfeSmillert } 660eac174f2Safresh1 66143003dfeSmillert PUSHMARK(sp); 66243003dfeSmillert PUTBACK; 663eac174f2Safresh1 if (call_pv(OUR_STOP_AT_PARTIAL, G_SCALAR) != 1) { 66443003dfeSmillert /* should never happen */ 665eac174f2Safresh1 Perl_die(aTHX_ "%s did not return a value", OUR_STOP_AT_PARTIAL); 66643003dfeSmillert } 66743003dfeSmillert SPAGAIN; 668eac174f2Safresh1 encode_stop_at_partial = POPu; 669eac174f2Safresh1 670eac174f2Safresh1 PUSHMARK(sp); 671eac174f2Safresh1 PUTBACK; 672eac174f2Safresh1 if (call_pv(OUR_LEAVE_SRC, G_SCALAR) != 1) { 673eac174f2Safresh1 /* should never happen */ 674eac174f2Safresh1 Perl_die(aTHX_ "%s did not return a value", OUR_LEAVE_SRC); 675eac174f2Safresh1 } 676eac174f2Safresh1 SPAGAIN; 677eac174f2Safresh1 encode_leave_src = POPu; 678eac174f2Safresh1 67943003dfeSmillert PUTBACK; 68043003dfeSmillert #ifdef PERLIO_LAYERS 681b8851fccSafresh1 PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_encode)); 68243003dfeSmillert #endif 68343003dfeSmillert POPSTACK; 68443003dfeSmillert } 685