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 }