Mercurial > emacs
comparison src/fns.c @ 23208:1abc842b1ca7
(base64_decode_1, base64_encode_1): New functions.
(Fbase64_decode_string, Fbase64_encode_string): New functions.
(Fbase64_decode_region, Fbase64_encode_region): New functions.
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Mon, 07 Sep 1998 19:58:05 +0000 |
parents | 302eccdcb73c |
children | 982f97638a8e |
comparison
equal
deleted
inserted
replaced
23207:302eccdcb73c | 23208:1abc842b1ca7 |
---|---|
2712 newargs[2] = Flist (nargs - 2, args + 2); | 2712 newargs[2] = Flist (nargs - 2, args + 2); |
2713 GCPRO2 (newargs[0], newargs[2]); | 2713 GCPRO2 (newargs[0], newargs[2]); |
2714 result = Fapply (3, newargs); | 2714 result = Fapply (3, newargs); |
2715 UNGCPRO; | 2715 UNGCPRO; |
2716 return result; | 2716 return result; |
2717 } | |
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; | |
2717 } | 3089 } |
2718 | 3090 |
2719 void | 3091 void |
2720 syms_of_fns () | 3092 syms_of_fns () |
2721 { | 3093 { |
2806 defsubr (&Sprovide); | 3178 defsubr (&Sprovide); |
2807 defsubr (&Swidget_plist_member); | 3179 defsubr (&Swidget_plist_member); |
2808 defsubr (&Swidget_put); | 3180 defsubr (&Swidget_put); |
2809 defsubr (&Swidget_get); | 3181 defsubr (&Swidget_get); |
2810 defsubr (&Swidget_apply); | 3182 defsubr (&Swidget_apply); |
2811 } | 3183 defsubr (&Sbase64_encode_region); |
3184 defsubr (&Sbase64_decode_region); | |
3185 defsubr (&Sbase64_encode_string); | |
3186 defsubr (&Sbase64_decode_string); | |
3187 } |