;;
;; LZH A series of (header,file). Headers are checksummed. No
;; interaction among members.
+;; Headers come in three flavours called level 0, 1 and 2 headers.
+;; Level 2 header is free of DOS specific restrictions and most
+;; prevalently used. Also level 1 and 2 headers consist of base
+;; and extension headers. For more details see
+;; http://homepage1.nifty.com/dangan/en/Content/Program/Java/jLHA/Notes/Notes.html
+;; http://www.osirusoft.com/joejared/lzhformat.html
;;
;; ZIP A series of (lheader,fil) followed by a "central directory"
;; which is a series of (cheader) followed by an end-of-
;; -------------------------------------------------------------------------
;; Section: Variables
-(defvar archive-subtype nil "*Symbol describing archive type.")
-(defvar archive-file-list-start nil "*Position of first contents line.")
-(defvar archive-file-list-end nil "*Position just after last contents line.")
-(defvar archive-proper-file-start nil "*Position of real archive's start.")
-(defvar archive-read-only nil "*Non-nil if the archive is read-only on disk.")
-(defvar archive-local-name nil "*Name of local copy of remote archive.")
-(defvar archive-mode-map nil "*Local keymap for archive mode listings.")
-(defvar archive-file-name-indent nil "*Column where file names start.")
+(defvar archive-subtype nil "Symbol describing archive type.")
+(defvar archive-file-list-start nil "Position of first contents line.")
+(defvar archive-file-list-end nil "Position just after last contents line.")
+(defvar archive-proper-file-start nil "Position of real archive's start.")
+(defvar archive-read-only nil "Non-nil if the archive is read-only on disk.")
+(defvar archive-local-name nil "Name of local copy of remote archive.")
+(defvar archive-mode-map nil "Local keymap for archive mode listings.")
+(defvar archive-file-name-indent nil "Column where file names start.")
-(defvar archive-remote nil "*Non-nil if the archive is outside file system.")
+(defvar archive-remote nil "Non-nil if the archive is outside file system.")
(make-variable-buffer-local 'archive-remote)
(put 'archive-remote 'permanent-local t)
(make-variable-buffer-local 'archive-member-coding-system)
(defvar archive-alternate-display nil
- "*Non-nil when alternate information is shown.")
+ "Non-nil when alternate information is shown.")
(make-variable-buffer-local 'archive-alternate-display)
(put 'archive-alternate-display 'permanent-local t)
-(defvar archive-superior-buffer nil "*In archive members, points to archive.")
+(defvar archive-superior-buffer nil "In archive members, points to archive.")
(put 'archive-superior-buffer 'permanent-local t)
-(defvar archive-subfile-mode nil "*Non-nil in archive member buffers.")
+(defvar archive-subfile-mode nil "Non-nil in archive member buffers.")
(make-variable-buffer-local 'archive-subfile-mode)
(put 'archive-subfile-mode 'permanent-local t)
+(defvar archive-file-name-coding-system nil)
+(make-variable-buffer-local 'archive-file-name-coding-system)
+(put 'archive-file-name-coding-system 'permanent-local t)
+
(defvar archive-files nil
"Vector of file descriptors.
Each descriptor is a vector of the form
;; -------------------------------------------------------------------------
;; Section: Support functions.
+(eval-when-compile
+ (defsubst byte-after (pos)
+ "Like char-after but an eight-bit char is converted to unibyte."
+ (multibyte-char-to-unibyte (char-after pos)))
+ (defsubst insert-unibyte (&rest args)
+ "Like insert but don't make unibyte string and eight-bit char multibyte."
+ (dolist (elt args)
+ (if (integerp elt)
+ (insert (if (< elt 128) elt (decode-char 'eight-bit elt)))
+ (insert (string-to-multibyte elt)))))
+ )
+
(defsubst archive-name (suffix)
(intern (concat "archive-" (symbol-name archive-subtype) "-" suffix)))
(if (stringp str)
(setq len (length str))
(setq str (buffer-substring str (+ str len))))
+ (setq str (string-as-unibyte str))
(let ((result 0)
(i 0))
(while (< i len)
(second (* 2 (logand time 31)))) ; 2 seconds resolution
(format "%02d:%02d:%02d" hour minute second)))
-;;(defun archive-unixdate (low high)
-;; "Stringify unix (LOW HIGH) date."
-;; (let ((str (current-time-string (cons high low))))
-;; (format "%s-%s-%s"
-;; (substring str 8 9)
-;; (substring str 4 7)
-;; (substring str 20 24))))
+(defun archive-unixdate (low high)
+ "Stringify unix (LOW HIGH) date."
+ (let ((str (current-time-string (cons high low))))
+ (format "%s-%s-%s"
+ (substring str 8 10)
+ (substring str 4 7)
+ (substring str 20 24))))
-;;(defun archive-unixtime (low high)
-;; "Stringify unix (LOW HIGH) time."
-;; (let ((str (current-time-string (cons high low))))
-;; (substring str 11 19)))
+(defun archive-unixtime (low high)
+ "Stringify unix (LOW HIGH) time."
+ (let ((str (current-time-string (cons high low))))
+ (substring str 11 19)))
(defun archive-get-lineno ()
(if (>= (point) archive-file-list-start)
(make-local-variable 'archive-file-list-start)
(make-local-variable 'archive-file-list-end)
(make-local-variable 'archive-file-name-indent)
+ (setq archive-file-name-coding-system
+ (or file-name-coding-system
+ default-file-name-coding-system
+ locale-coding-system))
+ (if default-enable-multibyte-characters
+ (set-buffer-multibyte 'to))
(archive-summarize nil)
(setq buffer-read-only t))))
Optional argument SHUT-UP, if non-nil, means don't print messages
when parsing the archive."
(widen)
- (set-buffer-multibyte nil)
(let (buffer-read-only)
(or shut-up
(message "Parsing archive file..."))
(apply
(function concat)
(mapcar
- (function
+ (function
(lambda (fil)
;; Using `concat' here copies the text also, so we can add
;; properties without problems.
(setq last-coding-system-used coding))
(set-buffer-modified-p nil)
(kill-local-variable 'buffer-file-coding-system)
- (after-insert-file-set-buffer-file-coding-system (- (point-max)
- (point-min))))))
+ (after-insert-file-set-coding (- (point-max) (point-min))))))
(defun archive-mouse-extract (event)
"Extract a file whose name you click on."
view-p
(string-match file-name-invalid-regexp ename)))
(buffer (get-buffer bufname))
- (just-created nil))
+ (just-created nil)
+ (file-name-coding archive-file-name-coding-system))
(if buffer
nil
(setq archive (archive-maybe-copy archive))
(make-local-variable 'local-write-file-hooks)
(add-hook 'local-write-file-hooks 'archive-write-file-member)
(setq archive-subfile-mode descr)
+ (setq archive-file-name-coding-system file-name-coding)
(if (and
(null
(let (;; We may have to encode file name arguement for
;; external programs.
(coding-system-for-write
(and enable-multibyte-characters
- file-name-coding-system))
+ archive-file-name-coding-system))
;; We read an archive member by no-conversion at
;; first, then decode appropriately by calling
;; archive-set-buffer-as-visiting-file later.
(if (aref descr 3)
;; Set the file modes, but make sure we can read it.
(set-file-modes tmpfile (logior ?\400 (aref descr 3))))
- (if enable-multibyte-characters
- (setq ename
- (encode-coding-string ename file-name-coding-system)))
- (let ((exitcode (apply 'call-process
- (car command)
- nil
- nil
- nil
- (append (cdr command) (list archive ename)))))
+ (setq ename
+ (encode-coding-string ename archive-file-name-coding-system))
+ (let* ((coding-system-for-write 'no-conversion)
+ (exitcode (apply 'call-process
+ (car command)
+ nil
+ nil
+ nil
+ (append (cdr command)
+ (list archive ename)))))
(if (equal exitcode 0)
nil
(error "Updating was unsuccessful (%S)" exitcode))))
(if (fboundp func)
(progn
(funcall func (buffer-file-name)
- (if enable-multibyte-characters
- (encode-coding-string newname file-name-coding-system)
- newname)
+ (encode-coding-string newname
+ archive-file-name-coding-system)
descr)
(archive-resummarize))
(error "Renaming is not supported for this archive type"))))
(setq archive-files nil)
(let ((revert-buffer-function nil)
(coding-system-for-read 'no-conversion))
- (set-buffer-multibyte nil)
(revert-buffer t t))
(archive-mode)
(goto-char archive-file-list-start)
files
visual)
(while (and (< (+ p 29) (point-max))
- (= (char-after p) ?\C-z)
- (> (char-after (1+ p)) 0))
+ (= (byte-after p) ?\C-z)
+ (> (byte-after (1+ p)) 0))
(let* ((namefld (buffer-substring (+ p 2) (+ p 2 13)))
(fnlen (or (string-match "\0" namefld) 13))
- (efnname (substring namefld 0 fnlen))
+ (efnname (decode-coding-string (substring namefld 0 fnlen)
+ archive-file-name-coding-system))
(csize (archive-l-e (+ p 15) 4))
(moddate (archive-l-e (+ p 19) 2))
(modtime (archive-l-e (+ p 21) 2))
(save-restriction
(save-excursion
(widen)
- (set-buffer-multibyte nil)
(goto-char (+ archive-proper-file-start (aref descr 4) 2))
(delete-char 13)
- (insert name)))))
+ (insert-unibyte name)))))
;; -------------------------------------------------------------------------
;; Section: Lzh Archives
(maxlen 8)
files
visual)
- (while (progn (goto-char p)
+ (while (progn (goto-char p) ;beginning of a base header.
(looking-at "\\(.\\|\n\\)\\(.\\|\n\\)-l[hz][0-9ds]-"))
- (let* ((hsize (char-after p))
- (csize (archive-l-e (+ p 7) 4))
- (ucsize (archive-l-e (+ p 11) 4))
- (modtime (archive-l-e (+ p 15) 2))
- (moddate (archive-l-e (+ p 17) 2))
- (hdrlvl (char-after (+ p 20)))
- (fnlen (char-after (+ p 21)))
- (efnname (let ((str (buffer-substring (+ p 22) (+ p 22 fnlen))))
- (if file-name-coding-system
- (decode-coding-string str file-name-coding-system)
- (string-as-multibyte str))))
- (fiddle (string= efnname (upcase efnname)))
- (ifnname (if fiddle (downcase efnname) efnname))
- (width (string-width ifnname))
- (p2 (+ p 22 fnlen))
- (creator (if (>= (- hsize fnlen) 24) (char-after (+ p2 2)) 0))
+ (let* ((hsize (byte-after p)) ;size of the base header (level 0 and 1)
+ (csize (archive-l-e (+ p 7) 4)) ;size of a compressed file to follow (level 0 and 2),
+ ;size of extended headers + the compressed file to follow (level 1).
+ (ucsize (archive-l-e (+ p 11) 4)) ;size of an uncompressed file.
+ (time1 (archive-l-e (+ p 15) 2)) ;date/time (MSDOS format in level 0, 1 headers
+ (time2 (archive-l-e (+ p 17) 2)) ;and UNIX format in level 2 header.)
+ (hdrlvl (byte-after (+ p 20))) ;header level
+ thsize ;total header size (base + extensions)
+ fnlen efnname fiddle ifnname width p2 creator
+ neh ;beginning of next extension header (level 1 and 2)
mode modestr uid gid text dir prname
- )
- (if (= hdrlvl 0)
- (setq mode (if (= creator ?U) (archive-l-e (+ p2 8) 2) ?\666)
- uid (if (= creator ?U) (archive-l-e (+ p2 10) 2))
- gid (if (= creator ?U) (archive-l-e (+ p2 12) 2)))
- (if (= creator ?U)
- (let* ((p3 (+ p2 3))
- (hsize (archive-l-e p3 2))
- (etype (char-after (+ p3 2))))
- (while (not (= hsize 0))
+ gname uname modtime moddate)
+ (if (= hdrlvl 3) (error "can't handle lzh level 3 header type"))
+ (when (or (= hdrlvl 0) (= hdrlvl 1))
+ (setq fnlen (byte-after (+ p 21))) ;filename length
+ (setq efnname (let ((str (buffer-substring (+ p 22) (+ p 22 fnlen)))) ;filename from offset 22
+ (decode-coding-string
+ str archive-file-name-coding-system)))
+ (setq p2 (+ p 22 fnlen))) ;
+ (if (= hdrlvl 1)
+ (progn ;specific to level 1 header
+ (setq creator (if (>= (- hsize fnlen) 24) (byte-after (+ p2 2)) 0))
+ (setq neh (+ p2 3)))
+ (if (= hdrlvl 2)
+ (progn ;specific to level 2 header
+ (setq creator (byte-after (+ p 23)) )
+ (setq neh (+ p 24)))))
+ (if neh ;if level 1 or 2 we expect extension headers to follow
+ (let* ((ehsize (archive-l-e neh 2)) ;size of the extension header
+ (etype (byte-after (+ neh 2)))) ;extension type
+ (while (not (= ehsize 0))
(cond
- ((= etype 2) (let ((i (+ p3 3)))
- (while (< i (+ p3 hsize))
+ ((= etype 1) ;file name
+ (let ((i (+ neh 3)))
+ (while (< i (+ neh ehsize))
+ (setq efnname (concat efnname (char-to-string (byte-after i))))
+ (setq i (1+ i)))))
+ ((= etype 2) ;directory name
+ (let ((i (+ neh 3)))
+ (while (< i (+ neh ehsize))
(setq dir (concat dir
- (if (= (char-after i)
+ (if (= (byte-after i)
255)
"/"
(char-to-string
(char-after i)))))
(setq i (1+ i)))))
- ((= etype 80) (setq mode (archive-l-e (+ p3 3) 2)))
- ((= etype 81) (progn (setq uid (archive-l-e (+ p3 3) 2))
- (setq gid (archive-l-e (+ p3 5) 2))))
+ ((= etype 80) ;Unix file permission
+ (setq mode (archive-l-e (+ neh 3) 2)))
+ ((= etype 81) ;UNIX file group/user ID
+ (progn (setq uid (archive-l-e (+ neh 3) 2))
+ (setq gid (archive-l-e (+ neh 5) 2))))
+ ((= etype 82) ;UNIX file group name
+ (let ((i (+ neh 3)))
+ (while (< i (+ neh ehsize))
+ (setq gname (concat gname (char-to-string (char-after i))))
+ (setq i (1+ i)))))
+ ((= etype 83) ;UNIX file user name
+ (let ((i (+ neh 3)))
+ (while (< i (+ neh ehsize))
+ (setq uname (concat uname (char-to-string (char-after i))))
+ (setq i (1+ i)))))
)
- (setq p3 (+ p3 hsize))
- (setq hsize (archive-l-e p3 2))
- (setq etype (char-after (+ p3 2)))))))
+ (setq neh (+ neh ehsize))
+ (setq ehsize (archive-l-e neh 2))
+ (setq etype (byte-after (+ neh 2))))
+ ;;get total header size for level 1 and 2 headers
+ (setq thsize (- neh p))))
+ (if (= hdrlvl 0) ;total header size
+ (setq thsize hsize))
+ (setq fiddle (if efnname (string= efnname (upcase efnname))))
+ (setq ifnname (if fiddle (downcase efnname) efnname))
(setq prname (if dir (concat dir ifnname) ifnname))
+ (setq width (if prname (string-width prname) 0))
(setq modestr (if mode (archive-int-to-mode mode) "??????????"))
+ (setq moddate (if (= hdrlvl 2)
+ (archive-unixdate time1 time2) ;level 2 header in UNIX format
+ (archive-dosdate time2))) ;level 0 and 1 header in DOS format
+ (setq modtime (if (= hdrlvl 2)
+ (archive-unixtime time1 time2)
+ (archive-dostime time1)))
(setq text (if archive-alternate-display
(format " %8d %5S %5S %s"
ucsize
(format " %10s %8d %-11s %-8s %s"
modestr
ucsize
- (archive-dosdate moddate)
- (archive-dostime modtime)
- ifnname)))
+ moddate
+ modtime
+ prname)))
(setq maxlen (max maxlen width)
totalsize (+ totalsize ucsize)
visual (cons (vector text
- (- (length text) (length ifnname))
+ (- (length text) (length prname))
(length text))
visual)
files (cons (vector prname ifnname fiddle mode (1- p))
- files)
- p (+ p hsize 2 csize))))
+ files))
+ (cond ((= hdrlvl 1)
+ (setq p (+ p hsize 2 csize)))
+ ((or (= hdrlvl 2) (= hdrlvl 0))
+ (setq p (+ p thsize 2 csize))))
+ ))
(goto-char (point-min))
- (set-buffer-multibyte default-enable-multibyte-characters)
(let ((dash (concat (if archive-alternate-display
"- -------- ----- ----- "
"- ---------- -------- ----------- -------- ")
(let ((sum 0))
(while (> count 0)
(setq count (1- count)
- sum (+ sum (char-after p))
+ sum (+ sum (byte-after p))
p (1+ p)))
(logand sum 255)))
(save-restriction
(save-excursion
(widen)
- (set-buffer-multibyte nil)
(let* ((p (+ archive-proper-file-start (aref descr 4)))
- (oldhsize (char-after p))
- (oldfnlen (char-after (+ p 21)))
+ (oldhsize (byte-after p))
+ (oldfnlen (byte-after (+ p 21)))
(newfnlen (length newname))
(newhsize (+ oldhsize newfnlen (- oldfnlen)))
buffer-read-only)
(error "The file name is too long"))
(goto-char (+ p 21))
(delete-char (1+ oldfnlen))
- (insert newfnlen newname)
+ (insert-unibyte newfnlen newname)
(goto-char p)
(delete-char 2)
- (insert newhsize (archive-lzh-resum p newhsize))))))
+ (insert-unibyte newhsize (archive-lzh-resum p newhsize))))))
(defun archive-lzh-ogm (newval files errtxt ofs)
(save-restriction
(save-excursion
(widen)
- (set-buffer-multibyte nil)
(while files
(let* ((fil (car files))
(p (+ archive-proper-file-start (aref fil 4)))
- (hsize (char-after p))
- (fnlen (char-after (+ p 21)))
+ (hsize (byte-after p))
+ (fnlen (byte-after (+ p 21)))
(p2 (+ p 22 fnlen))
- (creator (if (>= (- hsize fnlen) 24) (char-after (+ p2 2)) 0))
+ (creator (if (>= (- hsize fnlen) 24) (byte-after (+ p2 2)) 0))
buffer-read-only)
(if (= creator ?U)
(progn
(setq newval (funcall newval (archive-l-e (+ p2 ofs) 2))))
(goto-char (+ p2 ofs))
(delete-char 2)
- (insert (logand newval 255) (lsh newval -8))
+ (insert-unibyte (logand newval 255) (lsh newval -8))
(goto-char (1+ p))
(delete-char 1)
- (insert (archive-lzh-resum (1+ p) hsize)))
+ (insert-unibyte (archive-lzh-resum (1+ p) hsize)))
(message "Member %s does not have %s field"
(aref fil 1) errtxt)))
(setq files (cdr files))))))
files
visual)
(while (string= "PK\001\002" (buffer-substring p (+ p 4)))
- (let* ((creator (char-after (+ p 5)))
+ (let* ((creator (byte-after (+ p 5)))
(method (archive-l-e (+ p 10) 2))
(modtime (archive-l-e (+ p 12) 2))
(moddate (archive-l-e (+ p 14) 2))
(fclen (archive-l-e (+ p 32) 2))
(lheader (archive-l-e (+ p 42) 4))
(efnname (let ((str (buffer-substring (+ p 46) (+ p 46 fnlen))))
- (if file-name-coding-system
- (decode-coding-string str file-name-coding-system)
- (string-as-multibyte str))))
+ (decode-coding-string
+ str archive-file-name-coding-system)))
(isdir (and (= ucsize 0)
(string= (file-name-nondirectory efnname) "")))
(mode (cond ((memq creator '(2 3)) ; Unix + VMS
(logior ?\444
(if isdir (logior 16384 ?\111) 0)
(if (zerop
- (logand 1 (char-after (+ p 38))))
+ (logand 1 (byte-after (+ p 38))))
?\222 0)))
(t nil)))
(modestr (if mode (archive-int-to-mode mode) "??????????"))
(save-restriction
(save-excursion
(widen)
- (set-buffer-multibyte nil)
(while files
(let* ((fil (car files))
(p (+ archive-proper-file-start (car (aref fil 4))))
- (creator (char-after (+ p 5)))
+ (creator (byte-after (+ p 5)))
(oldmode (aref fil 3))
(newval (archive-calc-mode oldmode newmode t))
buffer-read-only)
(cond ((memq creator '(2 3)) ; Unix + VMS
(goto-char (+ p 40))
(delete-char 2)
- (insert (logand newval 255) (lsh newval -8)))
+ (insert-unibyte (logand newval 255) (lsh newval -8)))
((memq creator '(0 5 6 7 10 11 15)) ; Dos etc.
(goto-char (+ p 38))
- (insert (logior (logand (char-after (point)) 254)
- (logand (logxor 1 (lsh newval -7)) 1)))
+ (insert-unibyte (logior (logand (byte-after (point)) 254)
+ (logand (logxor 1 (lsh newval -7)) 1)))
(delete-char 1))
(t (message "Don't know how to change mode for this member"))))
(setq files (cdr files))))))
(modtime (archive-l-e (+ p 16) 2))
(ucsize (archive-l-e (+ p 20) 4))
(namefld (buffer-substring (+ p 38) (+ p 38 13)))
- (dirtype (char-after (+ p 4)))
- (lfnlen (if (= dirtype 2) (char-after (+ p 56)) 0))
- (ldirlen (if (= dirtype 2) (char-after (+ p 57)) 0))
+ (dirtype (byte-after (+ p 4)))
+ (lfnlen (if (= dirtype 2) (byte-after (+ p 56)) 0))
+ (ldirlen (if (= dirtype 2) (byte-after (+ p 57)) 0))
(fnlen (or (string-match "\0" namefld) 13))
(efnname (let ((str
(concat
(buffer-substring (+ p 58)
(+ p 58 lfnlen -1))
(substring namefld 0 fnlen)))))
- (if file-name-coding-system
- (decode-coding-string str file-name-coding-system)
- (string-as-multibyte str))))
+ (decode-coding-string
+ str archive-file-name-coding-system)))
(fiddle (and (= lfnlen 0) (string= efnname (upcase efnname))))
(ifnname (if fiddle (downcase efnname) efnname))
(width (string-width ifnname))