Mercurial > hg > xemacs-beta
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 { |