View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2016, VU University Amsterdam
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(hash_stream,
   36          [ open_hash_stream/3,         % +OrgStream, -HashStream, +Options
   37            stream_hash/2               % +HashStream, -Hash
   38          ]).   39:- use_foreign_library(foreign(hashstream)).   40:- predicate_options(open_hash_stream/3, 3,
   41                     [ close_parent(boolean),
   42                       algorithm(oneof([md5,sha1,sha224,sha256,sha384,sha512]))
   43                     ]).   44
   45/** <module> Maintain a hash on a stream
   46
   47This library defines a filter stream that   maintains a hash of the data
   48that passes through the stream. It can be   used  to compute the hash of
   49input data while it is being processed.   This is notably interesting if
   50data is processed from a socket as it avoids the need for collecting the
   51data first in a temporary file.
   52
   53A typical processing sequence  is   illustrated  below,  where process/2
   54somehow processed the data  and  save_result/3   records  the  result as
   55obtained from `URL` with content digest `SHA256` its `Result`.
   56
   57  ```
   58      ...,
   59      http_open(URL, In0, []),
   60      open_hash_stream(In0, In, [algorithm(sha256)]),
   61      process(In, Result),
   62      stream_hash(In, SHA256),
   63      close(In),
   64      save_result(URL, SHA256, Result)
   65  ```
   66
   67This library can also be used to compute   the hash for the content of a
   68file. The advantage is that this code doesn't rely on external tools. It
   69is considerably faster for short files, but considerably slower on large
   70files because Prolog I/O  is  based   on  character  streams rather than
   71blocks.
   72
   73  ```
   74  file_hash(Algorithm, File, Hash) :-
   75      setup_call_cleanup(
   76          open(File, read, In0, [type(binary)]),
   77          setup_call_cleanup(
   78              open_hash_stream(In0, In,
   79                               [ algorithm(Algorithm),
   80                                 close_parent(false)
   81                               ]),
   82              ( setup_call_cleanup(
   83                    open_null_stream(Null),
   84                    copy_stream_data(In, Null),
   85                    close(Null)),
   86                stream_hash(In, Hash)
   87              ),
   88              close(In)),
   89          close(In0)).
   90  ```
   91
   92@see    In addition to this hash library, SWI-Prolog provides
   93        library(md5), library(sha) and hash functions through
   94        library(crypto), part of the `ssl` package.
   95*/
   96
   97%!  open_hash_stream(+OrgStream, -HashStream, +Options) is det.
   98%
   99%   Open a filter stream on  OrgStream   that  maintains a hash. The
  100%   hash can be retrieved at any  time using stream_hash/2. Provided
  101%   options:
  102%
  103%     - algorithm(+Algorithm)
  104%     One of `md5`, `sha1`, `sha224`, `sha256`, `sha384` or
  105%     `sha512`. Default is `sha1`.
  106%     - close_parent(+Bool)
  107%     If `true` (default), closing the filter stream also closes the
  108%     original (parent) stream.
  109
  110
  111%!  stream_hash(+HashStream, -Digest:atom) is det.
  112%
  113%   Unify Digest with a hash for  the   bytes  send  to or read from
  114%   HashStream. Note that  the  hash  is   computed  on  the  stream
  115%   buffers. If the stream is an output  stream, it is first flushed
  116%   and the Digest represents the hash   at the current location. If
  117%   the stream is an input stream the  Digest represents the hash of
  118%   the processed input including the already buffered data.