diff options
| author | Karl Heuer | 1998-09-07 19:58:05 +0000 |
|---|---|---|
| committer | Karl Heuer | 1998-09-07 19:58:05 +0000 |
| commit | 24c129e40e0693476967629f403406ef0476013a (patch) | |
| tree | a69f02a8293510e251187eea2ca8571b11d3a88f /src | |
| parent | f7993597fa059a47c956eda83620bb890381787a (diff) | |
| download | emacs-24c129e40e0693476967629f403406ef0476013a.tar.gz emacs-24c129e40e0693476967629f403406ef0476013a.zip | |
(base64_decode_1, base64_encode_1): New functions.
(Fbase64_decode_string, Fbase64_encode_string): New functions.
(Fbase64_decode_region, Fbase64_encode_region): New functions.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 376 |
1 files changed, 376 insertions, 0 deletions
| @@ -2716,6 +2716,378 @@ ARGS are passed as extra arguments to the function.") | |||
| 2716 | return result; | 2716 | return result; |
| 2717 | } | 2717 | } |
| 2718 | 2718 | ||
| 2719 | /* base64 encode/decode functions. | ||
| 2720 | Based on code from GNU recode. */ | ||
| 2721 | |||
| 2722 | #define MIME_LINE_LENGTH 76 | ||
| 2723 | |||
| 2724 | #define IS_ASCII(Character) \ | ||
| 2725 | ((Character) < 128) | ||
| 2726 | #define IS_BASE64(Character) \ | ||
| 2727 | (IS_ASCII (Character) && base64_char_to_value[Character] >= 0) | ||
| 2728 | |||
| 2729 | /* Table of characters coding the 64 values. */ | ||
| 2730 | static char base64_value_to_char[64] = | ||
| 2731 | { | ||
| 2732 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0- 9 */ | ||
| 2733 | 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */ | ||
| 2734 | 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */ | ||
| 2735 | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */ | ||
| 2736 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */ | ||
| 2737 | 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */ | ||
| 2738 | '8', '9', '+', '/' /* 60-63 */ | ||
| 2739 | }; | ||
| 2740 | |||
| 2741 | /* Table of base64 values for first 128 characters. */ | ||
| 2742 | static short base64_char_to_value[128] = | ||
| 2743 | { | ||
| 2744 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0- 9 */ | ||
| 2745 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10- 19 */ | ||
| 2746 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 20- 29 */ | ||
| 2747 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 30- 39 */ | ||
| 2748 | -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, /* 40- 49 */ | ||
| 2749 | 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, /* 50- 59 */ | ||
| 2750 | -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, /* 60- 69 */ | ||
| 2751 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70- 79 */ | ||
| 2752 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80- 89 */ | ||
| 2753 | 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, /* 90- 99 */ | ||
| 2754 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */ | ||
| 2755 | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */ | ||
| 2756 | 49, 50, 51, -1, -1, -1, -1, -1 /* 120-127 */ | ||
| 2757 | }; | ||
| 2758 | |||
| 2759 | /* The following diagram shows the logical steps by which three octets | ||
| 2760 | get transformed into four base64 characters. | ||
| 2761 | |||
| 2762 | .--------. .--------. .--------. | ||
| 2763 | |aaaaaabb| |bbbbcccc| |ccdddddd| | ||
| 2764 | `--------' `--------' `--------' | ||
| 2765 | 6 2 4 4 2 6 | ||
| 2766 | .--------+--------+--------+--------. | ||
| 2767 | |00aaaaaa|00bbbbbb|00cccccc|00dddddd| | ||
| 2768 | `--------+--------+--------+--------' | ||
| 2769 | |||
| 2770 | .--------+--------+--------+--------. | ||
| 2771 | |AAAAAAAA|BBBBBBBB|CCCCCCCC|DDDDDDDD| | ||
| 2772 | `--------+--------+--------+--------' | ||
| 2773 | |||
| 2774 | The octets are divided into 6 bit chunks, which are then encoded into | ||
| 2775 | base64 characters. */ | ||
| 2776 | |||
| 2777 | |||
| 2778 | static int base64_encode_1 P_ ((const char *, char *, int, int)); | ||
| 2779 | static int base64_decode_1 P_ ((const char *, char *, int)); | ||
| 2780 | |||
| 2781 | DEFUN ("base64-encode-region", Fbase64_encode_region, Sbase64_encode_region, | ||
| 2782 | 2, 3, "r", | ||
| 2783 | "base64 encode the region between BEG and END.\n\ | ||
| 2784 | Return the length of the encoded text. | ||
| 2785 | Optional third argument NO-LINE-BREAK means do not break long lines\n\ | ||
| 2786 | into shorter lines.") | ||
| 2787 | (beg, end, no_line_break) | ||
| 2788 | Lisp_Object beg, end, no_line_break; | ||
| 2789 | { | ||
| 2790 | char *encoded; | ||
| 2791 | int allength, length; | ||
| 2792 | int ibeg, iend, encoded_length; | ||
| 2793 | int old_pos = PT; | ||
| 2794 | |||
| 2795 | validate_region (&beg, &end); | ||
| 2796 | |||
| 2797 | ibeg = CHAR_TO_BYTE (XFASTINT (beg)); | ||
| 2798 | iend = CHAR_TO_BYTE (XFASTINT (end)); | ||
| 2799 | move_gap_both (XFASTINT (beg), ibeg); | ||
| 2800 | |||
| 2801 | /* We need to allocate enough room for encoding the text. | ||
| 2802 | We need 33 1/3% more space, plus a newline every 76 | ||
| 2803 | characters, and then we round up. */ | ||
| 2804 | length = iend - ibeg; | ||
| 2805 | allength = length + length/3 + 1; | ||
| 2806 | allength += allength / MIME_LINE_LENGTH + 1 + 6; | ||
| 2807 | |||
| 2808 | encoded = (char *) alloca (allength); | ||
| 2809 | encoded_length = base64_encode_1 (BYTE_POS_ADDR (ibeg), encoded, length, | ||
| 2810 | NILP (no_line_break)); | ||
| 2811 | if (encoded_length > allength) | ||
| 2812 | abort (); | ||
| 2813 | |||
| 2814 | /* Now we have encoded the region, so we insert the new contents | ||
| 2815 | and delete the old. (Insert first in order to preserve markers.) */ | ||
| 2816 | SET_PT (beg); | ||
| 2817 | insert (encoded, encoded_length); | ||
| 2818 | del_range_byte (ibeg + encoded_length, iend + encoded_length, 1); | ||
| 2819 | |||
| 2820 | /* If point was outside of the region, restore it exactly; else just | ||
| 2821 | move to the beginning of the region. */ | ||
| 2822 | if (old_pos >= XFASTINT (end)) | ||
| 2823 | old_pos += encoded_length - (XFASTINT (end) - XFASTINT (beg)); | ||
| 2824 | else if (old_pos > beg) | ||
| 2825 | old_pos = beg; | ||
| 2826 | SET_PT (old_pos); | ||
| 2827 | |||
| 2828 | /* We return the length of the encoded text. */ | ||
| 2829 | return make_number (encoded_length); | ||
| 2830 | } | ||
| 2831 | |||
| 2832 | DEFUN ("base64-encode-string", Fbase64_encode_string, Sbase64_encode_string, | ||
| 2833 | 1, 1, 0, | ||
| 2834 | "base64 encode STRING and return the result.") | ||
| 2835 | (string) | ||
| 2836 | Lisp_Object string; | ||
| 2837 | { | ||
| 2838 | int allength, length, encoded_length; | ||
| 2839 | char *encoded; | ||
| 2840 | |||
| 2841 | CHECK_STRING (string, 1); | ||
| 2842 | |||
| 2843 | length = STRING_BYTES (XSTRING (string)); | ||
| 2844 | allength = length + length/3 + 1 + 6; | ||
| 2845 | |||
| 2846 | /* We need to allocate enough room for decoding the text. */ | ||
| 2847 | encoded = (char *) alloca (allength); | ||
| 2848 | |||
| 2849 | encoded_length = base64_encode_1 (XSTRING (string)->data, | ||
| 2850 | encoded, length, 0); | ||
| 2851 | if (encoded_length > allength) | ||
| 2852 | abort (); | ||
| 2853 | |||
| 2854 | return make_unibyte_string (encoded, encoded_length); | ||
| 2855 | } | ||
| 2856 | |||
| 2857 | static int | ||
| 2858 | base64_encode_1 (from, to, length, line_break) | ||
| 2859 | const char *from; | ||
| 2860 | char *to; | ||
| 2861 | int length; | ||
| 2862 | int line_break; | ||
| 2863 | { | ||
| 2864 | int counter = 0, i = 0; | ||
| 2865 | char *e = to; | ||
| 2866 | unsigned char c; | ||
| 2867 | unsigned int value; | ||
| 2868 | |||
| 2869 | while (i < length) | ||
| 2870 | { | ||
| 2871 | c = from[i++]; | ||
| 2872 | |||
| 2873 | /* Wrap line every 76 characters. */ | ||
| 2874 | |||
| 2875 | if (line_break) | ||
| 2876 | { | ||
| 2877 | if (counter < MIME_LINE_LENGTH / 4) | ||
| 2878 | counter++; | ||
| 2879 | else | ||
| 2880 | { | ||
| 2881 | *e++ = '\n'; | ||
| 2882 | counter = 1; | ||
| 2883 | } | ||
| 2884 | } | ||
| 2885 | |||
| 2886 | /* Process first byte of a triplet. */ | ||
| 2887 | |||
| 2888 | *e++ = base64_value_to_char[0x3f & c >> 2]; | ||
| 2889 | value = (0x03 & c) << 4; | ||
| 2890 | |||
| 2891 | /* Process second byte of a triplet. */ | ||
| 2892 | |||
| 2893 | if (i == length) | ||
| 2894 | { | ||
| 2895 | *e++ = base64_value_to_char[value]; | ||
| 2896 | *e++ = '='; | ||
| 2897 | *e++ = '='; | ||
| 2898 | break; | ||
| 2899 | } | ||
| 2900 | |||
| 2901 | c = from[i++]; | ||
| 2902 | |||
| 2903 | *e++ = base64_value_to_char[value | (0x0f & c >> 4)]; | ||
| 2904 | value = (0x0f & c) << 2; | ||
| 2905 | |||
| 2906 | /* Process third byte of a triplet. */ | ||
| 2907 | |||
| 2908 | if (i == length) | ||
| 2909 | { | ||
| 2910 | *e++ = base64_value_to_char[value]; | ||
| 2911 | *e++ = '='; | ||
| 2912 | break; | ||
| 2913 | } | ||
| 2914 | |||
| 2915 | c = from[i++]; | ||
| 2916 | |||
| 2917 | *e++ = base64_value_to_char[value | (0x03 & c >> 6)]; | ||
| 2918 | *e++ = base64_value_to_char[0x3f & c]; | ||
| 2919 | } | ||
| 2920 | |||
| 2921 | /* Complete last partial line. */ | ||
| 2922 | |||
| 2923 | if (line_break) | ||
| 2924 | if (counter > 0) | ||
| 2925 | *e++ = '\n'; | ||
| 2926 | |||
| 2927 | return e - to; | ||
| 2928 | } | ||
| 2929 | |||
| 2930 | |||
| 2931 | DEFUN ("base64-decode-region", Fbase64_decode_region, Sbase64_decode_region, | ||
| 2932 | 2, 2, "r", | ||
| 2933 | "base64 decode the region between BEG and END.\n\ | ||
| 2934 | Return the length of the decoded text. | ||
| 2935 | If the region can't be decoded, return nil and don't modify the buffer.") | ||
| 2936 | (beg, end) | ||
| 2937 | Lisp_Object beg, end; | ||
| 2938 | { | ||
| 2939 | int ibeg, iend, length; | ||
| 2940 | char *decoded; | ||
| 2941 | int old_pos = PT; | ||
| 2942 | int decoded_length; | ||
| 2943 | |||
| 2944 | validate_region (&beg, &end); | ||
| 2945 | |||
| 2946 | ibeg = CHAR_TO_BYTE (XFASTINT (beg)); | ||
| 2947 | iend = CHAR_TO_BYTE (XFASTINT (end)); | ||
| 2948 | |||
| 2949 | length = iend - ibeg; | ||
| 2950 | /* We need to allocate enough room for decoding the text. */ | ||
| 2951 | decoded = (char *) alloca (length); | ||
| 2952 | |||
| 2953 | move_gap_both (XFASTINT (beg), ibeg); | ||
| 2954 | decoded_length = base64_decode_1 (BYTE_POS_ADDR (ibeg), decoded, length); | ||
| 2955 | if (decoded_length > length) | ||
| 2956 | abort (); | ||
| 2957 | |||
| 2958 | if (decoded_length < 0) | ||
| 2959 | /* The decoding wasn't possible. */ | ||
| 2960 | return Qnil; | ||
| 2961 | |||
| 2962 | /* Now we have decoded the region, so we insert the new contents | ||
| 2963 | and delete the old. (Insert first in order to preserve markers.) */ | ||
| 2964 | SET_PT (beg); | ||
| 2965 | insert (decoded, decoded_length); | ||
| 2966 | del_range_byte (ibeg + decoded_length, iend + decoded_length, 1); | ||
| 2967 | |||
| 2968 | /* If point was outside of the region, restore it exactly; else just | ||
| 2969 | move to the beginning of the region. */ | ||
| 2970 | if (old_pos >= XFASTINT (end)) | ||
| 2971 | old_pos += decoded_length - length; | ||
| 2972 | else if (old_pos > beg) | ||
| 2973 | old_pos = beg; | ||
| 2974 | SET_PT (old_pos); | ||
| 2975 | |||
| 2976 | return make_number (decoded_length); | ||
| 2977 | } | ||
| 2978 | |||
| 2979 | DEFUN ("base64-decode-string", Fbase64_decode_string, Sbase64_decode_string, | ||
| 2980 | 1, 1, 0, | ||
| 2981 | "base64 decode STRING and return the result.") | ||
| 2982 | (string) | ||
| 2983 | Lisp_Object string; | ||
| 2984 | { | ||
| 2985 | char *decoded; | ||
| 2986 | int length, decoded_length; | ||
| 2987 | |||
| 2988 | CHECK_STRING (string, 1); | ||
| 2989 | |||
| 2990 | length = STRING_BYTES (XSTRING (string)); | ||
| 2991 | /* We need to allocate enough room for decoding the text. */ | ||
| 2992 | decoded = (char *) alloca (length); | ||
| 2993 | |||
| 2994 | decoded_length = base64_decode_1 (XSTRING (string)->data, decoded, length); | ||
| 2995 | if (decoded_length > length) | ||
| 2996 | abort (); | ||
| 2997 | |||
| 2998 | if (decoded_length < 0) | ||
| 2999 | return Qnil; | ||
| 3000 | |||
| 3001 | return make_string (decoded, decoded_length); | ||
| 3002 | } | ||
| 3003 | |||
| 3004 | static int | ||
| 3005 | base64_decode_1 (from, to, length) | ||
| 3006 | const char *from; | ||
| 3007 | char *to; | ||
| 3008 | int length; | ||
| 3009 | { | ||
| 3010 | int counter = 0, i = 0; | ||
| 3011 | char *e = to; | ||
| 3012 | unsigned char c; | ||
| 3013 | unsigned long value; | ||
| 3014 | |||
| 3015 | while (i < length) | ||
| 3016 | { | ||
| 3017 | /* Accept wrapping lines, reversibly if at each 76 characters. */ | ||
| 3018 | |||
| 3019 | c = from[i++]; | ||
| 3020 | if (c == '\n') | ||
| 3021 | { | ||
| 3022 | if (i == length) | ||
| 3023 | break; | ||
| 3024 | c = from[i++]; | ||
| 3025 | if (i == length) | ||
| 3026 | break; | ||
| 3027 | if (counter != MIME_LINE_LENGTH / 4) | ||
| 3028 | return -1; | ||
| 3029 | counter = 1; | ||
| 3030 | } | ||
| 3031 | else | ||
| 3032 | counter++; | ||
| 3033 | |||
| 3034 | /* Process first byte of a quadruplet. */ | ||
| 3035 | |||
| 3036 | if (!IS_BASE64 (c)) | ||
| 3037 | return -1; | ||
| 3038 | value = base64_char_to_value[c] << 18; | ||
| 3039 | |||
| 3040 | /* Process second byte of a quadruplet. */ | ||
| 3041 | |||
| 3042 | if (i == length) | ||
| 3043 | return -1; | ||
| 3044 | c = from[i++]; | ||
| 3045 | |||
| 3046 | if (!IS_BASE64 (c)) | ||
| 3047 | return -1; | ||
| 3048 | value |= base64_char_to_value[c] << 12; | ||
| 3049 | |||
| 3050 | *e++ = (unsigned char) (value >> 16); | ||
| 3051 | |||
| 3052 | /* Process third byte of a quadruplet. */ | ||
| 3053 | |||
| 3054 | if (i == length) | ||
| 3055 | return -1; | ||
| 3056 | c = from[i++]; | ||
| 3057 | |||
| 3058 | if (c == '=') | ||
| 3059 | { | ||
| 3060 | c = from[i++]; | ||
| 3061 | if (c != '=') | ||
| 3062 | return -1; | ||
| 3063 | continue; | ||
| 3064 | } | ||
| 3065 | |||
| 3066 | if (!IS_BASE64 (c)) | ||
| 3067 | return -1; | ||
| 3068 | value |= base64_char_to_value[c] << 6; | ||
| 3069 | |||
| 3070 | *e++ = (unsigned char) (0xff & value >> 8); | ||
| 3071 | |||
| 3072 | /* Process fourth byte of a quadruplet. */ | ||
| 3073 | |||
| 3074 | if (i == length) | ||
| 3075 | return -1; | ||
| 3076 | c = from[i++]; | ||
| 3077 | |||
| 3078 | if (c == '=') | ||
| 3079 | continue; | ||
| 3080 | |||
| 3081 | if (!IS_BASE64 (c)) | ||
| 3082 | return -1; | ||
| 3083 | value |= base64_char_to_value[c]; | ||
| 3084 | |||
| 3085 | *e++ = (unsigned char) (0xff & value); | ||
| 3086 | } | ||
| 3087 | |||
| 3088 | return e - to; | ||
| 3089 | } | ||
| 3090 | |||
| 2719 | void | 3091 | void |
| 2720 | syms_of_fns () | 3092 | syms_of_fns () |
| 2721 | { | 3093 | { |
| @@ -2808,4 +3180,8 @@ invoked by mouse clicks and mouse menu items."); | |||
| 2808 | defsubr (&Swidget_put); | 3180 | defsubr (&Swidget_put); |
| 2809 | defsubr (&Swidget_get); | 3181 | defsubr (&Swidget_get); |
| 2810 | defsubr (&Swidget_apply); | 3182 | defsubr (&Swidget_apply); |
| 3183 | defsubr (&Sbase64_encode_region); | ||
| 3184 | defsubr (&Sbase64_decode_region); | ||
| 3185 | defsubr (&Sbase64_encode_string); | ||
| 3186 | defsubr (&Sbase64_decode_string); | ||
| 2811 | } | 3187 | } |