cl-olefs

OLE File System tools for Common Lisp
git clone https://logand.com/git/cl-olefs.git/
Log | Files | Refs

commit 1b967f90ef1002d6cb70879e3317c2613842b53f
parent 0adf1cae1952f13267e5662743b0a255b30787c2
Author: Tomas Hlavaty <tom@logand.com>
Date:   Sun,  6 Jan 2013 18:18:57 +0100

remove clos and dependency on :trivial-gray-streams and :alexandria

Diffstat:
Mcdef.lisp | 4++--
Mcl-olefs.asd | 2--
Molefs.lisp | 549++++++++++++++++++++++++++++++++++++++-----------------------------------------
3 files changed, 263 insertions(+), 292 deletions(-)

diff --git a/cdef.lisp b/cdef.lisp @@ -40,11 +40,11 @@ (defun slot-type-read (type) (cond ((eq 'ubyte type) - `(read-byte stream)) + `(read-octet stream)) ((atom type) `(,(intern (format nil "READ-~a" type)) stream)) ((eq 'ubyte (car type)) - `(read-byte-vector stream ,(cadr type))) + `(read-octets stream ,(cadr type))) (t `(read-vector stream ,(cadr type) ',(car type) ',(intern (format nil "READ-~a" (car type))))))) diff --git a/cl-olefs.asd b/cl-olefs.asd @@ -29,11 +29,9 @@ (defsystem :cl-olefs :description "OLE File System tools for Common Lisp." - :version "" :author "Tomas Hlavaty <tom@logand.com>" :maintainer "Tomas Hlavaty <tom@logand.com>" :licence "MIT" - :depends-on (:trivial-gray-streams :alexandria) :serial t :components ((:file "package") (:file "cdef") diff --git a/olefs.lisp b/olefs.lisp @@ -22,6 +22,73 @@ (in-package :olefs) +(defmacro with-stream ((var stream) &body body) + `(let ((,var ,stream)) + (unwind-protect (progn ,@body) + (funcall ,var 'close)))) + +(defun stream-position (stream &optional newpos) + (if (functionp stream) + (funcall stream 'stream-position newpos) + (if newpos + (file-position stream newpos) + (file-position stream)))) + +(defun physical-stream-position (stream) + (if (functionp stream) + (funcall stream 'physical-stream-position) + (file-position stream))) + +(defun read-octet (stream) + (if (functionp stream) + (funcall stream 'read-octet) + (read-byte stream))) + +(defun copy-stream (in out) + (handler-case (loop (write-byte (read-octet in) out)) + (end-of-file ()))) + +(defun copy-file (in out) + (with-open-file (i in :element-type '(unsigned-byte 8)) + (with-open-file (o out + :element-type '(unsigned-byte 8) + :direction :output + :if-exists :error + :if-does-not-exist :create) + (loop + with buf = (make-array 4096 :element-type '(unsigned-byte 8)) + with n = nil + while (plusp (setq n (read-sequence buf i))) + do (write-sequence buf o :end n))))) + +(defun shorter-stream (stream size) + (let ((offset 0)) + (lambda (msg) + (assert stream) + (ecase msg + (close (setq stream nil)) + (stream-position offset) + (read-octet + (unless (< offset size) + (error 'end-of-file)) + (incf offset) + (read-octet stream)))))) + +(defun vector-stream (vector physical-stream-position) + (let ((offset 0) + (size (length vector))) + (lambda (msg) + (assert vector) + (ecase msg + (close (setq vector nil)) + (stream-position offset) + (physical-stream-position (+ offset physical-stream-position)) + (read-octet + (unless (< offset size) + (error 'end-of-file)) + (prog1 (aref vector offset) + (incf offset))))))) + ;;; MS-CFB Compound File Binary File Format (defconstant +unused-sector+ 0) @@ -40,27 +107,27 @@ :initial-element 0)) (defun read-ushort (stream) - (logior (read-byte stream) - (ash (read-byte stream) 8))) + (logior (read-octet stream) + (ash (read-octet stream) 8))) (defun read-dword (stream) - (logior (read-byte stream) - (ash (read-byte stream) 8) - (ash (read-byte stream) 16) - (ash (read-byte stream) 24))) + (logior (read-octet stream) + (ash (read-octet stream) 8) + (ash (read-octet stream) 16) + (ash (read-octet stream) 24))) (defun read-ulonglong (stream) - (logior (read-byte stream) - (ash (read-byte stream) 8) - (ash (read-byte stream) 16) - (ash (read-byte stream) 24) - (ash (read-byte stream) 32) - (ash (read-byte stream) 40) - (ash (read-byte stream) 48) - (ash (read-byte stream) 56))) + (logior (read-octet stream) + (ash (read-octet stream) 8) + (ash (read-octet stream) 16) + (ash (read-octet stream) 24) + (ash (read-octet stream) 32) + (ash (read-octet stream) 40) + (ash (read-octet stream) 48) + (ash (read-octet stream) 56))) (defun read-achar (stream) - (read-byte stream)) + (read-octet stream)) (defun read-wchar (stream) (read-ushort stream)) @@ -68,13 +135,20 @@ (defun read-filetime (stream) (read-ulonglong stream)) -(defun read-byte-vector (stream n) +(defun read-octets (stream n) (let ((x (make-array n :element-type '(unsigned-byte 8) :initial-element 0))) - (read-sequence x stream) + (if (functionp stream) + (let ((i 0)) + (handler-case (do () + ((<= n i)) + (setf (aref x i) (read-octet stream)) + (incf i)) + (end-of-file () i))) + (read-sequence x stream)) x)) (defun read-guid (stream) - (read-byte-vector stream 16)) + (read-octets stream 16)) (defun read-vector (stream n element-type reader) (let ((x (make-array n :element-type element-type :initial-element 0))) @@ -140,7 +214,7 @@ (defun seek-sector (location stream) (let ((position (location-position location))) - (assert (file-position stream position)) + (assert (stream-position stream position)) location)) (defun check-ole-header (x) @@ -160,9 +234,6 @@ (unless (plusp (ole-header.number-of-difat-sectors x)) (assert (eql #xfffffffe (ole-header.first-difat-sector-location x))))) -(defstruct (ole-file (:conc-name ole-file.)) - filename stream header difat fat directory-chain directories mfat-chain mfat) - (defun sector-chain (fat location) (labels ((rec (x) (unless (member x (list +difsect+ +fatsect+ +endofchain+ +freesect+)) @@ -223,154 +294,110 @@ (dotimes (j m) (setf (aref x (incf i)) (read-dword stream)))))) -(defun traverse-directories (ole-file callback) - (let ((d (ole-file.directories ole-file))) - (labels ((rec (n level) - (let ((e (aref d n))) - (unless (zerop (ole-entry.object-type e)) - (funcall callback e n level) - (let ((id (ole-entry.left-sibling-id e))) - (when (<= id +maxregsig+) - (rec id level))) - (let ((id (ole-entry.child-id e))) - (when (<= id +maxregsig+) - (rec id (1+ level)))) - (let ((id (ole-entry.right-sibling-id e))) - (when (<= id +maxregsig+) - (rec id level))))))) - (rec 0 0)))) - -(defun call-with-ole-file (filename fn) - (with-open-file (stream filename :element-type '(unsigned-byte 8)) - (let* ((header (read-ole-header stream)) - (difat (read-difat header stream)) - (fat (read-fat difat stream)) - (directory-chain (sector-chain - fat - (ole-header.first-directory-sector-location header))) - (directories (read-directories directory-chain stream)) - (mfat-chain (sector-chain - fat - (ole-header.first-mini-fat-sector-location header))) - (mfat (read-mfat mfat-chain stream)) - (ole-file (make-ole-file - :filename filename - :stream stream - :header header - :difat difat - :fat fat - :directory-chain directory-chain - :directories directories - :mfat-chain mfat-chain - :mfat mfat))) - ;;(describe ole-file) - (check-ole-header (ole-file.header ole-file)) - ;;(describe header) - ;;(terpri) - #+nil - (traverse-directories ole-file - (lambda (entry id level) - (declare (ignore id)) - (dotimes (i level) - (write-string " ")) - (print-ole-entry entry *standard-output*) - (terpri))) - (funcall fn ole-file)))) - -(defmacro with-ole-file ((ole-file filename) &body body) - `(call-with-ole-file ,filename (lambda (,ole-file) ,@body))) - -(defclass ole-entry-stream (trivial-gray-streams:fundamental-binary-input-stream - trivial-gray-streams:trivial-gray-stream-mixin) - ((ole-file :initarg :ole-file) - (ole-entry :initarg :ole-entry) - (offset :initform 0) - (chain) - (mchain) - (sector :initform nil) - (buffer :initform (make-array 512 :element-type '(unsigned-byte 8))) - (size))) - -(defmethod initialize-instance :after ((instance ole-entry-stream) &rest initargs) - (declare (ignore initargs)) - (with-slots (ole-file ole-entry chain mchain buffer size) instance - (let ((mini (< (ole-entry.stream-size ole-entry) - (ole-header.mini-stream-cutoff-size (ole-file.header ole-file))))) - (setq chain (let ((x (sector-chain - (ole-file.fat ole-file) - (ole-entry.starting-sector-location - (if mini - (aref (ole-file.directories ole-file) 0) - ole-entry))))) - (when x - (coerce x 'vector))) - mchain (when mini - (let ((x (sector-chain - (ole-file.mfat ole-file) - (ole-entry.starting-sector-location ole-entry)))) - (when x - (coerce x 'vector)))) - size (ole-entry.stream-size ole-entry))))) - -(defmethod trivial-gray-streams::stream-element-type ((stream ole-entry-stream)) - '(unsigned-byte 8)) - -(defmethod trivial-gray-streams:stream-file-position ((stream ole-entry-stream)) - (with-slots (offset) stream - offset)) - -(defmethod (setf trivial-gray-streams:stream-file-position) (x (stream ole-entry-stream)) - (with-slots (offset sector) stream - (setf offset x - sector nil))) - -(defmethod trivial-gray-streams:stream-read-byte ((stream ole-entry-stream)) - (values (%read-byte stream t))) - -(defun peek-byte (stream) - (values (%read-byte stream nil))) - -(defun physical-stream-position (stream) - (typecase stream - (ole-entry-stream (nth-value 1 (%read-byte stream nil))) - (t (file-position stream)))) - -(defun %read-byte (stream consumep) - ;; => :eof - ;; | (values <current-byte> - ;; <position-of-current-byte>) - ;; Advance the stream by a byte if CONSUMEP is true, except at eof. - (with-slots (ole-file ole-entry offset chain mchain sector buffer size) stream - (assert (not (minusp offset))) - (if (< offset size) - (flet ((pick (q i) - (unless (eql sector q) - (let ((ole-stream (ole-file.stream ole-file))) - (seek-sector (aref chain q) ole-stream) - (let ((n (read-sequence buffer ole-stream))) - (assert (eql 512 n)))) - (setq sector q)) - (multiple-value-prog1 - (values (aref buffer i) - (+ i (location-position (aref chain sector)))) - (when consumep - (incf offset))))) - (if mchain - (multiple-value-bind (mq mr) (floor offset 64) - (multiple-value-bind (q r) (floor (aref mchain mq) (/ 512 64)) - (pick q (+ (* r 64) mr)))) - (multiple-value-bind (q r) (floor offset 512) - (pick q r)))) - :eof))) - -(defun call-with-ole-entry-stream (stream fn) - (with-open-stream (x stream) - (funcall fn x))) - -(defmacro with-ole-entry-stream ((var ole-file ole-entry) &body body) - `(call-with-ole-entry-stream - (make-instance 'ole-entry-stream :ole-file ,ole-file :ole-entry ,ole-entry) - (lambda (,var) ,@body))) +(defun %ole-entry-stream (header fat directories mfat stream ole-entry) + (let* ((offset 0) + (mini (< (ole-entry.stream-size ole-entry) + (ole-header.mini-stream-cutoff-size header))) + (chain (let ((x (sector-chain + fat + (ole-entry.starting-sector-location + (if mini + (aref directories 0) + ole-entry))))) + (when x + (coerce x 'vector)))) + (mchain (when mini + (let ((x (sector-chain + mfat + (ole-entry.starting-sector-location ole-entry)))) + (when x + (coerce x 'vector))))) + sector + (buffer (make-array 512 :element-type '(unsigned-byte 8))) + (size (ole-entry.stream-size ole-entry))) + (lambda (msg &rest args) + (assert stream) + (flet ((next-octet (consumep) + ;; (values <current-byte> <position-of-current-byte>) + ;; Advance the stream by a byte if CONSUMEP is true, except at eof. + (assert (not (minusp offset))) + (unless (< offset size) + (error 'end-of-file)) + (flet ((pick (q i) + (unless (eql sector q) + (seek-sector (aref chain q) stream) + (let ((n (read-sequence buffer stream))) + (assert (eql 512 n))) + (setq sector q)) + (multiple-value-prog1 + (values (aref buffer i) + (+ i (location-position (aref chain sector)))) + (when consumep + (incf offset))))) + (if mchain + (multiple-value-bind (mq mr) (floor offset 64) + (multiple-value-bind (q r) (floor (aref mchain mq) (/ 512 64)) + (pick q (+ (* r 64) mr)))) + (multiple-value-bind (q r) (floor offset 512) + (pick q r)))))) + (ecase msg + (close (setq stream nil)) + (stream-position + (destructuring-bind (&optional newpos) args + (if newpos + (setf offset newpos + sector nil) + offset))) + (physical-stream-position (nth-value 1 (next-octet nil))) + (read-octet (values (next-octet t)))))))) + +(defun ole-entry-stream (ole-file entry) + (funcall ole-file 'ole-entry-stream entry)) + +(defun traverse-directories (ole-file fn) + (funcall ole-file 'traverse-directories fn)) + +(defun ole-file-stream (filename) + (let* ((stream (open filename :element-type '(unsigned-byte 8))) + (header (read-ole-header stream)) + (difat (read-difat header stream)) + (fat (read-fat difat stream)) + (directory-chain (sector-chain + fat + (ole-header.first-directory-sector-location header))) + (directories (read-directories directory-chain stream)) + (mfat-chain (sector-chain + fat + (ole-header.first-mini-fat-sector-location header))) + (mfat (read-mfat mfat-chain stream))) + (check-ole-header header) + ;;(describe header) + ;;(terpri) + (lambda (msg &rest args) + (assert stream) + (ecase msg + (close + (close stream) + (setq stream nil)) + (ole-entry-stream + (destructuring-bind (entry) args + (%ole-entry-stream header fat directories mfat stream entry))) + (traverse-directories + (destructuring-bind (fn) args + (labels ((rec (n level) + (let ((e (aref directories n))) + (unless (zerop (ole-entry.object-type e)) + (funcall fn e n level) + (let ((id (ole-entry.left-sibling-id e))) + (when (<= id +maxregsig+) + (rec id level))) + (let ((id (ole-entry.child-id e))) + (when (<= id +maxregsig+) + (rec id (1+ level)))) + (let ((id (ole-entry.right-sibling-id e))) + (when (<= id +maxregsig+) + (rec id level))))))) + (rec 0 0)))))))) (defun extract-pictures (ole-file dir html) (traverse-directories @@ -382,13 +409,14 @@ (let ((entry-name (ole-entry-name-to-string (ole-entry.name entry) (ole-entry.name-length entry)))) - (with-ole-entry-stream (in ole-file entry) + #+nil + (with-stream (in (ole-entry-stream ole-file entry)) (with-open-file (out (format nil "~a/~a" dir entry-name) :direction :output :if-does-not-exist :create :if-exists :supersede :element-type '(unsigned-byte 8)) - (alexandria:copy-stream in out))) + (copy-stream in out))) (when (equal "Pictures" entry-name) (walk-RecordHeader-tree ole-file @@ -408,13 +436,13 @@ :if-does-not-exist :create :if-exists :supersede :element-type '(unsigned-byte 8)) - (alexandria:copy-stream in out)))) + (copy-stream in out)))) (declare (ignore blip)) (when html - (format html "<p><img src=\"_~d.~(~a~)\">~%" i kind)))))))))))) + (format html "<p><img src=\"~d.~(~a~)\">~%" i kind)))))))))))) (defun extract-ole-file (filename &optional (dir "/tmp")) ;; TODO extract audio files - (with-ole-file (ole-file filename) + (with-stream (ole-file (ole-file-stream filename)) (with-open-file (html (format nil "~a/index.html" dir) :direction :output :if-does-not-exist :create @@ -447,36 +475,6 @@ ;;; MS-ODRAW Office Drawing Binary File Format -(defclass shorter-stream (trivial-gray-streams:fundamental-binary-input-stream - trivial-gray-streams:trivial-gray-stream-mixin) - ((wrap :initarg :wrap) - (size :initarg :size) - (offset :initform 0))) - -(defmethod trivial-gray-streams::stream-element-type ((stream shorter-stream)) - '(unsigned-byte 8)) - -(defmethod trivial-gray-streams:stream-file-position ((stream shorter-stream)) - (with-slots (offset) stream - offset)) - -(defmethod trivial-gray-streams:stream-read-byte ((stream shorter-stream)) - (with-slots (wrap size offset) stream - (cond - ((< offset size) - (incf offset) - (read-byte wrap)) - (t :eof)))) - -(defun call-with-shorter-stream (stream fn) - (with-open-stream (x stream) - (funcall fn x))) - -(defmacro with-shorter-stream ((var wrap size) &body body) - `(call-with-shorter-stream - (make-instance 'shorter-stream :wrap ,wrap :size ,size) - (lambda (,var) ,@body))) - (define-structure POINT () (x dword) (y dword)) @@ -509,8 +507,8 @@ (let ((x RecordHeader #+nil(read-RecordHeader stream))) (with-slots (recVer recInstance recType recLen) x (flet ((blip (ext guid2 &optional metafileHeader) - (with-shorter-stream (in stream (RecordHeader.recLen x)) - (let* ((start (file-position stream)) + (with-stream (in (shorter-stream stream (RecordHeader.recLen x))) + (let* ((start (stream-position stream)) (end (+ start (RecordHeader.recLen x))) (y (make-blip :header x @@ -520,11 +518,11 @@ (read-guid in)) :metafileHeader (if metafileHeader (read-OfficeArtMetafileHeader in) - (read-byte in))))) + (read-octet in))))) (when fn (funcall fn y in)) - (unless (eql end (file-position stream)) - (file-position stream end)) + (unless (eql end (stream-position stream)) + (stream-position stream end)) y)))) (ecase recType (#.RT_CurrentUserAtom @@ -537,18 +535,18 @@ (#.RT_UserEditAtom (assert (zerop recVer)) (assert (zerop recInstance)) - (with-shorter-stream (in stream (RecordHeader.recLen x)) + (with-stream (in (shorter-stream stream (RecordHeader.recLen x))) (list x (read-UserEditAtom in)))) (#.RT_PersistDirectoryAtom (assert (zerop recVer)) (assert (zerop recInstance)) (let ((n (RecordHeader.recLen x))) ;;(print n) - (with-shorter-stream (in stream n) + (with-stream (in (shorter-stream stream n)) (make-PersistDirectoryAtom :header x :entries (loop - for fpos = 0 then (file-position in) + for fpos = 0 then (stream-position in) while (< fpos n) collect (progn ;;(print fpos) @@ -594,14 +592,14 @@ (defun walk-RecordHeader-tree (ole-file entry fn &optional post-fn) (when entry - (with-ole-entry-stream (in ole-file entry) + (with-stream (in (ole-entry-stream ole-file entry)) (labels ((rec (level pos parents) (handler-case (loop for i from 0 - until (<= 1 pos (file-position in)) + until (<= 1 pos (stream-position in)) do (let* ((h (read-RecordHeader in)) - (start (file-position in)) + (start (stream-position in)) (end (+ start (RecordHeader.recLen h)))) (funcall fn in level i h start end parents) (if (= #xf (RecordHeader.recVer h)) @@ -610,7 +608,7 @@ (min pos end) end) (cons h parents)) - (file-position in end)) + (stream-position in end)) (when post-fn (funcall post-fn in level i h start end parents)))) (end-of-file () @@ -636,7 +634,7 @@ (enum-by-value 'RecordType (RecordHeader.recType h)))))) (defun print-RecordHeader-tree-from-ppt-file (filename) - (with-ole-file (ole-file filename) + (with-stream (ole-file (ole-file-stream filename)) (traverse-directories ole-file (lambda (entry id level) @@ -781,13 +779,13 @@ (with-output-to-string (s) (loop for j from 0 below (RecordHeader.recLen h) - do (format s "~a" (ascii-char (read-byte in)))))) + do (format s "~a" (ascii-char (read-octet in)))))) texts)) (t (out "<p>") (loop for j from 0 below (RecordHeader.recLen h) - do (out "~a" (ascii-char (read-byte in)))) + do (out "~a" (ascii-char (read-octet in)))) (out "</p>~%"))))) (#.RT_OUTLINETEXTREFATOM (let* ((index (1+ (read-dword in))) @@ -801,10 +799,10 @@ (out "<p>!!!</p>~%")))) ;; TODO RT_DOCUMENT / RT_SLIDELISTWITHTEXT / RT_TEXTBYTESATOM (#.RT_OfficeArtFOPT - (with-shorter-stream (s in (RecordHeader.recLen h)) + (with-stream (s (shorter-stream in (RecordHeader.recLen h))) (let ((len (RecordHeader.recLen h))) (loop - while (< (file-position s) len) + while (< (stream-position s) len) do (let ((opid (read-OfficeArtFOPTEOPID s)) (value (read-dword s))) ;;(out "<p>...... ~s ~s</p>~%" opid value) @@ -838,7 +836,7 @@ (return-from find-ole-entry entry)))))) (defun ppt-file-to-html-naive (filename &optional (stream *standard-output*)) - (with-ole-file (ole-file filename) + (with-stream (ole-file (ole-file-stream filename)) (let ((pictures nil)) ;;(extract-pictures ole-file dir html) ;; TODO mount olefs and traverse Pictures only once (walk-RecordHeader-tree ole-file @@ -898,7 +896,7 @@ (out "<p>") (loop for j from 0 below (RecordHeader.recLen h) - do (out "~a" (ascii-char (read-byte in)))) + do (out "~a" (ascii-char (read-octet in)))) (out "</p>~%"))))) (out "</div>~%</body>~%</html>~%")))) @@ -915,7 +913,7 @@ (setf (gethash k htab) o))))))) (defun ppt-file-to-html (filename &optional (stream *standard-output*)) - (with-ole-file (ole-file filename) + (with-stream (ole-file (ole-file-stream filename)) (let ((u (block CurrentUser (traverse-directories ole-file @@ -946,21 +944,22 @@ (declare (ignore blip)) (push (list i (- start 8) kind) pictures)))) (print (list :pictures pictures)) - (with-ole-entry-stream (in ole-file - (find-ole-entry ole-file "PowerPoint Document")) + (with-stream (in (ole-entry-stream + ole-file + (find-ole-entry ole-file "PowerPoint Document"))) (let ((htab (make-hash-table)) ;; persist oid -> fpos (first-UserEditAtom nil)) - (file-position in (CurrentUserAtom.offsetToCurrentEdit u)) + (stream-position in (CurrentUserAtom.offsetToCurrentEdit u)) (loop for e = (cadr (read-record in)) then (cadr (read-record in)) do (progn ;;(describe e) (unless first-UserEditAtom (setq first-UserEditAtom e)) - (file-position in (UserEditAtom.offsetPersistDirectory e)) + (stream-position in (UserEditAtom.offsetPersistDirectory e)) (process-PersistDirectoryAtom htab in)) until (zerop (UserEditAtom.offsetLastEdit e)) - do (file-position in (UserEditAtom.offsetLastEdit e))) + do (stream-position in (UserEditAtom.offsetLastEdit e))) ;; live PersistDirectory (let ((persist-directory nil)) (maphash (lambda (k v) (push (cons k v) persist-directory)) htab) @@ -968,40 +967,11 @@ (print persist-directory)) ;; live DocumentContainer (print (gethash (UserEditAtom.docPersistIdRef first-UserEditAtom) htab))) - #+nil(file-position in 0) + #+nil(stream-position in 0) #+nil(print (read-record in))))))) ;;; MS-DOC Word (.doc) Binary File Format -(defclass vector-stream (trivial-gray-streams:fundamental-binary-input-stream - trivial-gray-streams:trivial-gray-stream-mixin) - ((wrap :initarg :wrap) - (offset :initform 0))) - -(defmethod trivial-gray-streams::stream-element-type ((stream vector-stream)) - '(unsigned-byte 8)) - -(defmethod trivial-gray-streams:stream-file-position ((stream vector-stream)) - (with-slots (offset) stream - offset)) - -(defmethod trivial-gray-streams:stream-read-byte ((stream vector-stream)) - (with-slots (wrap offset) stream - (cond - ((< offset (length wrap)) - (prog1 (aref wrap offset) - (incf offset))) - (t :eof)))) - -(defun call-with-vector-stream (stream fn) - (with-open-stream (x stream) - (funcall fn x))) - -(defmacro with-vector-stream ((var wrap) &body body) - `(call-with-vector-stream - (make-instance 'vector-stream :wrap ,wrap) - (lambda (,var) ,@body))) - (define-structure FibBase () (wIdent ushort) (nFib ushort) @@ -1229,15 +1199,17 @@ (csw (let ((x (read-ushort stream))) (assert (= x #x0e)) x)) - (fibRgW (read-vector stream 28 '(unsigned-byte 8) 'read-byte)) + (fibRgW (read-vector stream 28 '(unsigned-byte 8) 'read-octet)) (cslw (let ((x (read-ushort stream))) (assert (= x #x16)) x)) - (fibRgLw (read-vector stream 88 '(unsigned-byte 8) 'read-byte)) + (fibRgLw (read-vector stream 88 '(unsigned-byte 8) 'read-octet)) (cbRgFcLcb (read-ushort stream)) - (fibRgFcLcbBlob (read-vector stream (* 8 cbRgFcLcb) '(unsigned-byte 8) 'read-byte)) + (fibRgFcLcbBlob-position (stream-position stream)) + (fibRgFcLcbBlob (read-vector stream (* 8 cbRgFcLcb) '(unsigned-byte 8) 'read-octet)) (cswNew (read-ushort stream)) - (fibRgCswNew (read-vector stream cswNew '(unsigned-byte 8) 'read-byte)) + (fibRgCswNew (read-vector stream cswNew '(unsigned-byte 8) 'read-octet)) + #+nil (nFib (if (zerop cswNew) (FibBase.nFib base) -1 #+nil(assert (zerop cswNew))))) ;; TODO implement this case @@ -1265,7 +1237,8 @@ :fibRgLw fibRgLw :cbRgFcLcb cbRgFcLcb :fibRgFcLcbBlob fibRgFcLcbBlob - :fibRgFcLcb (with-vector-stream (s fibRgFcLcbBlob) + :fibRgFcLcb (with-stream (s (vector-stream fibRgFcLcbBlob + fibRgFcLcbBlob-position)) (read-FibRgFcLcb97 s)) :cswNew cswNew :fibRgCswNew fibRgCswNew))) @@ -1321,7 +1294,7 @@ (defstruct PChgTabsDelClose cTabs rgdxaDel rgdxaClose) (defun read-PChgTabsDelClose (stream) - (let ((cTabs (read-byte stream))) + (let ((cTabs (read-octet stream))) (assert (<= 0 cTabs 64)) (let ((rgdxaDel (read-vector stream cTabs t 'read-ushort)) (rgdxaClose (read-vector stream cTabs t 'read-ushort))) @@ -1333,10 +1306,10 @@ (defstruct PChgTabsAdd cTabs rgdxaAdd rgtbdAdd) (defun read-PChgTabsAdd (stream) - (let ((cTabs (read-byte stream))) + (let ((cTabs (read-octet stream))) (assert (<= 0 cTabs 64)) (let ((rgdxaAdd (read-vector stream cTabs t 'read-ushort)) - (rgtbdAdd (read-vector stream cTabs t 'read-byte))) ;; TODO decode TBD struct + (rgtbdAdd (read-vector stream cTabs t 'read-octet))) ;; TODO decode TBD struct (assert (equalp rgdxaAdd (sort (copy-seq rgdxaAdd) #'<=))) (make-PChgTabsAdd :cTabs cTabs :rgdxaAdd rgdxaAdd @@ -1345,9 +1318,9 @@ (defstruct PChgTabsOperand cb DelClose Add) (defun read-PChgTabsOperand (stream) - (let ((cb (read-byte stream))) + (let ((cb (read-octet stream))) (assert (< 1 cb 255)) ;; TODO 255 - ;;(read-vector stream cb t 'read-byte) + ;;(read-vector stream cb t 'read-octet) (make-PChgTabsOperand :cb cb :DelClose (read-PChgTabsDelClose stream) :Add (read-PChgTabsAdd stream)))) @@ -1357,19 +1330,19 @@ (defun read-Prl (stream) (let ((sprm (read-Sprm stream))) ;; (when (zerop (Sprm.sgc sprm)) - ;; (print (list :@@@-!!! (read-vector stream 10 t 'read-byte)))) + ;; (print (list :@@@-!!! (read-vector stream 10 t 'read-octet)))) (assert (member (Sprm.sgc sprm) '(1 2 3 4 5))) (make-Prl :sprm sprm :operand (ecase (Sprm.spra sprm) - (0 (read-byte stream)) - (1 (read-byte stream)) + (0 (read-octet stream)) + (1 (read-octet stream)) (2 (read-ushort stream)) (3 (read-dword stream)) (4 (read-ushort stream)) (5 (read-ushort stream)) (6 (flet ((rd () - (read-vector stream (read-byte stream) t 'read-byte))) + (read-vector stream (read-octet stream) t 'read-octet))) (ecase (Sprm.sgc sprm) (1 (ecase (Sprm.flags sprm) ;; par (#xc615 (read-PChgTabsOperand stream)))) @@ -1377,9 +1350,9 @@ (3 (rd)) ;; pic (4 (rd)) ;; sec #+nil(5 )))) ;; tab - (7 (read-vector stream 3 t 'read-byte)))))) + (7 (read-vector stream 3 t 'read-octet)))))) -;;(defstruct Xst blob parsed) +(defstruct Xst blob parsed) (defun read-Xst (stream) ;;(read-vector stream (read-ushort stream) t 'read-ushort) @@ -1396,15 +1369,15 @@ ;;(describe lvlf) (make-LVL :lvlf lvlf - :grpprlPapx (read-vector stream (LVLF.cbGrpprlPapx lvlf) t 'read-byte) - :grpprlChpx (read-vector stream (LVLF.cbGrpprlChpx lvlf) t 'read-byte) + :grpprlPapx (read-vector stream (LVLF.cbGrpprlPapx lvlf) t 'read-octet) + :grpprlChpx (read-vector stream (LVLF.cbGrpprlChpx lvlf) t 'read-octet) ;; :grpprlPapx (read-vector stream (LVLF.cbGrpprlPapx lvlf) t 'read-prl) ;; :grpprlChpx (read-vector stream (LVLF.cbGrpprlChpx lvlf) t 'read-prl) :xst (read-Xst stream)))) (defun fix-numbering (filename) (let (offsets) - (with-ole-file (ole-file filename) + (with-stream (ole-file (ole-file-stream filename)) #+nil(break "~s" ole-file) (let (fcPlfLst lcbPlfLst) (block found1 @@ -1418,7 +1391,7 @@ (ole-entry.name entry) (ole-entry.name-length entry)))) (when (equal "WordDocument" entry-name) - (with-ole-entry-stream (in ole-file entry) + (with-stream (in (ole-entry-stream ole-file entry)) (let ((fib (read-fib in))) ;;(describe fib) (let ((x (fib-fibRgFcLcb fib))) @@ -1427,7 +1400,7 @@ (return-from found1) #+nil (multiple-value-bind (fcPlfLst lcbPlfLst) - (with-vector-stream (s (subseq (fib-fibRgFcLcbBlob fib) #.(* 4 146))) + (with-stream (s (vector-stream (subseq (fib-fibRgFcLcbBlob fib) #.(* 4 146)))) (values (read-dword s) (read-dword s))) (print (list :@@@ fcPlfLst lcbPlfLst)) )))))))))) @@ -1443,8 +1416,8 @@ (ole-entry.name-length entry)))) (when (or (equal "0Table" entry-name) ;; TODO be sure which one? (equal "1Table" entry-name)) - (with-ole-entry-stream (in ole-file entry) - (file-position in fcPlfLst) + (with-stream (in (ole-entry-stream ole-file entry)) + (stream-position in fcPlfLst) (let ((PlfLst (read-PlfLst in))) (let ((n 0)) (dotimes (i (length PlfLst)) @@ -1477,7 +1450,7 @@ (return-from found2)))))))) #+nil(values fcPlfLst lcbPlfLst))) (let ((fixed (format nil "~a.fixed.doc" filename))) - (alexandria:copy-file filename fixed) + (copy-file filename fixed) ;;(print (list :@@@-offsets offsets)) (with-open-file (s fixed :direction :io @@ -1485,12 +1458,12 @@ :if-does-not-exist :error :element-type '(unsigned-byte 8)) (dolist (o offsets) - (file-position s (+ 5 o)) - (let ((flags (read-byte s))) - (file-position s (+ 5 o)) + (stream-position s (+ 5 o)) + (let ((flags (read-octet s))) + (stream-position s (+ 5 o)) (write-byte (logior #x08 flags) s) #+nil(write-byte (logand #x07 flags) s)) - (file-position s (+ 26 o)) + (stream-position s (+ 26 o)) (write-byte 0 s)))))) ;;(fix-numbering "/home/hlavaty/Shared/numbering/Layout_von_Gesamt.doc")