stb_sbox
文件大小: unknow
源码售价: 5 个金币 积分规则     积分充值
资源说明:STB's public domain sbox library
sboxlib                          This file documents "sboxlib", and should come
                                 in a distribution file called "sboxlib.zip".
a reference implementation       If it it did not, or for more information, see
of the sBOX file format          http://world.std.com/~buzzard/sbox/sbox.html


This distribution contains the free, freely
redistributable source code to the reference
implementation for sBOX file reading and writing.

1.   MANIFEST
2.   BUILD INSTRUCTIONS
2.1.    PORTING
2.2.    COMPILE-TIME OPTIONS
2.3.    VAGUE LIBRARY HOW-TO
3.   BUGS AND TESTING STATUS
4.   IMPLEMENTATION FEATURES
5.   QUICKSTART DOCUMENTATION
6.   REFERENCE

-----------------------------------------------------------------------------

1. MANIFEST

sboxlib includes the following files:

sboxread.c      A prototypical sBOX reading codebase (standalone)
sboxwrit.c      A prototypical sBOX writing codebase (standalone)
sboxkit.c       A toolkit layered over sboxread and sboxwrit
box.c           A demonstration program using sboxread and sboxwrit

sbox.h          General shared definitions
sboxtype.h      Internal-to-library definitions
sboxread.h      Functions exposed by sboxread.c
sboxwrit.h      Functions exposed by sboxwrit.c
sboxkit.h       Functions exposed by sboxkit.c
sboxlib.h       A single header file providing all entry points to above

readme.txt      This file (library documentation)

The sBOX specification is available separately; the current version
as of 1999-03-29 is preliminary version 0.1, and can be found at:
   http://world.std.com~/buzzard/sbox

-----------------------------------------------------------------------------

2.   VAGUE BUILDING-THE-LIBRARY INSTRUCTIONS

2.1.   PORTING

sboxlib requires you to do a single thing in two header files:
the typedef of "uint32" should be set to a type which is
unsigned and 32 bits long; the typedef is found in sbox.h
and in sboxlib.h, and a default value that works for most 32-bit
processors is provided.  (sbox.h is used internally when compiling
the library; sboxlib.h is used by clients of the library.)

Ideally sboxlib would work automatically as long as uint32
is *at least* 32 bits long, because it can use explicit
conversions from byte streams to values, but I didn't think
of it when I wrote it.

sboxlib automatically deals with endianness.  Its solution
is not maxmimally efficient for little-endian processors, but
sboxlib's tasks should be so I/O dominated that this will not
be an issue.  (In an ideal world, compilers would recognize
the standard assemble-bytes-into-integers sequences and output
efficient code for them.)

2.2.   COMPILE-TIME OPTIONS

