comparison src/fns.c @ 377:d883f39b8495 r21-2b4

Import from CVS: tag r21-2b4
author cvs
date Mon, 13 Aug 2007 11:05:42 +0200
parents 6240c7796c7a
children 8626e4521993
comparison
equal deleted inserted replaced
376:e2295b4d9f2e 377:d883f39b8495
47 #include "device.h" 47 #include "device.h"
48 #include "events.h" 48 #include "events.h"
49 #include "extents.h" 49 #include "extents.h"
50 #include "frame.h" 50 #include "frame.h"
51 #include "systime.h" 51 #include "systime.h"
52 #include "insdel.h"
53 #include "lstream.h"
54 #include "opaque.h"
52 55
53 /* NOTE: This symbol is also used in lread.c */ 56 /* NOTE: This symbol is also used in lread.c */
54 #define FEATUREP_SYNTAX 57 #define FEATUREP_SYNTAX
55 58
56 Lisp_Object Qstring_lessp; 59 Lisp_Object Qstring_lessp;
3520 /* Once loading finishes, don't undo it. */ 3523 /* Once loading finishes, don't undo it. */
3521 Vautoload_queue = Qt; 3524 Vautoload_queue = Qt;
3522 return unbind_to (speccount, feature); 3525 return unbind_to (speccount, feature);
3523 } 3526 }
3524 } 3527 }
3525 3528
3529 /* base64 encode/decode functions.
3530 Based on code from GNU recode. */
3531
3532 #define MIME_LINE_LENGTH 76
3533
3534 #define IS_ASCII(Character) \
3535 ((Character) < 128)
3536 #define IS_BASE64(Character) \
3537 (IS_ASCII (Character) && base64_char_to_value[Character] >= 0)
3538
3539 /* Table of characters coding the 64 values. */
3540 static char base64_value_to_char[64] =
3541 {
3542 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0- 9 */
3543 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */
3544 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */
3545 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */
3546 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */
3547 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */
3548 '8', '9', '+', '/' /* 60-63 */
3549 };
3550
3551 /* Table of base64 values for first 128 characters. */
3552 static short base64_char_to_value[128] =
3553 {
3554 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0- 9 */
3555 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10- 19 */
3556 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20- 29 */
3557 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 30- 39 */
3558 -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, /* 40- 49 */
3559 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, /* 50- 59 */
3560 -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, /* 60- 69 */
3561 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70- 79 */
3562 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80- 89 */
3563 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, /* 90- 99 */
3564 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */
3565 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */
3566 49, 50, 51, -1, -1, -1, -1, -1 /* 120-127 */
3567 };
3568
3569 /* The following diagram shows the logical steps by which three octets
3570 get transformed into four base64 characters.
3571
3572 .--------. .--------. .--------.
3573 |aaaaaabb| |bbbbcccc| |ccdddddd|
3574 `--------' `--------' `--------'
3575 6 2 4 4 2 6
3576 .--------+--------+--------+--------.
3577 |00aaaaaa|00bbbbbb|00cccccc|00dddddd|
3578 `--------+--------+--------+--------'
3579
3580 .--------+--------+--------+--------.
3581 |AAAAAAAA|BBBBBBBB|CCCCCCCC|DDDDDDDD|
3582 `--------+--------+--------+--------'
3583
3584 The octets are divided into 6 bit chunks, which are then encoded into
3585 base64 characters. */
3586
3587 #define ADVANCE_INPUT(c, stream) \
3588 (ec = Lstream_get_emchar (stream), \
3589 ec == -1 ? 0 : \
3590 ((ec > 255) ? \
3591 (error ("Non-ascii character detected in base64 input"), 0) \
3592 : (c = (Bufbyte)ec, 1)))
3593
3594 static Bytind
3595 base64_encode_1 (Lstream *istream, Bufbyte *to, int line_break)
3596 {
3597 EMACS_INT counter = 0;
3598 Bufbyte *e = to;
3599 Emchar ec;
3600 unsigned int value;
3601
3602 while (1)
3603 {
3604 Bufbyte c;
3605 if (!ADVANCE_INPUT (c, istream))
3606 break;
3607
3608 /* Wrap line every 76 characters. */
3609 if (line_break)
3610 {
3611 if (counter < MIME_LINE_LENGTH / 4)
3612 counter++;
3613 else
3614 {
3615 *e++ = '\n';
3616 counter = 1;
3617 }
3618 }
3619
3620 /* Process first byte of a triplet. */
3621 *e++ = base64_value_to_char[0x3f & c >> 2];
3622 value = (0x03 & c) << 4;
3623
3624 /* Process second byte of a triplet. */
3625 if (!ADVANCE_INPUT (c, istream))
3626 {
3627 *e++ = base64_value_to_char[value];
3628 *e++ = '=';
3629 *e++ = '=';
3630 break;
3631 }
3632
3633 *e++ = base64_value_to_char[value | (0x0f & c >> 4)];
3634 value = (0x0f & c) << 2;
3635
3636 /* Process third byte of a triplet. */
3637 if (!ADVANCE_INPUT (c, istream))
3638 {
3639 *e++ = base64_value_to_char[value];
3640 *e++ = '=';
3641 break;
3642 }
3643
3644 *e++ = base64_value_to_char[value | (0x03 & c >> 6)];
3645 *e++ = base64_value_to_char[0x3f & c];
3646 }
3647
3648 /* Complete last partial line. */
3649 if (line_break)
3650 if (counter > 0)
3651 *e++ = '\n';
3652
3653 return e - to;
3654 }
3655 #undef ADVANCE_INPUT
3656
3657 #define ADVANCE_INPUT(c, stream) \
3658 (ec = Lstream_get_emchar (stream), \
3659 ec == -1 ? 0 : (c = (Bufbyte)ec, 1))
3660
3661 #define INPUT_EOF_P(stream) \
3662 (ADVANCE_INPUT (c2, stream) \
3663 ? (Lstream_unget_emchar (stream, (Emchar)c2), 0) \
3664 : 1)
3665
3666 #define STORE_BYTE(pos, val) do { \
3667 pos += set_charptr_emchar (pos, (Emchar)((unsigned char)(val))); \
3668 ++*ccptr; \
3669 } while (0)
3670
3671 static Bytind
3672 base64_decode_1 (Lstream *istream, Bufbyte *to, Charcount *ccptr)
3673 {
3674 EMACS_INT counter = 0;
3675 Emchar ec;
3676 Bufbyte *e = to;
3677 unsigned long value;
3678
3679 *ccptr = 0;
3680 while (1)
3681 {
3682 Bufbyte c, c2;
3683
3684 if (!ADVANCE_INPUT (c, istream))
3685 break;
3686
3687 /* Accept wrapping lines, reversibly if at each 76 characters. */
3688 if (c == '\n')
3689 {
3690 if (!ADVANCE_INPUT (c, istream))
3691 break;
3692 if (INPUT_EOF_P (istream))
3693 break;
3694 /* FSF Emacs has this check, apparently inherited from
3695 recode. However, I see no reason to be this picky about
3696 line length -- why reject base64 with say 72-byte lines?
3697 (yes, there are programs that generate them.) */
3698 /*if (counter != MIME_LINE_LENGTH / 4) return -1;*/
3699 counter = 1;
3700 }
3701 else
3702 counter++;
3703
3704 /* Process first byte of a quadruplet. */
3705 if (!IS_BASE64 (c))
3706 return -1;
3707 value = base64_char_to_value[c] << 18;
3708
3709 /* Process second byte of a quadruplet. */
3710 if (!ADVANCE_INPUT (c, istream))
3711 return -1;
3712
3713 if (!IS_BASE64 (c))
3714 return -1;
3715 value |= base64_char_to_value[c] << 12;
3716
3717 STORE_BYTE (e, value >> 16);
3718
3719 /* Process third byte of a quadruplet. */
3720 if (!ADVANCE_INPUT (c, istream))
3721 return -1;
3722
3723 if (c == '=')
3724 {
3725 if (!ADVANCE_INPUT (c, istream))
3726 return -1;
3727 if (c != '=')
3728 return -1;
3729 continue;
3730 }
3731
3732 if (!IS_BASE64 (c))
3733 return -1;
3734 value |= base64_char_to_value[c] << 6;
3735
3736 STORE_BYTE (e, 0xff & value >> 8);
3737
3738 /* Process fourth byte of a quadruplet. */
3739 if (!ADVANCE_INPUT (c, istream))
3740 return -1;
3741
3742 if (c == '=')
3743 continue;
3744
3745 if (!IS_BASE64 (c))
3746 return -1;
3747 value |= base64_char_to_value[c];
3748
3749 STORE_BYTE (e, 0xff & value);
3750 }
3751
3752 return e - to;
3753 }
3754 #undef ADVANCE_INPUT
3755 #undef INPUT_EOF_P
3756
3757 static Lisp_Object
3758 free_malloced_ptr (Lisp_Object unwind_obj)
3759 {
3760 void *ptr = (void *)get_opaque_ptr (unwind_obj);
3761 xfree (ptr);
3762 free_opaque_ptr (unwind_obj);
3763 return Qnil;
3764 }
3765
3766 /* Don't use alloca for regions larger than this, lest we overflow
3767 the stack. */
3768 #define MAX_ALLOCA 65536
3769
3770 /* We need to setup proper unwinding, because there is a number of
3771 ways these functions can blow up, and we don't want to have memory
3772 leaks in those cases. */
3773 #define XMALLOC_OR_ALLOCA(ptr, len, type) do { \
3774 if ((len) > MAX_ALLOCA) \
3775 { \
3776 ptr = (type *)xmalloc ((len) * sizeof (type)); \
3777 speccount = specpdl_depth (); \
3778 record_unwind_protect (free_malloced_ptr, \
3779 make_opaque_ptr ((void *)ptr)); \
3780 } \
3781 else \
3782 ptr = alloca_array (type, len); \
3783 } while (0)
3784
3785 #define XMALLOC_UNBIND(ptr, len) do { \
3786 if ((len) > MAX_ALLOCA) \
3787 unbind_to (speccount, Qnil); \
3788 } while (0)
3789
3790 DEFUN ("base64-encode-region", Fbase64_encode_region, 2, 3, "r", /*
3791 Base64-encode the region between BEG and END.
3792 Return the length of the encoded text.
3793 Optional third argument NO-LINE-BREAK means do not break long lines
3794 into shorter lines.
3795 */
3796 (beg, end, no_line_break))
3797 {
3798 Bufbyte *encoded;
3799 Bytind encoded_length;
3800 Charcount allength, length;
3801 struct buffer *buf = current_buffer;
3802 Bufpos begv, zv, old_pt = BUF_PT (buf);
3803 Lisp_Object input;
3804 int speccount;
3805
3806 get_buffer_range_char (buf, beg, end, &begv, &zv, 0);
3807
3808 /* We need to allocate enough room for encoding the text.
3809 We need 33 1/3% more space, plus a newline every 76
3810 characters, and then we round up. */
3811 length = zv - begv;
3812 allength = length + length/3 + 1;
3813 allength += allength / MIME_LINE_LENGTH + 1 + 6;
3814
3815 input = make_lisp_buffer_input_stream (buf, begv, zv, 0);
3816 /* We needn't multiply allength with MAX_EMCHAR_LEN because all the
3817 base64 characters will be single-byte. */
3818 XMALLOC_OR_ALLOCA (encoded, allength, Bufbyte);
3819 encoded_length = base64_encode_1 (XLSTREAM (input), encoded,
3820 NILP (no_line_break));
3821 if (encoded_length > allength)
3822 abort ();
3823 Lstream_delete (XLSTREAM (input));
3824
3825 /* Now we have encoded the region, so we insert the new contents
3826 and delete the old. (Insert first in order to preserve markers.) */
3827 buffer_insert_raw_string_1 (buf, begv, encoded, encoded_length, 0);
3828 XMALLOC_UNBIND (encoded, allength);
3829 buffer_delete_range (buf, begv + encoded_length, zv + encoded_length, 0);
3830
3831 /* Simulate FSF Emacs: if point was in the region, place it at the
3832 beginning. */
3833 if (old_pt >= begv && old_pt < zv)
3834 BUF_SET_PT (buf, begv);
3835
3836 /* We return the length of the encoded text. */
3837 return make_int (encoded_length);
3838 }
3839
3840 DEFUN ("base64-encode-string", Fbase64_encode_string, 1, 1, 0, /*
3841 Base64 encode STRING and return the result.
3842 */
3843 (string))
3844 {
3845 Charcount allength, length;
3846 Bytind encoded_length;
3847 Bufbyte *encoded;
3848 Lisp_Object input, result;
3849 int speccount;
3850
3851 CHECK_STRING (string);
3852
3853 length = XSTRING_CHAR_LENGTH (string);
3854 allength = length + length/3 + 1 + 6;
3855
3856 input = make_lisp_string_input_stream (string, 0, -1);
3857 XMALLOC_OR_ALLOCA (encoded, allength, Bufbyte);
3858 encoded_length = base64_encode_1 (XLSTREAM (input), encoded, 0);
3859 if (encoded_length > allength)
3860 abort ();
3861 Lstream_delete (XLSTREAM (input));
3862 result = make_string (encoded, encoded_length);
3863 XMALLOC_UNBIND (encoded, allength);
3864 return result;
3865 }
3866
3867 DEFUN ("base64-decode-region", Fbase64_decode_region, 2, 2, "r", /*
3868 Base64-decode the region between BEG and END.
3869 Return the length of the decoded text.
3870 If the region can't be decoded, return nil and don't modify the buffer.
3871 */
3872 (beg, end))
3873 {
3874 struct buffer *buf = current_buffer;
3875 Bufpos begv, zv, old_pt = BUF_PT (buf);
3876 Bufbyte *decoded;
3877 Bytind decoded_length;
3878 Charcount length, cc_decoded_length;
3879 Lisp_Object input;
3880 int speccount;
3881
3882 get_buffer_range_char (buf, beg, end, &begv, &zv, 0);
3883 length = zv - begv;
3884
3885 input = make_lisp_buffer_input_stream (buf, begv, zv, 0);
3886 /* We need to allocate enough room for decoding the text. */
3887 XMALLOC_OR_ALLOCA (decoded, length * MAX_EMCHAR_LEN, Bufbyte);
3888 decoded_length = base64_decode_1 (XLSTREAM (input), decoded, &cc_decoded_length);
3889 if (decoded_length > length * MAX_EMCHAR_LEN)
3890 abort ();
3891 Lstream_delete (XLSTREAM (input));
3892
3893 if (decoded_length < 0)
3894 {
3895 /* The decoding wasn't possible. */
3896 XMALLOC_UNBIND (decoded, length * MAX_EMCHAR_LEN);
3897 return Qnil;
3898 }
3899
3900 /* Now we have decoded the region, so we insert the new contents
3901 and delete the old. (Insert first in order to preserve markers.) */
3902 BUF_SET_PT (buf, begv);
3903 buffer_insert_raw_string_1 (buf, begv, decoded, decoded_length, 0);
3904 XMALLOC_UNBIND (decoded, length * MAX_EMCHAR_LEN);
3905 buffer_delete_range (buf, begv + cc_decoded_length,
3906 zv + cc_decoded_length, 0);
3907
3908 /* Simulate FSF Emacs: if point was in the region, place it at the
3909 beginning. */
3910 if (old_pt >= begv && old_pt < zv)
3911 BUF_SET_PT (buf, begv);
3912
3913 return make_int (cc_decoded_length);
3914 }
3915
3916 DEFUN ("base64-decode-string", Fbase64_decode_string, 1, 1, 0, /*
3917 Base64-decode STRING and return the result.
3918 */
3919 (string))
3920 {
3921 Bufbyte *decoded;
3922 Bytind decoded_length;
3923 Charcount length, cc_decoded_length;
3924 Lisp_Object input, result;
3925 int speccount;
3926
3927 CHECK_STRING (string);
3928
3929 length = XSTRING_CHAR_LENGTH (string);
3930 /* We need to allocate enough room for decoding the text. */
3931 XMALLOC_OR_ALLOCA (decoded, length * MAX_EMCHAR_LEN, Bufbyte);
3932
3933 input = make_lisp_string_input_stream (string, 0, -1);
3934 decoded_length = base64_decode_1 (XLSTREAM (input), decoded,
3935 &cc_decoded_length);
3936 if (decoded_length > length * MAX_EMCHAR_LEN)
3937 abort ();
3938 Lstream_delete (XLSTREAM (input));
3939
3940 if (decoded_length < 0)
3941 {
3942 return Qnil;
3943 XMALLOC_UNBIND (decoded, length * MAX_EMCHAR_LEN);
3944 }
3945
3946 result = make_string (decoded, decoded_length);
3947 XMALLOC_UNBIND (decoded, length * MAX_EMCHAR_LEN);
3948 return result;
3949 }
3526 3950
3527 Lisp_Object Qyes_or_no_p; 3951 Lisp_Object Qyes_or_no_p;
3528 3952
3529 void 3953 void
3530 syms_of_fns (void) 3954 syms_of_fns (void)
3606 DEFSUBR (Fmapconcat); 4030 DEFSUBR (Fmapconcat);
3607 DEFSUBR (Fload_average); 4031 DEFSUBR (Fload_average);
3608 DEFSUBR (Ffeaturep); 4032 DEFSUBR (Ffeaturep);
3609 DEFSUBR (Frequire); 4033 DEFSUBR (Frequire);
3610 DEFSUBR (Fprovide); 4034 DEFSUBR (Fprovide);
4035 DEFSUBR (Fbase64_encode_region);
4036 DEFSUBR (Fbase64_encode_string);
4037 DEFSUBR (Fbase64_decode_region);
4038 DEFSUBR (Fbase64_decode_string);
3611 } 4039 }
3612 4040
3613 void 4041 void
3614 init_provide_once (void) 4042 init_provide_once (void)
3615 { 4043 {