"Fossies" - the Fresh Open Source Software Archive

Member "tcpflow-1.6.1/src/be13_api/sbuf.h" (19 Feb 2021, 22217 Bytes) of package /linux/misc/tcpflow-1.6.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sbuf.h" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.4.5_vs_1.5.0.

    1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
    2 /*
    3  * sbuf.h:
    4  *
    5  * sbuf ("safer buffer") provides a typesafe means to
    6  * refer to binary data within the context of a C++ computer forensics
    7  * tool. The sbuf is a const buffer for which the first byte's
    8  * position is tracked in the "pos0" variable (the position of
    9  * byte[0]). The buffer may come from a disk, a disk image, or be the
   10  * result of decompressing or otherwise decoding other data.
   11  *
   12  * Created and maintained by Simson Garfinkel, 2007--2012.
   13  *
   14  * sbuf_stream is a stream-oriented interface for reading sbuf data. 
   15  */
   16  
   17 
   18 #ifndef SBUF_H
   19 #define SBUF_H
   20 
   21 #ifdef HAVE_STRING_H
   22 #include <string.h>
   23 #endif
   24 
   25 //Don't turn this on; it currently makes scan_net crash.
   26 //#define SBUF_TRACK
   27 
   28 /* required per C++ standard */
   29 #ifndef __STDC_FORMAT_MACROS
   30 #define __STDC_FORMAT_MACROS
   31 #endif
   32 
   33 #include <stdlib.h>
   34 #include <inttypes.h>
   35 #include <string>
   36 #include <sstream>
   37 #include <iostream>
   38 
   39 
   40 /****************************************************************
   41  *** pos0_t
   42  ****************************************************************/
   43 
   44 /** \addtogroup bulk_extractor_APIs
   45  * @{
   46  */
   47 /** \file */
   48 /**
   49  * \class pos0_t
   50  * The pos0_t structure is used to record the forensic path of the
   51  * first byte of an sbuf. The forensic path can include strings associated
   52  * with decompressors and ordinals associated with offsets.
   53  * 
   54  * e.g., 1000-GZIP-300-BASE64-30 means go 1000 bytes into the stream,
   55  *       unzip, go 300 bytes into the decompressed stream, un-BASE64, and
   56  *       go 30 bytes into that.
   57  * 
   58  * pos0_t uses a string to hold the base path and the offset into that path
   59  * in a 64-bit number.  
   60  */
   61 
   62 inline int64_t stoi64(std::string str)
   63 {
   64     int64_t val(0);
   65     std::istringstream ss(str);
   66     ss >> val;
   67     return val;
   68 }
   69 
   70 class pos0_t {
   71 public:
   72     const std::string path;                     /* forensic path of decoders*/
   73     const uint64_t    offset;                   /* location of buf[0] */
   74     
   75     explicit pos0_t():path(""),offset(0){}
   76     pos0_t(std::string s):path(s),offset(0){}
   77     pos0_t(std::string s,uint64_t o):path(s),offset(o){}
   78     pos0_t(const pos0_t &obj):path(obj.path),offset(obj.offset){ }
   79     std::string str() const {           // convert to a string, with offset included
   80         std::stringstream ss;
   81         if(path.size()>0){
   82             ss << path << "-";
   83         }
   84         ss << offset;
   85         return ss.str();
   86     }
   87     bool isRecursive() const {          // is there a path?
   88         return path.size() > 0;
   89     } 
   90     std::string firstPart() const {     // the first part of the path
   91         size_t p = path.find('-');
   92         if(p==std::string::npos) return std::string("");
   93         return path.substr(0,p);
   94     }
   95     std::string lastAddedPart() const { // the last part of the path, before the offset
   96         size_t p = path.rfind('-');
   97         if(p==std::string::npos) return std::string("");
   98         return path.substr(p+1);
   99     }
  100     std::string alphaPart() const {    // return the non-numeric parts, with /'s between each
  101         std::string desc;
  102         bool inalpha = false;
  103         /* Now get the std::string part of pos0 */
  104         for(std::string::const_iterator it = path.begin();it!=path.end();it++){
  105             if((*it)=='-'){
  106                 if(desc.size()>0 && desc.at(desc.size()-1)!='/') desc += '/';
  107                 inalpha=false;
  108             }
  109             if(isalpha(*it) || (inalpha && isdigit(*it))){
  110                 desc += *it;
  111                 inalpha=true;
  112             }
  113         }
  114         return desc;
  115     }
  116     uint64_t imageOffset() const {      // return the offset from start of disk
  117         if(path.size()>0) return stoi64(path);
  118         return offset;
  119     }
  120 
  121 
  122     /**
  123      * Return a new position that's been shifted by an offset
  124      */
  125     pos0_t shift(int64_t s) const {
  126         if(s==0) return *this;
  127         size_t p = path.find('-');
  128         if(p==std::string::npos){            // no path
  129             return pos0_t("",offset+s);
  130         }
  131         /* Figure out the value of the shift */
  132         int64_t baseOffset = stoi64(path.substr(0,p-1));
  133         std::stringstream ss;
  134         ss << (baseOffset+s) << path.substr(p);
  135         return pos0_t(ss.str(),offset);
  136     }
  137 };
  138 
  139 /** iostream support for the pos0_t */
  140 inline std::ostream & operator <<(std::ostream &os,const class pos0_t &pos0) {
  141     os << "(" << pos0.path << "|" << pos0.offset << ")";
  142     return os;
  143 }
  144 
  145 
  146 /** Append a string (subdir).
  147  * The current offset is a prefix to the subdir.
  148  */
  149 inline class pos0_t operator +(pos0_t pos,const std::string &subdir) {
  150     std::stringstream ss;
  151     ss << pos.path << (pos.path.size()>0 ? "-" : "") << pos.offset << "-" << subdir;
  152     return pos0_t(ss.str(),0);
  153 };
  154 
  155 /** Adding an offset */
  156 inline class pos0_t operator +(pos0_t pos,int64_t delta) {
  157     return pos0_t(pos.path,pos.offset+delta);
  158 };
  159 
  160 /** \name Comparision operations
  161  * @{
  162  */
  163 inline bool operator <(const class pos0_t &pos0,const class pos0_t & pos1)  {
  164     if(pos0.path.size()==0 && pos1.path.size()==0) return pos0.offset < pos1.offset;
  165     if(pos0.path == pos1.path) return pos0.offset < pos1.offset;
  166     return pos0.path < pos1.path;
  167 };
  168 
  169 inline bool operator >(const class pos0_t & pos0,const class pos0_t &pos1)  {
  170     if(pos0.path.size()==0 && pos1.path.size()==0) return pos0.offset > pos1.offset;
  171     if(pos0.path == pos1.path) return pos0.offset > pos1.offset;
  172     return pos0.path > pos1.path;
  173 };
  174 
  175 inline bool operator ==(const class pos0_t & pos0,const class pos0_t &pos1) {
  176     return pos0.path==pos1.path && pos0.offset==pos1.offset;
  177 };
  178 /** @} */
  179 
  180 /**
  181  * \class managed_malloc Like new[], but it automatically gets freed when the object is dropped.
  182  * throws std::bad_alloc if no memory.
  183  */
  184 template < class TYPE > class managed_malloc {
  185     // default construction, copy construction and assignment are meaningless
  186     // and not implemented
  187     managed_malloc& operator=(const managed_malloc&); 
  188     managed_malloc(const managed_malloc&);
  189     managed_malloc();
  190 public:
  191     TYPE *buf;
  192     managed_malloc(size_t bytes):buf(new TYPE[bytes]){ }
  193     ~managed_malloc(){
  194         if(buf) delete []buf;
  195     }
  196 };
  197 
  198 
  199 /**
  200  * \class sbuf_t
  201  * This class describes the search buffer.
  202  * The accessors are safe so that no buffer overflow can happen.
  203  * Integer readers may throw sbuf_bounds_exception.
  204  *
  205  * This structure actually holds the data.
  206  * We use a pos0_t to maintain the address of the first byte.
  207  *
  208  * There are lots of ways for allocating an sbuf_t:
  209  * - map from a file.
  210  * - set from a block of memory.
  211  * - a subset of an existing sbuf_t (sbuf+10 gives you 10 bytes in, and therefore 10 bytes shorter)
  212  *
  213  * The subf_t class remembers how the sbuf_t was allocated and
  214  * automatically frees whatever resources are needed when it is freed.
  215  *
  216  * \warning DANGER: You must delete sbuf_t structures First-In,
  217  * Last-out, otherwise bad things can happen. (For example, if you
  218  * make a subset sbuf_t from a mapped file and unmap the file, the
  219  * subset will now point to unallocated memory.)
  220  */
  221 class sbuf_t {
  222 private:
  223     /* The private structures keep track of memory management */
  224     int    fd;                          /* file this came from if mmapped file */
  225 public:;
  226     bool   should_unmap;                /* munmap buffer when done */
  227     bool   should_free;                 /* should buf be freed when this sbuf is deleted? */
  228     bool   should_close;                /* close(fd) when done. */
  229     static size_t min(size_t a,size_t b){
  230         return a<b ? a : b;
  231     }
  232 
  233 public:
  234     int     page_number;                /* used for debugging */
  235     pos0_t  pos0;                       /* the path of buf[0] */
  236 private:
  237     const sbuf_t  *parent;              // parent sbuf references data in another.
  238 public:
  239     mutable int   children;             // number of child sbufs; can get increment in copy
  240 public:
  241     //private:               // one day
  242     /**
  243      * \deprecated
  244      * This field will be private in a future release of \b bulk_extractor.
  245      */
  246     const uint8_t *buf;         /* start of the buffer */
  247 public:
  248      size_t  bufsize;           /* size of the buffer */
  249      size_t  pagesize;          /* page data; the rest is the 'margin'. pagesize <= bufsize */
  250     
  251 private:
  252     void release();                     // release allocated storage
  253     // default assignment not implemented
  254     sbuf_t &operator=(const sbuf_t &that);
  255 public:
  256     /** Make an empty sbuf.
  257         It's used for situations where an sbuf is needed but not referenced */
  258     explicit sbuf_t():fd(0),should_unmap(false),should_free(false),should_close(false),
  259              page_number(0),pos0(),
  260              parent(0),
  261              children(0),buf(0),bufsize(0),pagesize(0){
  262     }
  263 
  264     /****************************************************************
  265      *** Child allocators --- allocate an sbuf from another sbuf
  266      ****************************************************************/
  267 
  268     /**
  269      * Make an sbuf from a parent. 
  270      * note: don't add an 'explicit' --- it causes problems.
  271      */
  272     sbuf_t(const sbuf_t &that):
  273              fd(0),should_unmap(false),should_free(false),should_close(false),
  274              page_number(that.page_number),pos0(that.pos0),
  275              parent(that.highest_parent()),
  276              children(0),buf(that.buf),bufsize(that.bufsize),pagesize(that.pagesize){
  277         parent->add_child(*this);
  278     }
  279 
  280     /**
  281      * Make an sbuf from a parent but with a different path. 
  282      */
  283     explicit sbuf_t(const pos0_t &that_pos0, const sbuf_t &that_sbuf ):
  284         fd(0),should_unmap(false),should_free(false),should_close(false),
  285         page_number(that_sbuf.page_number),pos0(that_pos0),
  286         parent(that_sbuf.highest_parent()),children(0),
  287         buf(that_sbuf.buf),bufsize(that_sbuf.bufsize),pagesize(that_sbuf.pagesize){
  288         parent->add_child(*this);
  289     }
  290 
  291     /**
  292      * make an sbuf from a parent but with an indent.
  293      */
  294     sbuf_t(const sbuf_t &that_sbuf,size_t off):
  295         fd(0),should_unmap(false),should_free(false),should_close(false),
  296         page_number(that_sbuf.page_number),pos0(that_sbuf.pos0+off),
  297         parent(that_sbuf.highest_parent()),children(0),
  298         buf(that_sbuf.buf+off),
  299         bufsize(that_sbuf.bufsize > off ? that_sbuf.bufsize-off : 0),
  300         pagesize(that_sbuf.pagesize > off ? that_sbuf.pagesize-off : 0){
  301     }
  302 
  303     /** Allocate from an existing sbuf.
  304      * The allocated buf MUST be freed before the source, since no copy is made...
  305      */
  306     explicit sbuf_t(const sbuf_t &sbuf,size_t off,size_t len):
  307         fd(0), should_unmap(false), should_free(false), should_close(false),
  308         page_number(sbuf.page_number),pos0(sbuf.pos0+off),
  309         parent(sbuf.highest_parent()),
  310         children(0), buf(sbuf.buf+off),
  311         bufsize(off+len<sbuf.bufsize ? len : sbuf.bufsize-off),
  312         pagesize(off+len<sbuf.bufsize ? len : sbuf.bufsize-off){
  313         parent->add_child(*this);
  314     };
  315 
  316     /****************************************************************
  317      *** Allocators that allocate from memory
  318      ****************************************************************/
  319 
  320     /* Allocators */
  321     /** Allocate a new buffer of a given size for filling.
  322      * This is the one case where buf is written into...
  323      * This should probably be a subclass mutable_sbuf_t() for clarity.
  324      */
  325 
  326     /* Allocate from an existing buffer, optionally freeing that buffer */
  327     explicit sbuf_t(const pos0_t &pos0_,const uint8_t *buf_,
  328                     size_t bufsize_,size_t pagesize_,
  329                     int fd_, bool should_unmap_,bool should_free_,bool should_close_):
  330         fd(fd_), should_unmap(should_unmap_), should_free(should_free_),
  331         should_close(should_close_),
  332         page_number(0),pos0(pos0_),parent(0),children(0),buf(buf_),bufsize(bufsize_),
  333         pagesize(min(pagesize_,bufsize_)){
  334     };
  335 
  336     /* Similar to above, but with no fd */
  337     explicit sbuf_t(const pos0_t &pos0_,const uint8_t *buf_,
  338                     size_t bufsize_,size_t pagesize_,bool should_free_):
  339         fd(0), should_unmap(false), should_free(should_free_), should_close(false),
  340         page_number(0),pos0(pos0_),parent(0),children(0),buf(buf_),bufsize(bufsize_),
  341         pagesize(min(pagesize_,bufsize_)){
  342     };
  343 
  344     /**
  345      * the + operator returns a new sbuf that is i bytes in and, therefore, i bytes smaller.
  346      * Note:
  347      * 1. We assume that pagesize is always smaller than or equal to bufsize.
  348      * 2. The child sbuf uses the parent's memory. If the parent gets deleted, the child points
  349      *    to invalid data.
  350      *
  351      * 3. If i is bigger than pagesize, then an sbuf is returned with
  352      *    0 bytes in the page and all of the margin.
  353      *
  354      *    (Because we won't return what's in the margin as page data.)
  355      */
  356     sbuf_t operator +(size_t off ) const {
  357         return sbuf_t(*this,off);
  358     }
  359 
  360     virtual ~sbuf_t(){
  361 #if defined(SBUF_TRACK) && defined(HAVE___SYNC_ADD_AND_FETCH)
  362         assert(__sync_fetch_and_add(&children,0)==0);
  363 #endif
  364         if(parent) parent->del_child(*this);
  365         release();
  366     }
  367 
  368     /* Allocate a sbuf from a file mapped into memory */
  369     static sbuf_t *map_file(const std::string &fname); 
  370     static sbuf_t *map_file(const std::string &fname,int fd); // if file is already opened
  371     static const std::string U10001C;         // default delimeter character in bulk_extractor
  372     static std::string map_file_delimiter; // character placed
  373     static void set_map_file_delimiter(const std::string &new_delim){
  374         map_file_delimiter = new_delim;
  375     }
  376 
  377     /* Properties */
  378     size_t size() const {return bufsize;} // return the number of bytes
  379     size_t left(size_t n) const {return n<bufsize ? bufsize-n : 0;}; // how much space is left at n
  380 
  381     const sbuf_t *highest_parent() const; // returns the parent of the parent...
  382     void add_child(const sbuf_t &child) const {
  383 #if defined(HAVE___SYNC_ADD_AND_FETCH) && defined(SBUF_TRACK)
  384         __sync_fetch_and_add(&children,1);
  385         std::cerr << "add_child(" << this << ")="<<children << "\n";
  386 #endif
  387     }
  388     void del_child(const sbuf_t &child) const {
  389 #if defined(HAVE___SYNC_ADD_AND_FETCH) && defined(SBUF_TRACK)
  390         __sync_fetch_and_add(&children,-1);
  391         std::cerr << "del_child(" << this << ")="<<children << "\n";
  392         assert(__sync_fetch_and_add(&children,0)>=0);
  393 #endif
  394     }
  395 
  396     /** Find the offset of a byte */
  397     size_t offset(const uint8_t *loc) const {
  398         if(loc<buf) return 0;
  399         if(loc>buf+bufsize) return bufsize;
  400         return loc-buf;
  401     }
  402 
  403     /**
  404      * asString - returns the sbuf as a string
  405      */
  406 
  407     std::string asString() const {return std::string((reinterpret_cast<const char *>(buf)),bufsize);}
  408 
  409     /****************************************************************
  410      *** range_exception_t
  411      *** An sbuf_range_exception object is thrown if the attempted sbuf access is out of range.
  412      ****************************************************************/
  413     /**
  414      * sbuf_t raises an sbuf_range_exception when an attempt is made to read past the end of buf.
  415      */
  416     class range_exception_t: public std::exception {
  417     public:
  418         virtual const char *what() const throw() {
  419             return "Error: Read past end of sbuf";
  420         }
  421     };
  422 
  423     /****************************************************************
  424      *** The following get functions read integer and string types
  425      *** or else throw an sbuf_range_exception if out of range.
  426      ****************************************************************/
  427 
  428     /* Search functions --- memcmp at a particular location */
  429     int memcmp(const uint8_t *cbuf,size_t at,size_t len) const;
  430 
  431     /**
  432      * \name unsigned int Intel (littel-endian) readers
  433      * @{
  434      * these get functions safely return an unsigned integer value for the offset of i,
  435      * in Intel (little-endian) byte order or else throw sbuf_range_exception if out of range.
  436      */
  437     uint8_t  get8u(size_t i) const;
  438     uint16_t get16u(size_t i) const;
  439     uint32_t get32u(size_t i) const;
  440     uint64_t get64u(size_t i) const;
  441     /** @} */
  442 
  443     /**
  444      * \name unsigned int Motorola (big-endian) readers
  445      * @{
  446      * these get functions safely return an unsigned integer value for the offset of i,
  447      * in Motorola (big-endian) byte order or else throw sbuf_range_exception if out of range.
  448      */
  449     uint8_t  get8uBE(size_t i) const;
  450     uint16_t get16uBE(size_t i) const;
  451     uint32_t get32uBE(size_t i) const;
  452     uint64_t get64uBE(size_t i) const;
  453     /** @} */
  454 
  455     /**
  456      * \name signed int Intel (little-endian) readers
  457      * @{
  458      * these get functions safely return a signed integer value for the offset of i,
  459      * in Intel (little-endian) byte order or else throw sbuf_range_exception if out of range.
  460      */
  461     int8_t  get8i(size_t i) const;
  462     int16_t get16i(size_t i) const;
  463     int32_t get32i(size_t i) const;
  464     int64_t get64i(size_t i) const;
  465     /** @} */
  466 
  467     /**
  468      * \name signed int Motorola (big-endian) readers
  469      * @{
  470      * these get functions safely return a signed integer value for the offset of i,
  471      * in Motorola (big-endian) byte order or else throw sbuf_range_exception if out of range.
  472      */
  473     int8_t  get8iBE(size_t i) const;
  474     int16_t get16iBE(size_t i) const;
  475     int32_t get32iBE(size_t i) const;
  476     int64_t get64iBE(size_t i) const;
  477     /** @} */
  478 
  479     /**
  480      * some get functions take byte_order_t as a specifier to indicate which endian format to use.
  481      */
  482     typedef enum {BO_LITTLE_ENDIAN=0,BO_BIG_ENDIAN=1} byte_order_t;
  483 
  484     /**
  485      * \name unsigned int, byte-order specified readers
  486      * @{
  487      * these get functions safely return an unsigned integer value for the offset of i,
  488      * in the byte order of your choice or else throw sbuf_range_exception if out of range.
  489      */
  490     uint8_t  get8u(size_t i,byte_order_t bo) const;
  491     uint16_t get16u(size_t i,byte_order_t bo) const;
  492     uint32_t get32u(size_t i,byte_order_t bo) const;
  493     uint64_t get64u(size_t i,byte_order_t bo) const;
  494     /** @} */
  495 
  496     /**
  497      * \name signed int, byte-order specified readers
  498      * @{
  499      * these get functions safely return a signed integer value for the offset of i,
  500      * in the byte order of your choice or else throw sbuf_range_exception if out of range.
  501      */
  502     int8_t  get8i(size_t i,byte_order_t bo) const;
  503     int16_t get16i(size_t i,byte_order_t bo) const;
  504     int32_t get32i(size_t i,byte_order_t bo) const;
  505     int64_t get64i(size_t i,byte_order_t bo) const;
  506     /** @} */
  507 
  508     /**
  509      * \name string readers
  510      * @{
  511      * These get functions safely read string
  512      */
  513     void getUTF8(size_t i, size_t num_octets_requested, std::string &utf8_string) const;
  514     void getUTF8(size_t i, std::string &utf8_string) const;
  515     /** @} */
  516 
  517     /**
  518      * \name wstring readers
  519      * @{
  520      * These get functions safely read wstring
  521      */
  522     void getUTF16(size_t i, size_t num_code_units_requested, std::wstring &utf16_string) const;
  523     void getUTF16(size_t i, std::wstring &utf16_string) const;
  524     void getUTF16(size_t i, size_t num_code_units_requested, byte_order_t bo, std::wstring &utf16_string) const;
  525     void getUTF16(size_t i, byte_order_t bo, std::wstring &utf16_string) const;
  526     /** @} */
  527 
  528     /**
  529      * The [] operator safely returns what's at index [i] or else returns 0 if out of range.
  530      * We made a decision that this would not throw the exception
  531      * Notice that we don't need to check to see if i<0 because i is unsigned.
  532      */
  533     uint8_t operator [](size_t i) const {
  534         return (i<bufsize) ? buf[i] : 0;
  535     }
  536 
  537     /**
  538      * Find the next occurance of a character in the buffer
  539      * starting at a given point.
  540      * return -1 if there is none to find.
  541      */
  542     ssize_t find(uint8_t ch,size_t start) const {
  543         for(;start<pagesize;start++){
  544             if(buf[start]==ch) return start;
  545         }
  546         return -1;
  547     }
  548 
  549     /**
  550      * Find the next occurance of a char* string in the buffer
  551      * starting at a give point.
  552      * Return offset or -1 if there is none to find.
  553      * This would benefit from a boyer-Moore implementation
  554      */
  555     ssize_t find(const char *str,size_t start) const {
  556         if(str[0]==0) return -1;        // nothing to search for
  557 
  558         for(;start<pagesize;start++){
  559             const uint8_t *p = (const uint8_t *)memchr(buf+start,str[0],bufsize-start);
  560             if(p==0) return -1;             // first character not present,
  561             size_t loc = p-buf;
  562             for(size_t i=0;loc + i < bufsize && str[i];i++){
  563                 if(buf[loc+i] != str[i]) break;
  564                 if(str[i+1]==0) return loc; // next char is null, so we are found!
  565             }
  566             start = loc+1;              // advance to character after found character
  567         }
  568         return -1;
  569     }
  570 
  571     std::string substr(size_t loc,size_t len) const; /* make a substring */
  572     bool is_constant(size_t loc,size_t len,uint8_t ch) const; // verify that it's constant
  573     bool is_constant(uint8_t ch) const { return is_constant(0,this->pagesize,ch); }
  574 
  575     // Return a pointer to a structure contained within the sbuf if there is
  576     // room, otherwise return a null pointer.
  577     template<class TYPE>
  578     const TYPE * get_struct_ptr(uint32_t pos) const {
  579         if (pos + sizeof(TYPE) <= bufsize) {
  580             return reinterpret_cast<const TYPE *> (buf+pos);
  581         }
  582         return NULL;
  583     }
  584     
  585 
  586     /**
  587      * These are largely for debugging, but they also support the BEViewer.
  588      * Dump the sbuf to a stream.
  589      */
  590     void raw_dump(std::ostream &os,uint64_t start,uint64_t len) const;
  591     void raw_dump(int fd,uint64_t start,uint64_t len) const; // writes to a raw file descriptor
  592     void hex_dump(std::ostream &os,uint64_t start,uint64_t len) const;
  593     void hex_dump(std::ostream &os) const; /* dump all */
  594     ssize_t  write(int fd,size_t loc,size_t len) const; /* write to a file descriptor, returns # bytes written */
  595     ssize_t  write(FILE *f,size_t loc,size_t len) const; /* write to a file descriptor, returns # bytes written */
  596 };
  597 
  598 std::ostream & operator <<(std::ostream &os,const sbuf_t &sbuf);
  599 
  600 #include "sbuf_private.h"
  601 
  602 #endif