sboxlib provides three major compile time flags which can be
set when building the library.  (Setting the flags does not
affect the header file or client code, so the client need not
worry about being 'in sync' with the library's setting.)

These flags are designed to simplify life for programmers creating
tools for software developers, or during testing and debugging.
For this reason, all three flags can be turned on by defining the
single flag SBOX_TOOL.

ERROR_STRINGS

    If ERROR_STRINGS is enabled, then in addition to generating
    result codes in response to errors, a result string is placed
    in sbox_read_error_message or sbox_write_error_message.
    These messages are aimed at programmers developing sBOX-derived
    formats, and provide explicit feedback about what in the sBOX
    file went wrong.  The messages will not be useful to end users.
    Examples: "Out of memory for directory", "Invalid directory offset",
    "fread() on file failed".

    Disabling ERROR_STRINGS will save a little memory.

PRINT_ERRORS

    If an error occurs during sbox reading or writing, a message
    will be printed to stderr containing the error code (or error
    string if ERROR_STRINGS is enabled).

EXIT_ON_ERROR

    If an error occurs during sbox reading or writing, the program
    will automatically exit if and only if PRINT_ERRORS is defined.
    (Exitting silently doesn't seem like a very useful thing.)
    Programs aimed at end users will want greater resiliency to
    input errors and failure conditions; however, this can simplify
    early development, and is appropriate for certain kinds of
    in-house tools.

Note that sboxkit provides a separate run-time system for error
response and reporting.  The intention here is that SBOX_TOOL will
do exactly what some people need, and save them the effort of
learning the details of how sboxkit's error-handling works.
(sboxkit's exit-on-error processing will *not* print out the error
message if PRINT_ERRORS is defined, on the assumption that the
underlying sboxread or sboxwrit call already did.)

2.3.  VAGUE LIBRARY HOW-TO

The simplest and most effective way of using sboxlib is to
compile all three of the source code files into a single library:

   sboxread.c
   sboxwrit.c
   sboxkit.c

Then use the resulting library file (e.g. sboxlib.lib) and
the header file 'sboxlib.h' in other projects directly.

You may want to compile two different versions of the library,
one with SBOX_TOOL defined and the other with all the flags
undefined.  These should probably be named different things,
not considered 'debug' versus 'release', because they behave
radically differently in the face of errors which would
undermine debugging.

-----------------------------------------------------------------------------

3.  BUGS AND TESTING STATUS

3.1  PORTABILITY

At this date, 1999-03-29, sboxlib has only been tested with
one compiler and one platform: MSVC 4.2 under Win98.

However, sboxlib's dependency on the platform is limited
to the FILE * interface from the stdio library, which should
be being used in a strictly portable fashion.

It is possible that an endian dependency or a sizeof(int)
dependency crawled into the code despite my precautions.
If you have a mysterious failure or an inconsistency between
systems, check if the bad system is big endian or if
sizeof(int) != 4 first thing.

I was writing extremely portable unix applications in 1990,
so hopefully I haven't dropped the ball now that I'm only
developing under Windows--but I can't make any guarantees
until I get some feedback.

3.2  BUGS

sboxlib was developed for my own personal use.  It has not
undergone a thorough QA process, nor even an appropriate
amount of programmer-testing.

Notably undertested:

   The support for scanning directories on disk (instead of
   reading them entirely into memory) is entirely untested
   (and hence almost certainly buggy).

   Many of the sboxkit interfaces haven't been tested.

   Some of the sboxwrit interfaces haven't been tested.

Also:

   I *tried* to write very bulletproof code, with totally
   thorough error-checking everywhere.  (But parameter
   validation is not done for pointers arguments.)  But
   I probably missed some cases.

All of this means that things may well suck if you're not willing
to debug my code.  Yeah, my code is pretty well structured,
and it's not much code, and it's a layered API so you don't
have to understand the innards of sboxread/sboxwrit to debug
sboxkit, but it opens up a whole can of worms if you use it.

However, you should realize that I haven't debugged this
stuff not because it's hard, but because writing test code
to debug it is a giant waste of my time if nobody is ever
going to use it.  You should think of it as 'lazy evaluation'
testing.

In other words, any bugs (as opposed to feature requests)
that you find are probably trivial for me to fix (if not
for you), and I will make them my number one priority.

On the other hand, if you find and fix bugs, I will gladly
incorporate them into my codebase.  On the other other hand,
I am leery about adding new features, as I would like to
keep the sboxlib codebase relatively concise and easy to
comprehend, so that the source itself is useful for more
than just compiling.

-----------------------------------------------------------------------------

4.   IMPLEMENTATION FEATURES

sboxlib exposes a very simple, hopefully stable, layered API.

-- SBOXREAD & SBOXWRIT --

The bottom layer of the library consists of sboxread and sboxwrit.
Each of these files provides the basic mechanisms for reading and
writing sbox files.  They do a very careful, hopefully thorough
job of error detection and reporting.  sboxread provides the bare
minimum functionality necessary 'to get the job done', and relies
on the layered API to achieve flexibility.  (sboxwrit attempts to
subscribe to the same philosophy, but is forced to provide several
different accessing mechanisms due to it being harder to layer
correctly than just provide them all in the first place.)

Notable features:

   Full error detection and reporting, compile-time controllable
   using the preprocessor flags discussed in section 2.2.  (Check
   out the function locate_directory() in sboxread.c for an example
   of why error checking takes up more code in sboxread than does
   actual processing.  This level of detail is mainly useful for
   debugging flawed sBOX writers.)

   sboxread supports a 'max memory directory size'; if a directory
   is smaller than this size, sboxread reads the entire directory
   into memory for later use.  If it is larger than this size, then
   it is left on disk.  sboxread provides accessing methods for
   reading directory entries that automatically use whichever mechanism
   was used to open the file.

   sboxread can parse an arbitrary subregion of a file as an sbox
   file, so, for example, it can directly handle nested sbox files.

   sboxwrit writes to a FILE * sequentially, and thus can be used to
   generate a subregion of a file.  (It explicitly generates offsets
   relative to the start of its subregion, as opposed to explicit
   global file offsets.)  Additionally, data-writing is done by
   getting a FILE * from sboxwrit and writing the data for a block
   to it (typically sequentially); therefore, it is possible (and
   straightforward) to use sboxwrit to generate nested sbox files.

   sboxread and sboxwrit are thread-safe if multiple threads don't operate
   on the same file (because there is no global state), except for extended
   error reporting which occurs through global variables.  Multiple
   threads cannot safely read or write to the same file (at least
   not through the same SboxHandle; while multi-thread writing is
   entirely impossible, multi-thread reading is possible if each
   thread uses its own SboxHandle built on top of independent
   FILE * handles).

   sboxwrit currently won't work if you lie to it about how much data
   you wrote into the FILE * (if you use the interface that requires
   explicit lengths).  I could make some straightforward changes
   to it (actually, simplify the design quite a bit!), and make it so
   that you can write into the FILE * freely, generating "dead data"
   as well as the sbox data.  I didn't need it or want it, so I designed
   it differently, but it could be changed.  (It would probably make
   sboxwrit behave more predictably, although the current design was
   intended to basically make sure you couldn't accidentally write data
   that didn't end up in some data block.)

-- SBOXKIT --

The top layer of the library is sboxkit.  sboxkit is a pure layer
over sboxread and sboxwrit--it doesn't access any internal data
structures, just the pure functional interface.  [The file sboxtype.h
defines the internal structures used by sboxread and sboxwrit, but
it isn't exported in sboxlib.h, and it's not used by sboxkit.]

sboxkit provides some very important functionality, such as directory
searching.  It also provides a large number of 'wrapper' functions
which simplify the usage of the raw functionality provided by sboxread.
It includes automatic memory allocation for reading data items,
interfaces for using C-style strings as names (that is, not needing
to supply an explicit length field for names), a set of interfaces
which squish the result codes into other return values, and support for
automatic file opening and closing for super-simple one-shot access.

Notable issues:

   sboxkit just linear searches the directory when asked to find an
   item.  This will need to change at some point to a smarter data
   structure (e.g. a hash table or a binary tree).  To do so without
   changing the interface will require some cleverness, however, as
   sboxkit does not wrap the file handles provided by sboxread, and
   therefore has nowhere to store any derived data (like a hash table).
   This is the number one feature that will definitely go into sboxkit
   the minute it is being used for any serious applications, and it
   will NOT require any changes to the API exposed to the client.
   [The solution: sboxread will be extended to provide a void * which
   it stores in the file handle on behalf of a client; sboxkit can
   hang its data off of there.  Thus the sboxread API will be extended,
   sboxkit will use the new API, and the API will be unchanged as
   perceived by clients.  Also, since these files are read-only once
   they're accessed by sboxread, an easy fast approach would be to
   make an index array that's sorted, and binary search it.  This involves
   lg N string compares, which could suck with long strings, but simple
   and relatively efficient.  It also would handle the current 'repeated
   item' interface cleanly.  Plus, 'simple and easy' means 'bug free'--
   use qsort, spend a little effort on "proving" the binary search, and
   it's basically done.]

   sboxkit is not multi-thread friendly, since it uses a lot of global
   data to keep track of temporarily allocated data items and temporarily
   opened files.

-----------------------------------------------------------------------------

5. QUICKSTART DOCUMENTATION

  sboxlib provides a wide variety of functions to maximize functionality
  and improve ease of use.  That means it would take a while to come up
  to speed on the entire API.  Therefore, here is an extremely simple
  set of functions you can use to start with.

5.1  QUICKSTART: READING SBOX FILES

Prototypes:

#   SboxHandle *SboxkitReadOpenFilename(char *filename, char *signature);

      Creates a new sbox file handle for reading.  Fails if the
      file doesn't exist or doesn't begin with the 16-byte signature
      pointed to by the argument signature.  If signature is a NULL,
      any sBOX file will be accepted.

#   SRCode SboxReadClose(SboxHandle *sbox);

      Closes such a file handle.

#   uint32 SboxkitGetByString(void **p, SboxHandle *sbox, char *name);

      Looks for a  pair that matches the name, and loads the
      corresponding value into a temporary memory buffer, returning the length.

Sample code:

  #include "sboxlib.h"
  #define MY_NAME   "my_name"

  int main(int argc, char **argv)
  {
     SboxHandle *sbox;
     uint32 length;
     unsigned char *value;

     sbox = SboxkitReadOpenFilename(argv[1]);

     length = SboxkitGetByString(&value, sbox, MY_NAME);

     if (value)
        printf(MY_NAME ": length %d, first byte %d\n", length, value[0]);
     else
        printf(MY_NAME " was not present or was zero-length\n");
     
     // NOTE: if we did another SboxkitGetByString(), 'value' would
     // no longer be pointing to a valid buffer--it's a temporary
     // short-lifetime buffer

     SboxReadClose(sbox);
  }

5.2  QUICKSTART: WRITING SBOX FILES

Prototypes:

#   SboxWriteHandle *SboxkitWriteOpenFromFilename(char *filename, char *sig);

      Creates a new sbox file for writing.  (Truncates an existing file.)
      Uses the first 16 bytes pointed to by "sig" as the 16-byte file
      signature for the sBOX file.

#   SRCode SboxWriteClose(SboxWriteHandle *handle);

      Closes an active sboxfile being written, freezing its contents
      (the sBOX directory is written out at this time).

#   SRCode SboxWriteStartItemNamed(SboxWriteHandle *h,
#                                                char *name, int namesize);

      Begin adding an item named 'name' to the sbox file.  'name' need
      not be nulll terminated, and should be of length 'namesize'. (Sorry
      for the lack of parallelism with the read code here, but sboxkit
      wrappers were focused on simplifying reading, not writing.)

#   SRCode SboxWriteEndItem(SboxWriteHandle *h);

      Indiciate the end of the value of the item started previously
      with SboxWriteStartItemNamed().

#   SRCode SboxWriteData(SboxWriteHandle *h, void *data, uint32 datasize);

      Write some of the value into the current  pair.
      Explicitly: append datasize bytes to the current value.  Must
      be called between SboxWriteStartItemNamed() and SboxWriteEndItem()
      or equivalent functions.

Sample code:

  #include "sboxlib.h"
  #define MY_NAME   "my_name"

  int main(int argc, char **argv)
  {
     SboxWriteHandle *sbox;

     sbox = SboxkitWriteOpenFilename(argv[1]);

     SboxWriteStartItemNamed(sbox, MY_NAME, strlen(MY_NAME));
     SboxWriteData(sbox, "some junky data",  15);
     SboxWriteData(sbox, " plus some more!", 16);
     SboxWriteEndItem();

     SboxWriteClose(sbox);
     // creates a single item:  <"my_name", "some junky data plus some more!">
  }

-----------------------------------------------------------------------------

6. REFERENCE

  It may look like there are a lot of functions here.  A lot of
  this is merely to provide flexibility.

6.0   ARGUMENT ORDER CONVENTIONS

  All sbox interfaces use a consistent argument ordering convention
  to try to make it easier to remember them without looking them up:

     1.  All output items appear first (an output item is a
         pointer through which the called function will write)
     2.  Buffers are always named with the pointer and then the size;
         if the buffer is a output item, then the size appears next,
         even if the size is not a output item.
     3.  The SboxHandle * appears as early in the list as is possible
         without conflicting with the above rules.  (In other words,
         SboxHandle * appears immediately after all output items, unless
         it is an output (e.g. SboxHandle **), in which case it appears
         *first*.)
     4.  offset/size pairs always appear in that order
     5.  boolean flags come last

  Boolean flags are typed with 'int' to avoid system dependent
  conflicts and conflicts with C++.

6.1   READING SBOX FILES

6.1.1.  ERROR CODES

  Almost all functions in sboxread return a value of type SboxResultCode,
  indicating whether an operation succeeded (indicated by SBOX_OK == 0),
  or whether something went wrong.  In the remainder of this file,
  SboxResultCode will be abbreviated SRCode.

  The returned error code indicates either a general class of errors
  (such as SBOX_OUT_OF_MEMORY), or indicates where in the sBOX file something
  went wrong (header, tail, directory, data block), or whether an invalid
  item offset was provided (SBOX_INVALID_ITEM).

  Extended error information giving more details are exposed via global
  variables, depending on options defined at compile time:

#    int   sbox_read_error_code;
#    char *sbox_read_error_message;

  See sboxread.c for the values of sbox_read_error_code, and section 2.2
  to learn how to get non-NULL values for sbox_read_error_message.

  Many sboxkit functions hide the detailed error values and provide
  either a single value, or none at all.  You can enable at run time
  whether errors will cause sboxkit functions to terminate the application
  by setting

#    int sboxkit_exit_on_error;

  to TRUE.

6.1.2.   MEMORY USAGE

  sBOX provides a global variable whose value is used to determine
  whether or not to load an sBOX directory into memory, or to search
  it on disk.

#     unsigned long  sbox_max_memory_directory;

  Set this to the maximum size (in bytes) of an sBOX directory which
  should be stored in memory.  The actual storage used depends on the
  sBOX file; and every open sBOX file can use this amount independently.
  The value only affects files which are opened subsequently.

  Set it to SBOX_DIRECTORY_ALWAYS_IN_MEMORY to have directories always
  read into memory (the default).  Set it to SBOX_DIRECTORY_NEVER_IN_MEMORY
  to have it never be read into memory.

6.1.3   OPENING FILES FOR READ

  sBOX files are read through the use of SboxHandle *, which
  somewhat resemble the FILE * interfaces provided by stdio.h.

  There are three interfaces for opening an sbox file for reading,
  depending on how it should get at the underlying file.  Each of these
  three interfaces has two variants.  The first variant returns a
  result code and requires a pointer to an SboxHandle *.  The second
  variant returns an SboxHandle *, and returns NULL if there is an
  error.  The former case allows you to distinguish between a file
  not existing, not being an sBOX file, or being a corrupted sBOX
  file; the second variant is a little easier to use but makes it
  clumsier to find out what went wrong.

#   SRCode      SboxReadOpenFilename(SboxHandle **, char *filename, char *sig);
#   SboxHandle *SboxkitReadOpenFilename(char *filename, char *sig);

       Given a filename, fopen() it and parse it as an sbox file.  Checks
       that it begins with the signature specified as "sig", unless sig
       is NULL, in which case any file is accepted.

#   SRCode SboxReadOpenFromFile(SboxHandle **, FILE *f, int close, char *sig);
#   SboxHandle *SboxkitReadOpenFromFile(FILE *f, int close, char *sig);

       Given an open file f, rewind to the beginning and parse it as
       an sbox file.  If 'close' is true, sboxlib will fclose()
       the FILE * when the sbox file is closed.

#   SRCode      SboxReadOpenFromFileBlock(SboxHandle **, FILE *f,
#                         uint32 offset, uint32 size, int close, char *sig);
#   SboxHandle *SboxkitReadOpenFromFileBlock(FILE *f,
#                         uint32 offset, uint32 size, int close, char *sig);

       Given an open file f, treat the subregion of it starting at 'offset'
       and of length 'size' as an sbox file.  If 'close' is true, sboxlib
       will fclose() the FILE * when the sbox file is closed.

  Note: the following calls are essentially equivalent:
      SboxReadOpenFilename(&sbox, filename, sig)
      SboxReadOpenFromFile(&sbox, fopen(filename, "rb"), TRUE, sig);
      SboxReadOpenFromFileBlock(&sbox, fopen(filename, "rb"),
                    0, function_returning_file_length(filename), TRUE, sig);
  
6.1.4   CLOSING FILES FOR READ

#   SRCode SboxReadClose(SboxHandle *sbox);

    When you have finished reading from an sbox file, call SboxReadClose
    to release system resources.  (Mainly memory consumption, and a file
    handle if the file was opened with 'close' set TRUE.)

6.1.5   SIMPLE ITEM FETCHING

#   uint32 SboxkitGetByString(void **p, SboxHandle *sbox, char *name);
#   uint32 SboxkitSizeByString(SboxHandle *sbox, char *name);
#   void *SboxkitItemByString(SboxHandle *sbox, char *name);

    Given a name represented by a C string (zero-terminated, but
    the one in the sbox file is not explicitly zero-terminated),
    these functions return the size of the correspondin data item,
    and a pointer to a temporary buffer holding all of the data
    respectively.  Only one such buffer is available at a time,
    globally across all sbox files.

    The first function returns both values; the other two functions
    each return a single value.  A length of 0 and a pointer of NULL
    are used to indicate that a name is not present.  (Note that if a
    name is present but has a 0-length value, it will also be reported
    with a length of 0 and a pointer of NULL; to test for the presence
    of a data item, use another function, such as SboxkitFindString.)

#   void SboxkitStealItem(void *p);
#   void SboxkitFreeItem(void *p);

    The previous functions put the item in a temporary buffer, and
    one of the item is available at a time.  If you want to preserve
    the item without copying it, call SboxkitStealItem().  This informs
    sboxkit that you are taking responsibility for managing the lifetime
    of the item.  It will remain valid until you release it, which you
    do by calling SboxkitFreeItem().  

  This somewhat clumsy solution allows for extremely convenient
  automatic storage management in simple situations, and a facility
  for overriding it in special circumstances.  If you want to do
  the storage managment yourself, then you need to get an id for
  the item (see section 6.1.6), and then use SboxReadItem(),
  described in section 6.1.7.  If you want to use names which are
  not 0-terminated--i.e. they have embedded 0s in the names, or
  the representation you have for them in code does not have a
  terminating 0, then you must use the id interface as well.

6.1.6   DIRECTORY LOOKUP

  Items in an sboxfile are referred to by integer ids, starting from 0.
  You can find the index of a  pair given only the name
  (assuming it is unique):

#   uint32 SboxkitFindName(SboxHandle *sbox, void *name, uint32 namelen);
#   uint32 SboxkitFindString(SboxHandle *sbox, char *name);

    The second function takes a 0-terminated string.  (It matches a string
    of the length strlen(str) in the sbox file--the name in the sbox file
    must not be zero-terimated.)  These functions return SBOXKIT_NOTFOUND
    if the name is not present.  [Note that 0 is a legal item id.]

  There is also extremely primitive support for handling files in
  which the same name appears multiple times.  If iterating over the
  entire directory is not an appropriate solution, please consult sboxkit.h
  for brief documentation on these functions:

#        SboxkitCountName
#        SboxkitCountString
#        SboxkitFindDuplicateName
#        SboxkitFindDuplicateString

6.1.7   READING ITEMS 

  Given an item id generated from the functions in section 6.1.6, you
  can read the data directly.

#   uint32 SboxReadItem(void *buffer, uint32 bufsize,
                        SboxHandle *sbox, uint32 n, uint32 offset);

    This function reads as much as 'bufsize' data into the buffer
    provided by the caller.  The data is taken from the n'th item's
    data field, starting at 'offset' bytes within it.  The return
    value is the number of bytes read, or 0 if there is no such item
    or if the offset specified is outside the legal range for that item.
    This is roughly equivalent to an fseek() followed by an fread().

#   SRCode SboxSeekItem(  SboxHandle *sbox, uint32 n, uint32 offset);
#   FILE  *SboxFileHandle(SboxHandle *sbox);

    You can read the data field manually.  SboxSeekItem()
    will wind the file pointed to by SboxFileHandle to the offset'th
    byte of the n'th item.  SboxFileHandle() will return the file handle
    which can then be used to fread() the data directly.  This allows
    the data to be supplied to other libraries which want to stream the
    data directly from a file, but it is not recommended for general use.

6.1.8   RAW DIRECTORY ACCESS

  Given an item id, you can directly access all the information
  about the corresponding  pair; for example, you
  can explicitly iterate through id's and examine 
  pairs this way.

#   SRCode SboxNumItems(uint32 *value, SboxHandle *sbox);
#   uint32 SboxkitNumItems(SboxHandle *sbox);

    Reports the number of  pairs in the file.

#   SRCode SboxNameSize(uint32 *value, SboxHandle *sbox, uint32 n);
#   uint32 SboxkitNameSize(SboxHandle *sbox, uint32 n);

    Reports the length of the  field of the n'th item (numbered from 0).

#   SRCode SboxNameData  (void **value, SboxHandle *sbox, uint32 n);
#   void *SboxkitNameData(SboxHandle *sbox, uint32 n);

    Returns the value of the  field of the n'th item (numbered from 0).
    This data is malloc'd and will become invalid on the next Sbox{kit}NameData
    operation on this sbox file.

#   SRCode SboxNameBuffer(void *buffer, uint32 bufsize,
#                                          SboxHandle *sbox, uint32 n);

    Puts up to 'bufsize' bytes of the name of the n'th item into buffer.
    The total number of bytes placed is the smaller of bufsize and the
    length of the name.

#   SRCode SboxItemSize(uint32 *value, SboxHandle *sbox, uint32 n);
#   uint32 SboxkitItemSize(SboxHandle *sbox, uint32 item);

    Reports the length of the  field of the n'th item (numbered from 0).

#   SRCode SboxItemLoc (uint32 *value, SboxHandle *sbox, uint32 n);

    Reports the file offset (relative to the start of the sbox file)
    of the data for the n'th item (numbered from 0).  (Note that you
    cannot just directly fseek() SboxFileHandle() to this location
    if the sbox file is formed from a subregion.  The information is
    provided for completeness, but you probably should never use it.)
 
6.1.9   UTILITY EASY READER

  For extra ease of use, sboxkit provides some mechanisms for
  reading from sbox files without ever creating sbox handles.
  (Behind the scenes, these mechanisms are less efficient, and
  may leave files open for longer than you might want, but they're
  convenient for quick-and-dirty situations):

#   uint32 SboxkitGet(void **p, char *filename, char *itemname);
#   uint32 SboxkitFilenameItemSize(char *filename, char *itemname);
#   void *SboxkitFilenameItem(char *filename, char *itemname);

    SboxkitGet is a single easy-to-use entry point.  The file named
    by 'filename' is scanned for an item named 'itemname'; if it is
    found, its value is loaded into memory, and *p is made to point
    to it; the length of the item is returned.  This value is only
    guaranteed to last until the next SboxkitGet or equivalent; see
    section 6.1.5 for information on how to 'acquire' the storage
    management of one of these items.

    The other two functions provide each of these items independently.

    There is no interface to easily detect the presence of a 0-length
    item.

6.2   WRITING SBOX FILES

  The provided codebase in sboxwrit allows the creation of sbox files
  with certain restrictions.  The entire directory must be able to fit
  in main memory.  The  pairs must be written out in order.
  No provision is made for providing a FILE handle to allow the use of
  libraries to write out the data.  You cannot output the canonical format.
  You *can* directly write nested sbox files--that is, allow the 
  field to contain one (or more!) sbox files which are also created on
  the fly.

6.2.1  ERROR CODES

  All functions in sboxwrit return a value of type SboxResultCode,
  indicating whether an operation succeeded (indicated by SBOX_OK == 0),
  or whether something went wrong.  In the remainder of this file,
  SboxResultCode will be abbreviated SRCode.

  The returned error code indicates either a general class of errors
  (such as SBOX_OUT_OF_MEMORY), or indicates where in the sBOX file something
  went wrong (header, tail, directory, data block), or whether an invalid
  item offset was provided (SBOX_INVALID_ITEM).

  Extended error information giving more details are exposed via global
  variables, depending on options defined at compile time:

#    int   sbox_write_error_code;
#    char *sbox_write_error_message;

  See sboxwrit.c for the values of sbox_write_error_code, and section 2.2
  to learn how to get non-NULL values for sbox_write_error_message.

  Many sboxkit functions hide the detailed error values and provide
  either a single value, or none at all.  You can enable at run time
  whether errors will cause sboxkit functions to terminate the application
  by setting

#    int sboxkit_exit_on_error;

  to TRUE.

6.2.2  OPENING FILES
   
  sBOX files are written through the use of SboxWriteHandle *, which
  somewhat resemble the FILE * interfaces provided by stdio.h.

  Note that SboxHandle (for reading) and SboxWrithandle (for writing)
  are not interchangeable, and there is no mechanism supporting
  both read and write to the same file.  sboxread.c and sboxwrit.c are
  entirely separate files and work entirely independently of each other.

  New writeable files can be created through one of two interfaces,
  each of which has two variants, one of which simplifies error handling:

#   SRCode SboxWriteOpenFilename(SboxWriteHandle **handle,
                                      char *filename, char *sig);
#   SboxWriteHandle *SboxkitWriteOpenFromFilename(char *filename, char *sig);

    Open the specified filename, creating or truncating it as necessary,
    to create a new sBOX file.  "sig" must point to a 16-byte array of
    characters which is used as the file signature.

#   SRCode SboxWriteOpenFromFile(SboxWriteHandle **handle,
                                            FILE *f, int close, char *sig);
