X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=mel-b.el;h=ad34a378d5bcf7b373488ea68f1c5ad6c923ba53;hb=4248a1b9eb6e8271990355e6393683be2a0ec54b;hp=dd59d7e6a05165d339db2e435e56b2aedb258a11;hpb=cea3b3e3aebf6721624f40f3d23bfb56f299848b;p=elisp%2Fflim.git diff --git a/mel-b.el b/mel-b.el index dd59d7e..ad34a37 100644 --- a/mel-b.el +++ b/mel-b.el @@ -27,58 +27,61 @@ ;;; Code: (require 'emu) +(require 'mime-def) ;;; @ variables ;;; -(defvar base64-external-encoder '("mmencode") - "*list of base64 encoder program name and its arguments.") +(defgroup base64 nil + "Base64 encoder/decoder" + :group 'mime) -(defvar base64-external-decoder '("mmencode" "-u") - "*list of base64 decoder program name and its arguments.") +(defcustom base64-external-encoder '("mmencode") + "*list of base64 encoder program name and its arguments." + :group 'base64 + :type '(cons (file :tag "Command")(repeat :tag "Arguments" string))) -(defvar base64-external-decoder-option-to-specify-file '("-o") - "*list of options of base64 decoder program to specify file.") +(defcustom base64-external-decoder '("mmencode" "-u") + "*list of base64 decoder program name and its arguments." + :group 'base64 + :type '(cons (file :tag "Command")(repeat :tag "Arguments" string))) -(defvar base64-internal-encoding-limit 1000 +(defcustom base64-external-decoder-option-to-specify-file '("-o") + "*list of options of base64 decoder program to specify file." + :group 'base64 + :type '(repeat :tag "Arguments" string)) + +(defcustom base64-internal-encoding-limit 1000 "*limit size to use internal base64 encoder. If size of input to encode is larger than this limit, -external encoder is called.") - -(defvar base64-internal-decoding-limit 1000 +external encoder is called." + :group 'base64 + :type '(choice (const :tag "Always use internal encoder" nil) + (integer :tag "Size"))) + +(defcustom base64-internal-decoding-limit (if (and (featurep 'xemacs) + (featurep 'mule)) + 1000 + 7600) "*limit size to use internal base64 decoder. If size of input to decode is larger than this limit, -external decoder is called.") +external decoder is called." + :group 'base64 + :type '(choice (const :tag "Always use internal decoder" nil) + (integer :tag "Size"))) -;;; @ internal base64 decoder/encoder +;;; @ internal base64 encoder ;;; based on base64 decoder by Enami Tsugutomo -;;; @@ convert from/to base64 char -;;; +(eval-and-compile + (defconst base64-characters + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + ) -(defun base64-num-to-char (n) - (cond ((eq n nil) ?=) - ((< n 26) (+ ?A n)) - ((< n 52) (+ ?a (- n 26))) - ((< n 62) (+ ?0 (- n 52))) - ((= n 62) ?+) - ((= n 63) ?/) - (t (error "not a base64 integer %d" n)))) - -(defun base64-char-to-num (c) - (cond ((and (<= ?A c) (<= c ?Z)) (- c ?A)) - ((and (<= ?a c) (<= c ?z)) (+ (- c ?a) 26)) - ((and (<= ?0 c) (<= c ?9)) (+ (- c ?0) 52)) - ((= c ?+) 62) - ((= c ?/) 63) - ((= c ?=) nil) - (t (error "not a base64 character %c" c)))) - - -;;; @@ encode/decode one base64 unit -;;; +(defmacro base64-num-to-char (n) + `(aref base64-characters ,n)) (defun base64-encode-1 (pack) (let ((a (car pack)) @@ -103,24 +106,6 @@ external decoder is called.") (base64-num-to-char (ash (logand a 3) 4))) "==") )))) -(defun base64-decode-unit (a b &optional c d) - (condition-case err - (concat - (char-to-string (logior (ash (base64-char-to-num a) 2) - (ash (setq b (base64-char-to-num b)) -4))) - (if (and c (setq c (base64-char-to-num c))) - (concat (char-to-string - (logior (ash (logand b 15) 4) (ash c -2))) - (if (and d (setq d (base64-char-to-num d))) - (char-to-string (logior (ash (logand c 3) 6) d)) - )))) - (error (message (nth 1 err)) - ""))) - - -;;; @@ base64 encoder/decoder for string -;;; - (defun base64-encode-string (string) "Encode STRING to base64, and return the result." (let ((len (length string)) @@ -149,51 +134,6 @@ external decoder is called.") )) ))) -(defun base64-internal-decode-string (string) - "Decode STRING which is encoded in base64, and return the result." - (let ((len (length string)) - (i 0) - dest) - (while (< i len) - (let ((a (aref string i))) - (setq i (1+ i)) - (unless (eq a ?\n) - (let ((b (aref string i))) - (setq i (1+ i)) - (cond - ((eq b ?\n) - ;; invalid - ) - ((>= i len) - (setq dest (concat dest (base64-decode-unit a b) )) - ) - (t - (let ((c (aref string i))) - (setq i (1+ i)) - (cond - ((eq c ?\n) - (setq dest (concat dest (base64-decode-unit a b))) - ) - ((>= i len) - (setq dest (concat dest (base64-decode-unit a b c))) - ) - (t - (let ((d (aref string i))) - (setq i (1+ i)) - (setq dest - (concat dest - (if (eq c ?\n) - (base64-decode-unit a b c) - (base64-decode-unit a b c d)))) - )))))))))) - dest)) - -(defalias 'base64-decode-string 'base64-internal-decode-string) - - -;;; @ base64 encoder/decoder for region -;;; - (defun base64-internal-encode-region (beg end) (save-excursion (save-restriction @@ -207,35 +147,121 @@ external decoder is called.") ) ))) + +;;; @ internal base64 decoder +;;; + +(defconst base64-numbers + (eval-when-compile + (let ((len (length base64-characters)) + (vec (make-vector 123 nil)) + (i 0)) + (while (< i len) + (aset vec (aref base64-characters i) i) + (setq i (1+ i))) + vec))) + +(defmacro base64-char-to-num (c) + `(aref base64-numbers ,c)) + +(defsubst base64-internal-decode (string buffer) + (let* ((len (length string)) + (i 0) + (j 0) + v1 v2 v3) + (catch 'tag + (while (< i len) + (when (prog1 (setq v1 (base64-char-to-num (aref string i))) + (setq i (1+ i))) + (setq v2 (base64-char-to-num (aref string i)) + i (1+ i) + v3 (base64-char-to-num (aref string i)) + i (1+ i)) + (aset buffer j (logior (lsh v1 2)(lsh v2 -4))) + (setq j (1+ j)) + (if v3 + (let ((v4 (base64-char-to-num (aref string i)))) + (setq i (1+ i)) + (aset buffer j (logior (lsh (logand v2 15) 4)(lsh v3 -2))) + (setq j (1+ j)) + (if v4 + (aset buffer (prog1 j (setq j (1+ j))) + (logior (lsh (logand v3 3) 6) v4)) + (throw 'tag nil) + )) + (throw 'tag nil) + )))) + (substring buffer 0 j) + )) + +(defun base64-internal-decode-string (string) + (base64-internal-decode string (make-string (length string) 0))) + +;; (defsubst base64-decode-string! (string) +;; (setq string (string-as-unibyte string)) +;; (base64-internal-decode string string)) + (defun base64-internal-decode-region (beg end) (save-excursion - (let ((str (buffer-substring beg end))) + (let ((str (string-as-unibyte (buffer-substring beg end)))) (delete-region beg end) (goto-char beg) - (insert (base64-internal-decode-string str))))) + (insert (base64-internal-decode str str))))) + +;; (defun base64-internal-decode-region2 (beg end) +;; (save-excursion +;; (let ((str (buffer-substring beg end))) +;; (delete-region beg end) +;; (goto-char beg) +;; (insert (base64-decode-string! str))))) + +;; (defun base64-internal-decode-region3 (beg end) +;; (save-excursion +;; (let ((str (buffer-substring beg end))) +;; (delete-region beg end) +;; (goto-char beg) +;; (insert (base64-internal-decode-string str))))) + + +;;; @ external encoder/decoder +;;; (defun base64-external-encode-region (beg end) (save-excursion (save-restriction (narrow-to-region beg end) - (as-binary-process (apply (function call-process-region) - beg end (car base64-external-encoder) - t t nil (cdr base64-external-encoder)) - ) + (as-binary-process + (apply (function call-process-region) + beg end (car base64-external-encoder) + t t nil (cdr base64-external-encoder))) ;; for OS/2 ;; regularize line break code (goto-char (point-min)) (while (re-search-forward "\r$" nil t) - (replace-match "") - ) + (replace-match "")) ))) (defun base64-external-decode-region (beg end) (save-excursion - (as-binary-process (apply (function call-process-region) - beg end (car base64-external-decoder) - t t nil (cdr base64-external-decoder)) - ))) + (as-binary-process + (apply (function call-process-region) + beg end (car base64-external-decoder) + t t nil (cdr base64-external-decoder))) + )) + +(defun base64-external-decode-string (string) + (with-temp-buffer + (insert string) + (as-binary-process + (apply (function call-process-region) + (point-min) (point-max) + (car base64-external-decoder) + t t nil (cdr base64-external-decoder))) + (buffer-string))) + + +;;; @ application interfaces +;;; (defun base64-encode-region (start end) "Encode current region by base64. @@ -249,8 +275,7 @@ metamail or XEmacs package)." (if (and base64-internal-encoding-limit (> (- end start) base64-internal-encoding-limit)) (base64-external-encode-region start end) - (base64-internal-encode-region start end) - )) + (base64-internal-encode-region start end))) (defun base64-decode-region (start end) "Decode current region by base64. @@ -264,12 +289,39 @@ metamail or XEmacs package)." (if (and base64-internal-decoding-limit (> (- end start) base64-internal-decoding-limit)) (base64-external-decode-region start end) - (base64-internal-decode-region start end) - )) + (base64-internal-decode-region start end))) + +(defun base64-decode-string (string) + "Decode STRING which is encoded in base64, and return the result. +This function calls internal base64 decoder if size of STRING is +smaller than `base64-internal-decoding-limit', otherwise it calls +external base64 decoder specified by `base64-external-decoder'. In +this case, you must install the program (maybe mmencode included in +metamail or XEmacs package)." + (interactive "r") + (if (and base64-internal-decoding-limit + (> (length string) base64-internal-decoding-limit)) + (base64-external-decode-string string) + (base64-internal-decode-string string))) -;;; @ base64 encoder/decoder for file -;;; +(mel-define-method-function (mime-encode-string string (nil "base64")) + 'base64-encode-string) +(mel-define-method-function (mime-decode-string string (nil "base64")) + 'base64-decode-string) +(mel-define-method-function (mime-encode-region start end (nil "base64")) + 'base64-encode-region) +(mel-define-method-function (mime-decode-region start end (nil "base64")) + 'base64-decode-region) + +(mel-define-method-function (encoded-text-encode-string string (nil "B")) + 'base64-encode-string) + +(mel-define-method encoded-text-decode-string (string (nil "B")) + (if (and (string-match B-encoded-text-regexp string) + (string= string (match-string 0 string))) + (base64-decode-string string) + (error "Invalid encoded-text %s" string))) (defun base64-insert-encoded-file (filename) "Encode contents of file FILENAME to base64, and insert the result. @@ -277,9 +329,23 @@ It calls external base64 encoder specified by `base64-external-encoder'. So you must install the program (maybe mmencode included in metamail or XEmacs package)." (interactive (list (read-file-name "Insert encoded file: "))) - (apply (function call-process) (car base64-external-encoder) - filename t nil (cdr base64-external-encoder)) - ) + (if (and base64-internal-encoding-limit + (> (nth 7 (file-attributes filename)) + base64-internal-encoding-limit)) + (apply (function call-process) (car base64-external-encoder) + filename t nil (cdr base64-external-encoder)) + (insert + (base64-encode-string + (with-temp-buffer + (set-buffer-multibyte nil) + (insert-file-contents-as-binary filename) + (buffer-string)))) + (or (bolp) + (insert "\n")) + )) + +(mel-define-method-function (mime-insert-encoded-file filename (nil "base64")) + 'base64-insert-encoded-file) (defun base64-write-decoded-region (start end filename) "Decode and write current region encoded by base64 into FILENAME. @@ -287,26 +353,29 @@ START and END are buffer positions." (interactive (list (region-beginning) (region-end) (read-file-name "Write decoded region to file: "))) - (as-binary-process - (apply (function call-process-region) - start end (car base64-external-decoder) - nil nil nil - (append (cdr base64-external-decoder) - base64-external-decoder-option-to-specify-file - (list filename)) - ))) - - + (if (and base64-internal-decoding-limit + (> (- end start) base64-internal-decoding-limit)) + (as-binary-process + (apply (function call-process-region) + start end (car base64-external-decoder) + nil nil nil + (append (cdr base64-external-decoder) + base64-external-decoder-option-to-specify-file + (list filename)))) + (let ((str (buffer-substring start end))) + (with-temp-buffer + (insert (base64-internal-decode-string str)) + (write-region-as-binary (point-min) (point-max) filename) + )))) + +(mel-define-method-function + (mime-write-decoded-region start end filename (nil "base64")) + 'base64-write-decoded-region) + + ;;; @ etc ;;; -(defun base64-encoded-length (string) - (let ((len (length string))) - (* (+ (/ len 3) - (if (= (mod len 3) 0) 0 1) - ) 4) - )) - (defun pack-sequence (seq size) "Split sequence SEQ into SIZE elements packs, and return list of packs. [mel-b; tl-seq function]"