home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / runtime / cpress.scm < prev    next >
Text File  |  1999-08-09  |  23KB  |  719 lines

  1. #| -*-Scheme-*-
  2.  
  3. $Id: cpress.scm,v 1.12 1999/08/09 18:26:47 cph Exp $
  4.  
  5. Copyright (c) 1992-1999 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. |#
  21.  
  22. ;;;; Data Compressor
  23.  
  24. (declare (usual-integrations))
  25.  
  26. ;; This declaration is worth up to 30% speedup
  27. (declare
  28.  (ignore-reference-traps
  29.   (set root-nodes oldest-node newest-node window-filled? byte-buffer)))
  30.  
  31. ;; This does not seem to make much difference:
  32. (declare (ignore-reference-traps (set current-pointer current-bp command-bp)))
  33.  
  34. ;;; This compression program is based on the algorithm described in
  35. ;;; "Data Compression with Finite Windows", by Edward R. Fiala and
  36. ;;; Daniel H. Greene, Xerox CSL-89-3.  A version of this paper
  37. ;;; appeared in "Communications of the Association for Computing
  38. ;;; Machinery", 32(1), 1989.
  39.  
  40. ;;; This is a one-pass lossless substitution algorithm.  The algorithm
  41. ;;; works by finding large blocks of text in the input stream and
  42. ;;; replacing them with shorter references to earlier occurrences of
  43. ;;; identical text.  In order to limit the amount of memory needed by
  44. ;;; the compressor and expander, a sliding "window" is used to
  45. ;;; remember the input stream, and "copy" references may only refer to
  46. ;;; text within that window.
  47.  
  48. ;;; The output stream of the compressor is a series of "commands", of
  49. ;;; which there are two kinds: "literal" and "copy".  A literal
  50. ;;; command specifies a sequence of bytes that appear in the input
  51. ;;; stream.  A copy command is a reference to some earlier part of the
  52. ;;; input stream, consisting of a length field and a relative pointer
  53. ;;; to the position of the referenced text.
  54.  
  55. ;;; Fiala and Greene describe five algorithms, which they name A1, A2,
  56. ;;; B1, B2, and C2:
  57.  
  58. ;;; A1 and B1 use a simple encoding of commands that is suitable for
  59. ;;; byte-addressed machines.  This encoding is adequate for many
  60. ;;; purposes but does not achieve the compression ratios of the other
  61. ;;; algorithms.
  62.  
  63. ;;; A2 and B2 use a more complex encoding that results in a
  64. ;;; significantly better compression ratio.  The price is that the
  65. ;;; compression and expansion are slower than that achieved with A1
  66. ;;; and B2.
  67.  
  68. ;;; C2's encoding is even more complex, and results in the best
  69. ;;; overall compression ratio.  The compression speed of C2 is the
  70. ;;; same as that of B2, and the expansion is about 25% slower.
  71.  
  72. ;;; A1 and A2 encode the relative pointers in copy commands as
  73. ;;; positions in the input byte stream.  B1 and B2 encode these
  74. ;;; pointers as positions in the output command stream, which the
  75. ;;; expander then translates back into byte positions.  The B
  76. ;;; algorithms speed up compression by approximately a factor of three
  77. ;;; over their A counterparts, while slowing expansion slightly.  The
  78. ;;; reason that compression is so much faster is that the A algorithms
  79. ;;; require much more complex data structures to keep track of the
  80. ;;; information in the window.
  81.  
  82. ;;; C2 is like B2, except that it encodes further information about
  83. ;;; the data structures it is using to represent the window, assumes
  84. ;;; that the expander reproduces those data structures, and takes
  85. ;;; advantage of that assumption to achieve shorter references.
  86.  
  87. ;;; This program implements the window data structures required by
  88. ;;; the algorithms B1, B2, and C2.  The encoder, which appears below,
  89. ;;; determines the algorithm.
  90.  
  91. (define input-port)
  92. (define output-port)
  93.  
  94. (define (compress ifile ofile)
  95.   (call-with-binary-input-file (merge-pathnames ifile)
  96.     (lambda (input)
  97.       (call-with-binary-output-file (merge-pathnames ofile)
  98.         (lambda (output)                      
  99.       (write-string "Compressed-B1-1.00" output)
  100.       (compress-ports input output))))))
  101.  
  102. (define (compress-ports input output)
  103.   (fluid-let ((root-nodes (make-vector 256 false))
  104.           (oldest-node false)
  105.           (newest-node false)
  106.           (window-filled? false)
  107.           (compress-continuation)
  108.           (byte-buffer (make-byte-buffer))
  109.           (current-pointer 0)
  110.           (current-bp 0)
  111.           (command-bp 0)
  112.           (output-buffer (make-output-buffer))
  113.           (input-port input)
  114.           (output-port output))
  115.     (call-with-current-continuation
  116.      (lambda (continuation)
  117.        (set! compress-continuation continuation)
  118.        (idle)))
  119.     (flush-output-buffer)))
  120.  
  121. (define (idle)
  122.   ;; This is the top of the compression loop.  We've just emitted a
  123.   ;; command.  If the next two bytes can be matched against some text
  124.   ;; in the window, start a copy command, otherwise start a literal.
  125.   (guarantee-buffer-space 2)
  126.   (let ((node (match-first)))
  127.     (if (not node)
  128.     (generate-literal)
  129.     (let ((node (match-next node 1)))
  130.       (if (not node)
  131.           (generate-literal)
  132.           (generate-copy node 2))))))
  133.  
  134. (define (generate-literal)
  135.   (guarantee-buffer-space (fix:+ literal-max 2))
  136.   (letrec
  137.       ((loop
  138.     (lambda (nb)
  139.       (let ((node (match-first)))
  140.         (if (not node)
  141.         (continue nb)
  142.         (let ((node (match-next node 1)))
  143.           (if (not node)
  144.               (continue nb)
  145.               (let ((node (match-next node 2)))
  146.             (if (not node)
  147.                 (begin
  148.                   (unread-byte)
  149.                   (continue nb))
  150.                 (let ((nb*
  151.                    (let ((cbp current-bp)
  152.                      (nbp (node-bp node)))
  153.                      (fix:- (if (fix:< cbp nbp)
  154.                         (fix:+ cbp buffer-size)
  155.                         cbp)
  156.                         nbp))))
  157.                   (if (fix:< nb* 3)
  158.                   ;; Don't consider matches that
  159.                   ;; would result in a copy that is
  160.                   ;; copying from itself.
  161.                   (begin
  162.                     (unread-bytes 2)
  163.                     (continue nb))
  164.                   (begin
  165.                     (write-literal nb)
  166.                     (generate-copy node 3))))))))))))
  167.        (continue
  168.     (lambda (nb)
  169.       (increment-current-pointer)
  170.       (increment-bp)
  171.       (let ((nb (fix:+ nb 1)))
  172.         (if (fix:< nb literal-max)
  173.         (loop nb)
  174.         (begin
  175.           (write-literal nb)
  176.           (idle)))))))
  177.     (increment-current-pointer)
  178.     (increment-bp)
  179.     (loop 1)))
  180.  
  181. (define (generate-copy node nb)
  182.   (guarantee-buffer-space copy-max)
  183.   (let ((copy-pointer current-pointer))
  184.     (let ((finish
  185.        (lambda (nb pointer bp)
  186.          (let ((nb*
  187.             (fix:- (let ((bp* command-bp))
  188.                  (if (fix:< bp* bp)
  189.                  (fix:+ bp* buffer-size)
  190.                  bp*))
  191.                bp))
  192.            (do-copy
  193.             (lambda (nb)
  194.               (write-copy nb pointer copy-pointer)
  195.               (increment-current-pointer)
  196.               (idle))))
  197.            ;; NB is the number of bytes that we want to write a
  198.            ;; copy command for; NB* is the number of bytes between
  199.            ;; the start of the copy and the current position.  If
  200.            ;; NB* is less than NB, we must truncate the copy in
  201.            ;; order to prevent it from copying from itself.  If
  202.            ;; NB* is 1, then don't copy -- it's too short.
  203.            (if (fix:<= nb nb*)
  204.            (do-copy nb)
  205.            (begin
  206.              (unread-bytes (fix:- nb nb*))
  207.              (if (fix:= nb* 1)
  208.              (generate-literal)
  209.              (do-copy nb*))))))))
  210.       (let loop ((node node) (nb nb))
  211.     (let ((pointer (node-pointer node))
  212.           (bp (node-bp node)))
  213.       (if (not (byte-ready?))
  214.           (finish nb pointer bp)
  215.           (let ((node* (match-next node nb)))
  216.         (if (not node*)
  217.             (finish nb pointer bp)
  218.             (let ((nb (fix:+ nb 1)))
  219.               (if (fix:< nb copy-max)
  220.               (loop node* nb)
  221.               (if (eq? node node*)
  222.                   (finish nb pointer bp)
  223.                   (let ((pointer (node-pointer node*))
  224.                     (bp (node-bp node*)))
  225.                 (update-node-pointer node*)
  226.                 (finish nb pointer bp)))))))))))))
  227.  
  228. (define (match-first)
  229.   (let ((byte (read-byte)))
  230.     (let ((node (vector-ref root-nodes byte)))
  231.       (if (not node)
  232.       (add-child false byte (make-node 0)))
  233.       node)))
  234.  
  235. (define (match-next node nb)
  236.   (let ((byte (peek-byte)))
  237.     (if (fix:= (node-nb node) nb)
  238.     (begin
  239.       (update-node-pointer node)
  240.       (let loop ((child (node-children node)))
  241.         (cond ((not child)
  242.            (add-child node byte (make-node 0))
  243.            false)
  244.           ((fix:= byte (node-byte child))
  245.            (discard-byte)
  246.            child)
  247.           (else
  248.            (loop (node-next child))))))
  249.     (let ((byte* (node-ref node nb)))
  250.       (if (fix:= byte byte*)
  251.           (begin
  252.         (discard-byte)
  253.         node)
  254.           (begin
  255.         (let ((parent (make-node nb)))
  256.           (replace-child node parent)
  257.           (add-child parent byte* node)
  258.           (add-child parent byte (make-node 0)))
  259.         false))))))
  260.  
  261. ;;;; PATRICIA Tree Database
  262.  
  263. (define root-nodes)
  264. (define oldest-node)
  265. (define newest-node)
  266. (define window-filled?)
  267.  
  268. (define-structure (node (constructor %make-node (nb older)))
  269.   ;; The parent of this node, or #F for a root node.
  270.   (parent false)
  271.  
  272.   ;; The children of this node.  Either #F for no children, or the
  273.   ;; first child.  The remaining children are accessed through the
  274.   ;; NODE-NEXT fields.  A node will never have exactly one child.
  275.   (children false)
  276.  
  277.   ;; The adjacent siblings of this node, or #F if none.
  278.   (previous false)
  279.   (next false)
  280.  
  281.   ;; The first byte of the substring between the parent and this node.
  282.   (byte false)
  283.  
  284.   ;; The number of bytes in the string represented by this node,
  285.   ;; counting down from the root of the tree.
  286.   (nb 0)
  287.  
  288.   ;; The adjacent nodes in the node pointer ordering.  The OLDER node
  289.   ;; has less recent POINTER and BP, while the newer node has more recent.
  290.   (older false)
  291.   (newer false)
  292.  
  293.   ;; The command pointer for this node.
  294.   (pointer current-pointer)
  295.  
  296.   ;; The byte pointer for this node.
  297.   (bp current-bp))
  298.  
  299. (define (make-node nb)
  300.   (let ((node (%make-node nb newest-node)))
  301.     (if newest-node
  302.     (set-node-newer! newest-node node)
  303.     (set! oldest-node node))
  304.     (set! newest-node node)
  305.     node))
  306.  
  307. (define (update-node-pointer node)
  308.   (set-node-pointer! node current-pointer)
  309.   (set-node-bp! node current-bp)
  310.   (let ((older (node-older node))
  311.     (newer (node-newer node)))
  312.     (if newer
  313.     (begin
  314.       (set-node-older! newer older)
  315.       (if older
  316.           (set-node-newer! older newer)
  317.           (set! oldest-node newer))
  318.       (set-node-newer! node false)
  319.       (set-node-older! node newest-node)
  320.       (set-node-newer! newest-node node)
  321.       (set! newest-node node)
  322.       unspecific))))
  323.  
  324. (define (add-child parent byte child)
  325.   (set-node-parent! child parent)
  326.   (set-node-byte! child byte)
  327.   (if parent
  328.       (let ((sibling (node-children parent)))
  329.     (set-node-next! child sibling)
  330.     (if sibling (set-node-previous! sibling child))
  331.     (set-node-children! parent child))
  332.       (vector-set! root-nodes byte child)))
  333.  
  334. (define (replace-child child child*)
  335.   (let ((parent (node-parent child))
  336.     (byte (node-byte child)))
  337.     (set-node-parent! child* parent)
  338.     (set-node-byte! child* byte)
  339.     (if parent
  340.     (begin
  341.       (let ((previous (node-previous child)))
  342.         (set-node-previous! child* previous)
  343.         (if previous
  344.         (set-node-next! previous child*)
  345.         (set-node-children! parent child*)))
  346.       (let ((next (node-next child)))
  347.         (set-node-next! child* next)
  348.         (if next
  349.         (set-node-previous! next child*))))
  350.     (vector-set! root-nodes byte child*))))
  351.  
  352. (define (set-oldest-node node pointer)
  353.   (let ((node
  354.      (do ((node node (node-newer node)))
  355.          ((not (fix:= (node-pointer node) pointer)) node))))
  356.     (if (not (eq? node oldest-node))
  357.     (let ((older (node-older node)))
  358.       (set-node-older! node false)
  359.       (set! oldest-node node)
  360.       ;; We don't have to do anything complicated to delete a node.
  361.       ;; If the node has any children, we know that they are also
  362.       ;; being deleted, because a descendant cannot be newer than
  363.       ;; its ancestor.  However, we want to avoid deleting a child
  364.       ;; from its parent if the parent is also going to be deleted,
  365.       ;; so we first mark each of the nodes being deleted, and then
  366.       ;; only do the deletion if the parent is not marked.
  367.       (do ((node older (node-older node)))
  368.           ((not node))
  369.         (set-node-nb! node false))
  370.       (do ((node older (node-older node)))
  371.           ((not node))
  372.         (let ((parent (node-parent node)))
  373.           (cond ((not parent)
  374.              (vector-set! root-nodes (node-byte node) false))
  375.             ((node-nb parent)
  376.              (delete-child parent node))))
  377.         (set-node-nb! node true))
  378.       unspecific))))
  379.  
  380. (define (delete-child parent child)
  381.   (let ((previous (node-previous child))
  382.     (next (node-next child)))
  383.     (if next
  384.     (set-node-previous! next previous))
  385.     (if previous
  386.     (set-node-next! previous next)
  387.     (set-node-children! parent next)))
  388.   (let ((child (node-children parent)))
  389.     ;; If only one child remains, splice out PARENT.
  390.     (if (not (node-next child))
  391.     (begin
  392.       (replace-child parent child)
  393.       (let ((older (node-older parent))
  394.         (newer (node-newer parent)))
  395.         (if older
  396.         (set-node-newer! older newer))
  397.         (if newer
  398.         (set-node-older! newer older))
  399.         (if (eq? parent oldest-node)
  400.         (set! oldest-node newer))
  401.         (if (eq? parent newest-node)
  402.         (set! newest-node older))
  403.         unspecific)))))
  404.  
  405. ;;;; The Byte Buffer
  406.  
  407. ;;; Maximum number of bytes that the byte buffer can hold.
  408. ;;; The optimal size for this buffer is
  409. ;;;  (+ (* COPY-MAX POINTER-MAX) BUFFER-READ)
  410. (define-integrable buffer-size 69632)
  411. (define-integrable buffer-size-optimal? true)
  412.  
  413. ;;; When input is needed from the input port, we attempt to read this
  414. ;;; many bytes all at once.  It is assumed that BUFFER-SIZE is an
  415. ;;; integral multiple of this number.
  416. (define-integrable buffer-read 4096)
  417.  
  418. (define compress-continuation)
  419. (define byte-buffer)
  420.  
  421. (define-structure (bb (constructor make-byte-buffer ()))
  422.   (vector (make-string buffer-size) read-only true)
  423.   (ptr 0)
  424.   (end 0)
  425.   (eof? false))
  426.  
  427. (define (byte-ready?)
  428.   (let ((bb byte-buffer))
  429.     (if (fix:= (bb-ptr bb) (bb-end bb))
  430.     (guarantee-buffer-data bb true)
  431.     true)))
  432.  
  433. (define (read-byte)
  434.   ;; Get a byte from the byte buffer.  If we are reading bytes in the
  435.   ;; process of generating a copy command, NODE is the current
  436.   ;; position in the copy, otherwise it is #F.  If we encounter EOF
  437.   ;; while reading this byte, NODE is used to emit the final command.
  438.   (let ((bb byte-buffer))
  439.     (let ((byte (%peek-byte bb)))
  440.       (%discard-byte bb)
  441.       byte)))
  442.  
  443. (define (peek-byte)
  444.   (%peek-byte byte-buffer))
  445.  
  446. (define (discard-byte)
  447.   (%discard-byte byte-buffer))
  448.  
  449. (declare (integrate-operator %peek-byte %discard-byte))
  450.  
  451. (define (%peek-byte bb)
  452.   (if (fix:= (bb-ptr bb) (bb-end bb))
  453.       (guarantee-buffer-data bb false))
  454.   (vector-8b-ref (bb-vector bb) (bb-ptr bb)))
  455.  
  456. (define (%discard-byte bb)
  457.   (set-bb-ptr! bb
  458.            (if (fix:= (bb-ptr bb) (fix:- buffer-size 1))
  459.            0
  460.            (fix:+ (bb-ptr bb) 1))))
  461.  
  462. (define (unread-byte)
  463.   (let ((bb byte-buffer))
  464.     (set-bb-ptr! bb
  465.          (if (fix:= (bb-ptr bb) 0)
  466.              (fix:- buffer-size 1)
  467.              (fix:- (bb-ptr bb) 1)))))
  468.  
  469. (define (unread-bytes nb)
  470.   (let ((bb byte-buffer))
  471.     (set-bb-ptr! bb
  472.          (let ((ptr (fix:- (bb-ptr bb) nb)))
  473.            (if (fix:< ptr 0)
  474.                (fix:+ ptr buffer-size)
  475.                ptr)))))
  476.  
  477. (define (node-ref node nb)
  478.   ;; Read byte NB in the string for NODE.
  479.   (vector-8b-ref (bb-vector byte-buffer)
  480.          (let ((bp (fix:+ (node-bp node) nb)))
  481.            (if (fix:< bp buffer-size)
  482.                bp
  483.                (fix:- bp buffer-size)))))
  484.  
  485. (define (guarantee-buffer-data bb probe?)
  486.   ;; We have read all of the bytes in the buffer, so it's time to get
  487.   ;; some more.  If PROBE? is false and we're at EOF, do a non-local
  488.   ;; exit to finish the compression.  If the last read was short, that
  489.   ;; means we are now at EOF.
  490.   (if (bb-eof? bb)
  491.       (if probe?
  492.       false
  493.       (compress-finished))
  494.       (let* ((end (bb-end bb))
  495.          (end* (fix:+ end buffer-read)))
  496.     ;; Calls to GUARANTEE-BUFFER-SPACE make sure that this read will
  497.     ;; not overwrite any data that we are still using.  Otherwise, we
  498.     ;; might have to invalidate some nodes here, and that would
  499.     ;; consequently make the program more complicated because we
  500.     ;; couldn't be sure that any nodes we were holding were valid
  501.     ;; across a call to READ-BYTE.
  502.     (let ((nb
  503.            (input-port/read-substring! input-port
  504.                        (bb-vector bb) end end*)))
  505.       (cond ((not nb)
  506.          (error "Input port must be in blocking mode:" input-port)
  507.          false)
  508.         ((fix:= nb buffer-read)
  509.          ;; A full block was read.
  510.          (set-bb-end! bb (if (fix:= end* buffer-size) 0 end*))
  511.          true)
  512.         ((fix:= nb 0)
  513.          ;; We're at EOF.
  514.          (if probe?
  515.              (begin
  516.                (set-bb-eof?! bb true)
  517.                false)
  518.              (compress-finished)))
  519.         ((and (fix:< 0 nb) (fix:< nb buffer-read))
  520.          ;; A partial block was read, meaning that
  521.          ;; this is the last block.  Set BB-EOF? to
  522.          ;; indicate that there is no more data after
  523.          ;; this block is exhausted.
  524.          (set-bb-eof?! bb true)
  525.          (set-bb-end! bb (fix:+ end nb))
  526.          true)
  527.         (else
  528.          (error "Illegal result from read:" nb buffer-read)
  529.          false))))))
  530.  
  531. (define (compress-finished)
  532.   ;; This is called from GUARANTEE-BUFFER-DATA when EOF is
  533.   ;; encountered.  If any data remains in the buffer which has not yet
  534.   ;; been emitted as a literal or copy, it is emitted as a literal.
  535.   (let ((bp command-bp)
  536.     (ptr (bb-ptr byte-buffer)))
  537.     (if (not (fix:= ptr bp))
  538.     (let loop
  539.         ((nb (fix:- (if (fix:< bp ptr) ptr (fix:+ ptr buffer-size)) bp)))
  540.       (if (fix:<= nb literal-max)
  541.           (write-literal nb)
  542.           (begin
  543.         (write-literal literal-max)
  544.         (loop (fix:- nb literal-max)))))))
  545.   (compress-continuation unspecific))
  546.  
  547. (define (guarantee-buffer-space nb)
  548.   ;; Make sure that the byte buffer has enough space to hold NB bytes.
  549.   ;; If necessary, invalidate old commands until this is true.  If the
  550.   ;; buffer size is optimal, this is never necessary, because the
  551.   ;; buffer is big enough to hold all of the commands in the window.
  552.   (if (and (not buffer-size-optimal?)
  553.        oldest-node)
  554.       (let ((end (bb-end byte-buffer)))
  555.     (if (fix:< (let ((bp command-bp))
  556.            (fix:- (if (fix:<= bp end)
  557.                 end
  558.                 (fix:+ end buffer-size))
  559.             bp))
  560.          nb)
  561.         (let ((start (node-bp oldest-node))
  562.           (nb (if (fix:< buffer-read nb) nb buffer-read)))
  563.           (if (fix:< (fix:- (if (fix:< end start)
  564.                 start
  565.                 (fix:+ start buffer-size))
  566.                 end)
  567.                nb)
  568.           (let ((node
  569.              (let ((end
  570.                 (let ((end (fix:+ end nb)))
  571.                   (if (fix:< end buffer-size)
  572.                       end
  573.                       (fix:- end buffer-size)))))
  574.                (if (fix:< start end)
  575.                    (do ((node oldest-node (node-newer node)))
  576.                    ((not
  577.                      (let ((bp (node-bp node)))
  578.                        (and (fix:<= start bp)
  579.                         (fix:< bp end))))
  580.                     node))
  581.                    (do ((node oldest-node (node-newer node)))
  582.                    ((not
  583.                      (let ((bp (node-bp node)))
  584.                        (or (and (fix:<= start bp)
  585.                         (fix:< bp buffer-size))
  586.                        (fix:< bp end))))
  587.                     node))))))
  588.             (set-oldest-node node
  589.                      (node-pointer (node-older node))))))))))
  590.  
  591. ;;;; The Encoder
  592. ;;;  This is the B1 encoder of Fiala and Greene.
  593.  
  594. ;;; Maximum length of a literal.
  595. (define-integrable literal-max 16)
  596.  
  597. ;;; Maximum length of a copy.
  598. (define-integrable copy-max 16)
  599.  
  600. ;;; Maximum displacement of a copy, in "pointers".  Consequently, this
  601. ;;; is the size of the compression window in pointers.
  602. (define-integrable pointer-max 4096)
  603.  
  604. ;;; Current "pointer" in input stream.  The pointer is updated at each
  605. ;;; literal character and copy command.
  606. (define current-pointer)
  607.  
  608. ;;; Starting position of current command in byte buffer.
  609. (define current-bp)
  610. (define command-bp)
  611.  
  612. (define (write-literal nb)
  613.   ;; Output a literal command of length NB, which is greater than zero
  614.   ;; and at most LITERAL-MAX.
  615.   (write-byte (fix:- nb 1))
  616.   (let ((string (bb-vector byte-buffer))
  617.     (start command-bp))
  618.     (let ((end (fix:+ start nb)))
  619.       (if (fix:<= end buffer-size)
  620.       (begin
  621.         (write-bytes string start end)
  622.         (set! command-bp (if (fix:= end buffer-size) 0 end)))
  623.       (let ((end (fix:- end buffer-size)))
  624.         (write-bytes string start buffer-size)
  625.         (write-bytes string 0 end)
  626.         (set! command-bp end)))))
  627.   unspecific)
  628.  
  629. (define (write-copy nb pointer copy-pointer)
  630.   ;; Output a copy command of length NB, which is greater than one
  631.   ;; and at most COPY-MAX.  POINTER is the pointer of the text being
  632.   ;; copied, while COPY-POINTER is the pointer of the copy command
  633.   ;; being emitted.
  634.   (let ((length (fix:* (fix:- nb 1) 16))
  635.     (displacement
  636.      (fix:- (if (fix:<= pointer copy-pointer)
  637.             copy-pointer
  638.             (fix:+ copy-pointer pointer-max))
  639.         pointer)))
  640.     (if (fix:< displacement 256)
  641.     (begin
  642.       (write-byte length)
  643.       (write-byte displacement))
  644.     (begin
  645.       (write-byte (fix:+ length (fix:quotient displacement 256)))
  646.       (write-byte (fix:remainder displacement 256)))))
  647.   (let ((bp
  648.      (let ((bp (fix:+ current-bp nb)))
  649.        (if (fix:< bp buffer-size)
  650.            bp
  651.            (fix:- bp buffer-size)))))
  652.     (set! current-bp bp)
  653.     (set! command-bp bp))
  654.   unspecific)
  655.  
  656. (define (increment-bp)
  657.   (set! current-bp
  658.     (let ((bp (fix:+ current-bp 1)))
  659.       (if (fix:= bp buffer-size)
  660.           0
  661.           bp)))
  662.   unspecific)
  663.  
  664. (define (increment-current-pointer)
  665.   (let ((pointer
  666.      (let ((pointer (fix:+ current-pointer 1)))
  667.        (if (fix:= pointer pointer-max)
  668.            (begin
  669.          (set! window-filled? true)
  670.          0)
  671.            pointer))))
  672.     (set! current-pointer pointer)
  673.     ;; Invalidate any nodes that refer to the previous command with
  674.     ;; number POINTER.  If WINDOW-FILLED? is false, we haven't yet
  675.     ;; generated enough commands for such nodes to exist.
  676.     (if window-filled?
  677.     (set-oldest-node oldest-node pointer))))
  678.  
  679. (define output-buffer)
  680.  
  681. (define (make-output-buffer)
  682.   (cons 0 (make-string 4096)))
  683.  
  684. (define (write-byte byte)
  685.   (let ((ob output-buffer))
  686.     (let ((index (car ob)))
  687.       (vector-8b-set! (cdr ob) index byte)
  688.       (if (fix:= index 4095)
  689.       (begin
  690.         (output-port/write-string output-port (cdr ob))
  691.         (set-car! ob 0))
  692.       (set-car! ob (fix:+ index 1))))))
  693.  
  694. (define (write-bytes string start end)
  695.   (let ((ob output-buffer))
  696.     (let ((index (car ob)))
  697.       (let ((new-index (fix:+ index (fix:- end start))))
  698.     (if (fix:< new-index 4096)
  699.         (begin
  700.           (let ((buffer (cdr ob)))
  701.         (do ((start start (fix:+ start 1))
  702.              (index index (fix:+ index 1)))
  703.             ((fix:= start end))
  704.           (vector-8b-set! buffer index (vector-8b-ref string start))))
  705.           (set-car! ob new-index))
  706.         (do ((start start (fix:+ start 1)))
  707.         ((fix:= start end))
  708.           (write-byte (vector-8b-ref string start))))))))
  709.  
  710. (define (flush-output-buffer)
  711.   (let ((ob output-buffer))
  712.     (if (fix:< 0 (car ob))
  713.     (output-port/write-substring output-port (cdr ob) 0 (car ob))))
  714.   (output-port/flush-output output-port))
  715.  
  716. (define (uncompress ifile ofile)
  717.   (uncompress-internal ifile ofile
  718.     (lambda (message . irritants)
  719.       (error message irritants))))