#   SboxWriteHandle *SboxkitWriteOpenFromFile(FILE *f, int close, char *sig);

    Start creating an sBOX file at the current location pointed to by
    the provided FILE *.

  Note that SboxWriteOpenFromFile() and SboxReadOpenFromFile() have
  radically different syntaces.  SboxReadOpenFromFile() always seeks
  to the beginning of the file before opening; if you want to read
  a subblock, you have to specify its location and length explicitly
  using SboxReadOpenFromFileBlock().  SboxReadOpenFromFile() has no
  way of knowing where the 'current block' would end.  However,
  SboxWriteOpenFromFile() simply starts writing at the current location;
  the 'current block' (the sub-sBOX file) ends whereever is necessary
  to write out all the data when it is eventually closed.

6.2.2  CLOSING FILES

#   SRCode SboxWriteClose(SboxWriteHandle *handle);

    Closes the file and causes sboxwrit to write out the directory.
    Failing to close an sbox file opened for write will result in a
    corrupted sbox file.

6.2.3  WRITING ITEMS

  sboxwrit provides a number of different mechanisms for specifying
   pairs to be written into the sbox file.
  
#    SRCode SboxkitStringPut(SboxWriteHandle *h, char *name,
#                                             void *data, uint32 datasize);

     Add a  pair to the sbox file where the selected name
     is specified by 'char *name'--the output name will not be null
     terminated, and will have length strlen(name)--and the value is
     in the buffer 'data' and has length 'datasize'.

  The remaining mechanisms allow you to write the data out to the file
  a little at a time.  There are three ways for specifying
  the name, start, and end of the value; the first two functions in this
  list represent one way, the second two functions the second way,
  and the fifth function the third way.

