indent -kr -nce and some manual tweaks to match perl style.
[p5sagit/p5-mst-13.2.git] / ext / Encode / Encode.xs
1 #define PERL_NO_GET_CONTEXT
2
3 #include "EXTERN.h"
4 #include "perl.h"
5 #include "XSUB.h"
6 #define U8 U8
7 #include "encode.h"
8 #include "8859.h"
9 #include "EBCDIC.h"
10 #include "Symbols.h"
11
12
13 #define UNIMPLEMENTED(x,y) y x (SV *sv, char *encoding) {dTHX;   \
14                          Perl_croak(aTHX_ "panic_unimplemented"); \
15                          return (y)0; /* fool picky compilers */ \
16                          }
17 UNIMPLEMENTED(_encoded_utf8_to_bytes, I32)
18     UNIMPLEMENTED(_encoded_bytes_to_utf8, I32)
19 #if defined(USE_PERLIO) && !defined(USE_SFIO)
20 /* Define an encoding "layer" in the perliol.h sense.
21    The layer defined here "inherits" in an object-oriented sense from the
22    "perlio" layer with its PerlIOBuf_* "methods".
23    The implementation is particularly efficient as until Encode settles down
24    there is no point in tryint to tune it.
25
26    The layer works by overloading the "fill" and "flush" methods.
27
28    "fill" calls "SUPER::fill" in perl terms, then calls the encode OO perl API
29    to convert the encoded data to UTF-8 form, then copies it back to the
30    buffer. The "base class's" read methods then see the UTF-8 data.
31
32    "flush" transforms the UTF-8 data deposited by the "base class's write
33    method in the buffer back into the encoded form using the encode OO perl API,
34    then copies data back into the buffer and calls "SUPER::flush.
35
36    Note that "flush" is _also_ called for read mode - we still do the (back)-translate
37    so that the the base class's "flush" sees the correct number of encoded chars
38    for positioning the seek pointer. (This double translation is the worst performance
39    issue - particularly with all-perl encode engine.)
40
41 */
42 #include "perliol.h"
43 typedef struct {
44     PerlIOBuf base;             /* PerlIOBuf stuff */
45     SV *bufsv;
46     SV *enc;
47 } PerlIOEncode;
48
49 SV *
50 PerlIOEncode_getarg(pTHX_ PerlIO * f, CLONE_PARAMS * param, int flags)
51 {
52     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
53     SV *sv = &PL_sv_undef;
54     if (e->enc) {
55         dSP;
56         ENTER;
57         SAVETMPS;
58         PUSHMARK(sp);
59         XPUSHs(e->enc);
60         PUTBACK;
61         if (perl_call_method("name", G_SCALAR) == 1) {
62             SPAGAIN;
63             sv = newSVsv(POPs);
64             PUTBACK;
65         }
66     }
67     return sv;
68 }
69
70 IV
71 PerlIOEncode_pushed(pTHX_ PerlIO * f, const char *mode, SV * arg)
72 {
73     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
74     dSP;
75     IV code;
76     code = PerlIOBuf_pushed(aTHX_ f, mode, Nullsv);
77     ENTER;
78     SAVETMPS;
79     PUSHMARK(sp);
80     XPUSHs(arg);
81     PUTBACK;
82     if (perl_call_pv("Encode::find_encoding", G_SCALAR) != 1) {
83         /* should never happen */
84         Perl_die(aTHX_ "Encode::find_encoding did not return a value");
85         return -1;
86     }
87     SPAGAIN;
88     e->enc = POPs;
89     PUTBACK;
90     if (!SvROK(e->enc)) {
91         e->enc = Nullsv;
92         errno = EINVAL;
93         Perl_warner(aTHX_ WARN_IO, "Cannot find encoding \"%" SVf "\"",
94                     arg);
95         code = -1;
96     }
97     else {
98         SvREFCNT_inc(e->enc);
99         PerlIOBase(f)->flags |= PERLIO_F_UTF8;
100     }
101     FREETMPS;
102     LEAVE;
103     return code;
104 }
105
106 IV
107 PerlIOEncode_popped(pTHX_ PerlIO * f)
108 {
109     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
110     if (e->enc) {
111         SvREFCNT_dec(e->enc);
112         e->enc = Nullsv;
113     }
114     if (e->bufsv) {
115         SvREFCNT_dec(e->bufsv);
116         e->bufsv = Nullsv;
117     }
118     return 0;
119 }
120
121 STDCHAR *
122 PerlIOEncode_get_base(pTHX_ PerlIO * f)
123 {
124     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
125     if (!e->base.bufsiz)
126         e->base.bufsiz = 1024;
127     if (!e->bufsv) {
128         e->bufsv = newSV(e->base.bufsiz);
129         sv_setpvn(e->bufsv, "", 0);
130     }
131     e->base.buf = (STDCHAR *) SvPVX(e->bufsv);
132     if (!e->base.ptr)
133         e->base.ptr = e->base.buf;
134     if (!e->base.end)
135         e->base.end = e->base.buf;
136     if (e->base.ptr < e->base.buf
137         || e->base.ptr > e->base.buf + SvLEN(e->bufsv)) {
138         Perl_warn(aTHX_ " ptr %p(%p)%p", e->base.buf, e->base.ptr,
139                   e->base.buf + SvLEN(e->bufsv));
140         abort();
141     }
142     if (SvLEN(e->bufsv) < e->base.bufsiz) {
143         SSize_t poff = e->base.ptr - e->base.buf;
144         SSize_t eoff = e->base.end - e->base.buf;
145         e->base.buf = (STDCHAR *) SvGROW(e->bufsv, e->base.bufsiz);
146         e->base.ptr = e->base.buf + poff;
147         e->base.end = e->base.buf + eoff;
148     }
149     if (e->base.ptr < e->base.buf
150         || e->base.ptr > e->base.buf + SvLEN(e->bufsv)) {
151         Perl_warn(aTHX_ " ptr %p(%p)%p", e->base.buf, e->base.ptr,
152                   e->base.buf + SvLEN(e->bufsv));
153         abort();
154     }
155     return e->base.buf;
156 }
157
158 IV
159 PerlIOEncode_fill(pTHX_ PerlIO * f)
160 {
161     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
162     dSP;
163     IV code;
164     code = PerlIOBuf_fill(aTHX_ f);
165     if (code == 0) {
166         SV *uni;
167         STRLEN len;
168         char *s;
169         /* Set SV that is the buffer to be buf..ptr */
170         SvCUR_set(e->bufsv, e->base.end - e->base.buf);
171         SvUTF8_off(e->bufsv);
172         ENTER;
173         SAVETMPS;
174         PUSHMARK(sp);
175         XPUSHs(e->enc);
176         XPUSHs(e->bufsv);
177         XPUSHs(&PL_sv_yes);
178         PUTBACK;
179         if (perl_call_method("decode", G_SCALAR) != 1)
180             code = -1;
181         SPAGAIN;
182         uni = POPs;
183         PUTBACK;
184         /* Now get translated string (forced to UTF-8) and copy back to buffer
185            don't use sv_setsv as that may "steal" PV from returned temp
186            and so free() our known-large-enough buffer.
187            sv_setpvn() should do but let us do it long hand.
188          */
189         s = SvPVutf8(uni, len);
190         if (s != SvPVX(e->bufsv)) {
191             e->base.buf = (STDCHAR *) SvGROW(e->bufsv, len);
192             Move(s, e->base.buf, len, char);
193             SvCUR_set(e->bufsv, len);
194         }
195         SvUTF8_on(e->bufsv);
196         e->base.end = e->base.buf + len;
197         e->base.ptr = e->base.buf;
198         FREETMPS;
199         LEAVE;
200     }
201     return code;
202 }
203
204 IV
205 PerlIOEncode_flush(pTHX_ PerlIO * f)
206 {
207     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
208     IV code = 0;
209     if (e->bufsv
210         && (PerlIOBase(f)->flags & (PERLIO_F_RDBUF | PERLIO_F_WRBUF))
211         && (e->base.ptr > e->base.buf)
212         ) {
213         dSP;
214         SV *str;
215         char *s;
216         STRLEN len;
217         SSize_t left = 0;
218         if (PerlIOBase(f)->flags & PERLIO_F_RDBUF) {
219             /* This is really just a flag to see if we took all the data, if
220                we did PerlIOBase_flush avoids a seek to lower layer.
221                Need to revisit if we start getting clever with unreads or seeks-in-buffer
222              */
223             left = e->base.end - e->base.ptr;
224         }
225         ENTER;
226         SAVETMPS;
227         PUSHMARK(sp);
228         XPUSHs(e->enc);
229         SvCUR_set(e->bufsv, e->base.ptr - e->base.buf);
230         SvUTF8_on(e->bufsv);
231         XPUSHs(e->bufsv);
232         XPUSHs(&PL_sv_yes);
233         PUTBACK;
234         if (perl_call_method("encode", G_SCALAR) != 1)
235             code = -1;
236         SPAGAIN;
237         str = POPs;
238         PUTBACK;
239         s = SvPV(str, len);
240         if (s != SvPVX(e->bufsv)) {
241             e->base.buf = (STDCHAR *) SvGROW(e->bufsv, len);
242             Move(s, e->base.buf, len, char);
243             SvCUR_set(e->bufsv, len);
244         }
245         SvUTF8_off(e->bufsv);
246         e->base.ptr = e->base.buf + len;
247         /* restore end != ptr as inequality is used by PerlIOBuf_flush in read case */
248         e->base.end = e->base.ptr + left;
249         FREETMPS;
250         LEAVE;
251         if (PerlIOBuf_flush(aTHX_ f) != 0)
252             code = -1;
253     }
254     return code;
255 }
256
257 IV
258 PerlIOEncode_close(pTHX_ PerlIO * f)
259 {
260     PerlIOEncode *e = PerlIOSelf(f, PerlIOEncode);
261     IV code = PerlIOBase_close(aTHX_ f);
262     if (e->bufsv) {
263         SvREFCNT_dec(e->bufsv);
264         e->bufsv = Nullsv;
265     }
266     e->base.buf = NULL;
267     e->base.ptr = NULL;
268     e->base.end = NULL;
269     PerlIOBase(f)->flags &= ~(PERLIO_F_RDBUF | PERLIO_F_WRBUF);
270     return code;
271 }
272
273 Off_t
274 PerlIOEncode_tell(pTHX_ PerlIO * f)
275 {
276     PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf);
277     /* Unfortunately the only way to get a postion is to back-translate,
278        the UTF8-bytes we have buf..ptr and adjust accordingly.
279        But we will try and save any unread data in case stream
280        is un-seekable.
281      */
282     if ((PerlIOBase(f)->flags & PERLIO_F_RDBUF) && b->ptr < b->end) {
283         Size_t count = b->end - b->ptr;
284         PerlIO_push(aTHX_ f, &PerlIO_pending, "r", Nullsv);
285         /* Save what we have left to read */
286         PerlIOSelf(f, PerlIOBuf)->bufsiz = count;
287         PerlIO_unread(f, b->ptr, count);
288         /* There isn't any unread data - we just saved it - so avoid the lower seek */
289         b->end = b->ptr;
290         /* Flush ourselves - now one layer down,
291            this does the back translate and adjusts position
292          */
293         PerlIO_flush(PerlIONext(f));
294         /* Set position of the saved data */
295         PerlIOSelf(f, PerlIOBuf)->posn = b->posn;
296     }
297     else {
298         PerlIO_flush(f);
299     }
300     return b->posn;
301 }
302
303 PerlIO *
304 PerlIOEncode_dup(pTHX_ PerlIO * f, PerlIO * o,
305                  CLONE_PARAMS * params, int flags)
306 {
307     if ((f = PerlIOBase_dup(aTHX_ f, o, params, flags))) {
308         PerlIOEncode *fe = PerlIOSelf(f, PerlIOEncode);
309         PerlIOEncode *oe = PerlIOSelf(o, PerlIOEncode);
310         if (oe->enc) {
311             fe->enc = PerlIO_sv_dup(aTHX_ oe->enc, params);
312         }
313     }
314     return f;
315 }
316
317 PerlIO_funcs PerlIO_encode = {
318     "encoding",
319     sizeof(PerlIOEncode),
320     PERLIO_K_BUFFERED,
321     PerlIOEncode_pushed,
322     PerlIOEncode_popped,
323     PerlIOBuf_open,
324     PerlIOEncode_getarg,
325     PerlIOBase_fileno,
326     PerlIOEncode_dup,
327     PerlIOBuf_read,
328     PerlIOBuf_unread,
329     PerlIOBuf_write,
330     PerlIOBuf_seek,
331     PerlIOEncode_tell,
332     PerlIOEncode_close,
333     PerlIOEncode_flush,
334     PerlIOEncode_fill,
335     PerlIOBase_eof,
336     PerlIOBase_error,
337     PerlIOBase_clearerr,
338     PerlIOBase_setlinebuf,
339     PerlIOEncode_get_base,
340     PerlIOBuf_bufsiz,
341     PerlIOBuf_get_ptr,
342     PerlIOBuf_get_cnt,
343     PerlIOBuf_set_ptrcnt,
344 };
345 #endif                          /* encode layer */
346
347 void
348 Encode_XSEncoding(pTHX_ encode_t * enc)
349 {
350     dSP;
351     HV *stash = gv_stashpv("Encode::XS", TRUE);
352     SV *sv = sv_bless(newRV_noinc(newSViv(PTR2IV(enc))), stash);
353     int i = 0;
354     PUSHMARK(sp);
355     XPUSHs(sv);
356     while (enc->name[i]) {
357         const char *name = enc->name[i++];
358         XPUSHs(sv_2mortal(newSVpvn(name, strlen(name))));
359     }
360     PUTBACK;
361     call_pv("Encode::define_encoding", G_DISCARD);
362     SvREFCNT_dec(sv);
363 }
364
365 void
366 call_failure(SV * routine, U8 * done, U8 * dest, U8 * orig)
367 {
368 }
369
370 static SV *
371 encode_method(pTHX_ encode_t * enc, encpage_t * dir, SV * src,
372                          int check)
373 {
374     STRLEN slen;
375     U8 *s = (U8 *) SvPV(src, slen);
376     SV *dst = sv_2mortal(newSV(2 * slen + 1));
377     if (slen) {
378         U8 *d = (U8 *) SvGROW(dst, 2 * slen + 1);
379         STRLEN dlen = SvLEN(dst);
380         int code;
381         while ((code = do_encode(dir, s, &slen, d, dlen, &dlen, !check))) {
382             SvCUR_set(dst, dlen);
383             SvPOK_on(dst);
384
385             if (code == ENCODE_FALLBACK)
386                 break;
387
388             switch (code) {
389             case ENCODE_NOSPACE:
390                 {
391                     STRLEN need = dlen + UTF8_MAXLEN * 128;     /* 128 is too big or small? */
392                     d = (U8 *) SvGROW(dst, need);
393                     if (dlen >= SvLEN(dst)) {
394                         Perl_croak(aTHX_
395                                    "Destination couldn't be grown (the need may be miscalculated).");
396                     }
397                     dlen = SvLEN(dst);
398                     slen = SvCUR(src);
399                     break;
400                 }
401
402             case ENCODE_NOREP:
403                 if (dir == enc->f_utf8) {
404                     if (!check && ckWARN_d(WARN_UTF8)) {
405                         STRLEN clen;
406                         UV ch =
407                             utf8n_to_uvuni(s + slen, (SvCUR(src) - slen),
408                                            &clen, 0);
409                         Perl_warner(aTHX_ WARN_UTF8,
410                                     "\"\\N{U+%" UVxf
411                                     "}\" does not map to %s", ch,
412                                     enc->name[0]);
413                         /* FIXME: Skip over the character, copy in replacement and continue
414                          * but that is messy so for now just fail.
415                          */
416                         return &PL_sv_undef;
417                     }
418                     else {
419                         return &PL_sv_undef;
420                     }
421                 }
422                 else {
423                     /* UTF-8 is supposed to be "Universal" so should not happen */
424                     Perl_croak(aTHX_ "%s '%.*s' does not map to UTF-8",
425                                enc->name[0], (int) (SvCUR(src) - slen),
426                                s + slen);
427                 }
428                 break;
429
430             case ENCODE_PARTIAL:
431                 if (!check && ckWARN_d(WARN_UTF8)) {
432                     Perl_warner(aTHX_ WARN_UTF8, "Partial %s character",
433                                 (dir ==
434                                  enc->f_utf8) ? "UTF-8" : enc->name[0]);
435                 }
436                 return &PL_sv_undef;
437
438             default:
439                 Perl_croak(aTHX_ "Unexpected code %d converting %s %s",
440                            code, (dir == enc->f_utf8) ? "to" : "from",
441                            enc->name[0]);
442                 return &PL_sv_undef;
443             }
444         }
445         SvCUR_set(dst, dlen);
446         SvPOK_on(dst);
447         if (check) {
448             if (slen < SvCUR(src)) {
449                 Move(s + slen, s, SvCUR(src) - slen, U8);
450             }
451             SvCUR_set(src, SvCUR(src) - slen);
452         }
453     }
454     else {
455         SvCUR_set(dst, slen);
456         SvPOK_on(dst);
457     }
458     return dst;
459 }
460
461 MODULE = Encode         PACKAGE = Encode::XS    PREFIX = Method_
462
463 PROTOTYPES: ENABLE
464
465 void
466 Method_decode(obj,src,check = FALSE)
467 SV *    obj
468 SV *    src
469 bool    check
470 CODE:
471  {
472   encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
473   ST(0) = encode_method(aTHX_ enc, enc->t_utf8, src, check);
474   SvUTF8_on(ST(0));
475   XSRETURN(1);
476  }
477
478 void
479 Method_encode(obj,src,check = FALSE)
480 SV *    obj
481 SV *    src
482 bool    check
483 CODE:
484  {
485   encode_t *enc = INT2PTR(encode_t *, SvIV(SvRV(obj)));
486   sv_utf8_upgrade(src);
487   ST(0) = encode_method(aTHX_ enc, enc->f_utf8, src, check);
488   XSRETURN(1);
489  }
490
491 MODULE = Encode         PACKAGE = Encode
492
493 PROTOTYPES: ENABLE
494
495 I32
496 _bytes_to_utf8(sv, ...)
497         SV *    sv
498       CODE:
499         {
500           SV * encoding = items == 2 ? ST(1) : Nullsv;
501
502           if (encoding)
503             RETVAL = _encoded_bytes_to_utf8(sv, SvPV_nolen(encoding));
504           else {
505             STRLEN len;
506             U8*    s = (U8*)SvPV(sv, len);
507             U8*    converted;
508
509             converted = bytes_to_utf8(s, &len); /* This allocs */
510             sv_setpvn(sv, (char *)converted, len);
511             SvUTF8_on(sv); /* XXX Should we? */
512             Safefree(converted);                /* ... so free it */
513             RETVAL = len;
514           }
515         }
516       OUTPUT:
517         RETVAL
518
519 I32
520 _utf8_to_bytes(sv, ...)
521         SV *    sv
522       CODE:
523         {
524           SV * to    = items > 1 ? ST(1) : Nullsv;
525           SV * check = items > 2 ? ST(2) : Nullsv;
526
527           if (to)
528             RETVAL = _encoded_utf8_to_bytes(sv, SvPV_nolen(to));
529           else {
530             STRLEN len;
531             U8 *s = (U8*)SvPV(sv, len);
532
533             RETVAL = 0;
534             if (SvTRUE(check)) {
535               /* Must do things the slow way */
536               U8 *dest;
537               U8 *src  = (U8*)savepv((char *)s); /* We need a copy to pass to check() */
538               U8 *send = s + len;
539
540               New(83, dest, len, U8); /* I think */
541
542               while (s < send) {
543                 if (*s < 0x80)
544                   *dest++ = *s++;
545                 else {
546                   STRLEN ulen;
547                   UV uv = *s++;
548
549                   /* Have to do it all ourselves because of error routine,
550                      aargh. */
551                   if (!(uv & 0x40))
552                     goto failure;
553                   if      (!(uv & 0x20)) { ulen = 2;  uv &= 0x1f; }
554                   else if (!(uv & 0x10)) { ulen = 3;  uv &= 0x0f; }
555                   else if (!(uv & 0x08)) { ulen = 4;  uv &= 0x07; }
556                   else if (!(uv & 0x04)) { ulen = 5;  uv &= 0x03; }
557                   else if (!(uv & 0x02)) { ulen = 6;  uv &= 0x01; }
558                   else if (!(uv & 0x01)) { ulen = 7;  uv = 0; }
559                   else                   { ulen = 13; uv = 0; }
560                 
561                   /* Note change to utf8.c variable naming, for variety */
562                   while (ulen--) {
563                     if ((*s & 0xc0) != 0x80)
564                       goto failure;
565                 
566                     else
567                       uv = (uv << 6) | (*s++ & 0x3f);
568                   }
569                   if (uv > 256) {
570                   failure:
571                     call_failure(check, s, dest, src);
572                     /* Now what happens? */
573                   }
574                   *dest++ = (U8)uv;
575                }
576                }
577             } else
578               RETVAL = (utf8_to_bytes(s, &len) ? len : 0);
579           }
580         }
581       OUTPUT:
582         RETVAL
583
584 bool
585 is_utf8(sv, check = FALSE)
586 SV *    sv
587 bool    check
588       CODE:
589         {
590           if (SvGMAGICAL(sv)) /* it could be $1, for example */
591             sv = newSVsv(sv); /* GMAGIG will be done */
592           if (SvPOK(sv)) {
593             RETVAL = SvUTF8(sv) ? TRUE : FALSE;
594             if (RETVAL &&
595                 check  &&
596                 !is_utf8_string((U8*)SvPVX(sv), SvCUR(sv)))
597               RETVAL = FALSE;
598           } else {
599             RETVAL = FALSE;
600           }
601           if (sv != ST(0))
602             SvREFCNT_dec(sv); /* it was a temp copy */
603         }
604       OUTPUT:
605         RETVAL
606
607 SV *
608 _utf8_on(sv)
609         SV *    sv
610       CODE:
611         {
612           if (SvPOK(sv)) {
613             SV *rsv = newSViv(SvUTF8(sv));
614             RETVAL = rsv;
615             SvUTF8_on(sv);
616           } else {
617             RETVAL = &PL_sv_undef;
618           }
619         }
620       OUTPUT:
621         RETVAL
622
623 SV *
624 _utf8_off(sv)
625         SV *    sv
626       CODE:
627         {
628           if (SvPOK(sv)) {
629             SV *rsv = newSViv(SvUTF8(sv));
630             RETVAL = rsv;
631             SvUTF8_off(sv);
632           } else {
633             RETVAL = &PL_sv_undef;
634           }
635         }
636       OUTPUT:
637         RETVAL
638
639 BOOT:
640 {
641 #if defined(USE_PERLIO) && !defined(USE_SFIO)
642  PerlIO_define_layer(aTHX_ &PerlIO_encode);
643 #endif
644 #include "8859_def.h"
645 #include "EBCDIC_def.h"
646 #include "Symbols_def.h"
647 }