;;AUTOLOAD: utf8-to-latin1
;;AUTODOC:  utf8-to-latin1 "converts an UTF-8 string to a latin-1"
;;(utf8-to-latin1 string &optional error-form)
;;
;;Converts the utf8 string into a ISO-8859-1 encoded one, and returns it
;;If not non 7-bit-ASCII chars were found, returns the original string without
;;doing a copy
;;If a character cannot fit in the ISO-8859-1 set, the error-form function is 
;;aplyied to the UTF-8 string and should return a string that will be inserted
;;in the result in place of the character
;;Default is to replace these chars silently by \xff chars
;;
;;e.g:
;;;; Converts buffer to latin-1, aborts if cannot decode
;;(setq buffer (utf8-to-latin1 buffer 
;;  (lambda (s) (fatal-error 1 "Non Latin-1 character UTF-8 code: %0\n" s))))

;U-00000000 - U-0000007F: 0xxxxxxx 
;U-00000080 - U-000007FF: 110xxxxx 10xxxxxx 
;U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 
;U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
;U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
;U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 

(setq utf8-to-latin1:re-7* (regcomp "^[\x01-\x7f]*"))
(setq utf8-to-latin1:re-7 (regcomp "^[\x01-\x7f]+"))
(setq utf8-to-latin1:re-hibit (regcomp "^[\xc0-\xff][\x080-\xbf]+"))
(setq utf8-to-latin1:re-utf8-2 (regcomp "^[\xc0-\xdf][\x080-\xbf]"))

(defun utf8-to-latin1 (s &optional (error-form utf8-to-latin1:default) 
    &aux
    pos
  )
  (regexec utf8-to-latin1:re-7* s)
  (if (= (length s) (setq pos (1 (get utf8-to-latin1:re-7* 0))))
    s					;string is only 7bit, return it
    (with (res (regsub utf8-to-latin1:re-7* 0)
	not-eof t)
      (while not-eof
	(if (regexec utf8-to-latin1:re-utf8-2 s pos) (progn
	    (if (utf8-to-latin1:append res
		(regsub utf8-to-latin1:re-utf8-2 0)
	      ) 
	      ()
	      (nconc res (apply error-form (list 
		    (regsub utf8-to-latin1:re-utf8-2 0)
	    ))))
	    (setq pos (1 (get utf8-to-latin1:re-utf8-2 0)))
	  )
	  (regexec utf8-to-latin1:re-7 s pos) (progn
	    (nconc res (regsub utf8-to-latin1:re-7 0))
	    (setq pos (1 (get utf8-to-latin1:re-7 0)))
	  )
	  (regexec utf8-to-latin1:re-hibit s pos) (progn
	    (nconc res (apply error-form (list 
		  (regsub utf8-to-latin1:re-hibit 0)
	    )))
	    (setq pos (1 (get utf8-to-latin1:re-hibit 0)))
	  )
	    ;;EOF
	  (setq not-eof ())
	))				;while
      res
  ))
)

(defun utf8-to-latin1:default (s) "\xff")

(defun utf8-to-latin1:append (res s)
  (if (< (0 s) 200)			;in 8-bit range
    (put res -1 (+ (* 64 (logand 3 (0 s))) (logand 63 (1 s))))
  )
)
  
;;AUTOLOAD: latin1-to-utf8
;;AUTODOC:  latin1-to-utf8 "converts an ISO-8859-1 (Latin-1) string to UTF-8"
;;(latin1-to-utf8 string)
;;
;;Converts the ISO-8859-1 string into a UTF-8 encoded one, and returns it
;;The string can be the same if it was comprised of only 7-bit ASCII chars
;;
;;e.g:
;;;; Converts buffer to UTF-8
;;(setq buffer (latin1-to-utf8 buffer)) 

(defun latin1-to-utf8 (s &aux c
  )
  (regexec utf8-to-latin1:re-7* s)
  (if (= (length s) (setq pos (1 (get utf8-to-latin1:re-7* 0))))
    s					;string is only 7bit, return it
    (with (res (regsub utf8-to-latin1:re-7* 0))
      (while (setq c (pos s))
	(if (> c 127)			;8th bit set ==> 2-byte UTF-8
	  (progn
	    (put res -1 (+ 192 (/ c 64)))
	    (put res -1 (+ 128 (mod c 64)))
	    (incf pos)
	  )
	  (regexec utf8-to-latin1:re-7* s pos) (progn
	    (nconc res (regsub utf8-to-latin1:re-7* 0))
	    (setq pos (1 (get utf8-to-latin1:re-7* 0)))
      )))
      res
)))