#    SRCode SboxWriteStartItemNamed(SboxWriteHandle *h,
#                                                char *name, int namesize);

     Adds a  pair to the sbox file where the name is pointed
     to by 'char *name' and is of length 'namesize'.  The value will be
     written using one of the functions at the end of this section, and
     then SboxWriteEndItem() will be called to indicate the end of the value.

#    SRCode SboxWriteEndItem(SboxWriteHandle *h);

     Marks the end of the value specified by SboxWriteStartItemNamed()

#    SRCode SboxWriteStartItem(SboxWriteHandle *h);

     Like SboxWriteStartItemNamed(), but doesn't specify the name yet--
     it will be specified when the value is ended with the next function:

#    SRCode SboxWriteEndItemNamed(SboxWriteHandle *h, char *name, int namesize);

     Marks the end of the value specified by SboxWriteStartItem(), and
     specifies the name of that item--pointed to by 'name' and of length
     namesize.

#    SRCode SboxWriteItem(SboxWriteHandle *h, char *name,
#                                      uint32 namesize, uint32 datasize);

     Specifies the start of a new item, with name pointed to by 'name'
     and of length 'namesize'.  Promises the item will be 'datasize' long.
     No explicit 'end of item' function needs to be called.

  In between calls to SboxWriteStartItem() and SboxWriteEndItem(),
  you write out the "value" part of the  pair by outputting
  data through the following function, which resembles fwrite:

#    SRCode SboxWriteData(SboxWriteHandle *h, void *data, uint32 datasize);

     Writes 'datasize' bytes pointed to by 'data' to the currently
     "open"  pair.  May be called multiple times; each
     item is appended to the previous item.

#    FILE  *SboxWriteFileHandle(SboxHandle *sbox);

     Provides a 'FILE *' file handle to which data can be written
     using fwrite(); this will have the same effect as the above
     function.  You can even ftell, fseek, and backpatch, even
     backpatching data from other values; just make sure you leave
     the file fseek()'d to the end of the data you want written
     for this value before calling a terminating function.

STB 1999-03-01
updated STB 2000-08-18

本源码包内暂不包含可直接显示的源代码文件,请下载源码包。