cbf_file.c

Go to the documentation of this file.
00001 /**********************************************************************
00002  * cbf_file -- file access (characterwise and bitwise)                *
00003  *                                                                    *
00004  * Version 0.6 13 January 1999                                        *
00005  *                                                                    *
00006  *            Paul Ellis (ellis@ssrl.slac.stanford.edu) and           *
00007  *         Herbert J. Bernstein (yaya@bernstein-plus-sons.com)        *
00008  **********************************************************************/
00009   
00010 /**********************************************************************
00011  *                               NOTICE                               *
00012  * Creative endeavors depend on the lively exchange of ideas. There   *
00013  * are laws and customs which establish rights and responsibilities   *
00014  * for authors and the users of what authors create.  This notice     *
00015  * is not intended to prevent you from using the software and         *
00016  * documents in this package, but to ensure that there are no         *
00017  * misunderstandings about terms and conditions of such use.          *
00018  *                                                                    *
00019  * Please read the following notice carefully.  If you do not         *
00020  * understand any portion of this notice, please seek appropriate     *
00021  * professional legal advice before making use of the software and    *
00022  * documents included in this software package.  In addition to       *
00023  * whatever other steps you may be obliged to take to respect the     *
00024  * intellectual property rights of the various parties involved, if   *
00025  * you do make use of the software and documents in this package,     *
00026  * please give credit where credit is due by citing this package,     *
00027  * its authors and the URL or other source from which you obtained    *
00028  * it, or equivalent primary references in the literature with the    *
00029  * same authors.                                                      *
00030  *                                                                    *
00031  * Some of the software and documents included within this software   *
00032  * package are the intellectual property of various parties, and      *
00033  * placement in this package does not in any way imply that any       *
00034  * such rights have in any way been waived or diminished.             *
00035  *                                                                    *
00036  * With respect to any software or documents for which a copyright    *
00037  * exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT.   *
00038  *                                                                    *
00039  * Even though the authors of the various documents and software      *
00040  * found here have made a good faith effort to ensure that the        *
00041  * documents are correct and that the software performs according     *
00042  * to its documentation, and we would greatly appreciate hearing of   *
00043  * any problems you may encounter, the programs and documents any     *
00044  * files created by the programs are provided **AS IS** without any   *
00045  * warranty as to correctness, merchantability or fitness for any     *
00046  * particular or general use.                                         *
00047  *                                                                    *
00048  * THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF    *
00049  * PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE   *
00050  * PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS   *
00051  * OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE          *
00052  * PROGRAMS OR DOCUMENTS.                                             *
00053  **********************************************************************/
00054  
00055 /**********************************************************************
00056  *                          The IUCr Policy                           *
00057  *                                 on                                 *
00058  *     the Use of the Crystallographic Information File (CIF)         *
00059  *                                                                    *
00060  * The Crystallographic Information File (Hall, Allen & Brown,        *
00061  * 1991) is, as of January 1992, the recommended method for           *
00062  * submitting publications to Acta Crystallographica Section C. The   *
00063  * International Union of Crystallography holds the Copyright on      *
00064  * the CIF, and has applied for Patents on the STAR File syntax       *
00065  * which is the basis for the CIF format.                             *
00066  *                                                                    *
00067  * It is a principal objective of the IUCr to promote the use of      *
00068  * CIF for the exchange and storage of scientific data. The IUCr's    *
00069  * sponsorship of the CIF development was motivated by its            *
00070  * responsibility to its scientific journals, which set the           *
00071  * standards in crystallographic publishing. The IUCr intends that    *
00072  * CIFs will be used increasingly for electronic submission of        *
00073  * manuscripts to these journals in future. The IUCr recognises       *
00074  * that, if the CIF and the STAR File are to be adopted as a means    *
00075  * for universal data exchange, the syntax of these files must be     *
00076  * strictly and uniformly adhered to. Even small deviations from      *
00077  * the syntax would ultimately cause the demise of the universal      *
00078  * file concept. Through its Copyrights and Patents the IUCr has      *
00079  * taken the steps needed to ensure strict conformance with this      *
00080  * syntax.                                                            *
00081  *                                                                    *
00082  * The IUCr policy on the use of the CIF and STAR File processes is   *
00083  * as follows:                                                        *
00084  * _________________________________________________________________  *
00085  *                                                                    *
00086  *  * 1 CIFs and STAR Files may be generated, stored or transmitted,  *
00087  *    without permission or charge, provided their purpose is not     *
00088  *    specifically for profit or commercial gain, and provided that   *
00089  *    the published syntax is strictly adhered to.                    *
00090  *  * 2 Computer software may be developed for use with CIFs or STAR  *
00091  *    files, without permission or charge, provided it is distributed *
00092  *    in the public domain. This condition also applies to software   *
00093  *    for which a charge is made, provided that its primary function  *
00094  *    is for use with files that satisfy condition 1 and that it is   *
00095  *    distributed as a minor component of a larger package of         *
00096  *    software.                                                       *
00097  *  * 3 Permission will be granted for the use of CIFs and STAR Files *
00098  *    for specific commercial purposes (such as databases or network  *
00099  *    exchange processes), and for the distribution of commercial     *
00100  *    CIF/STAR software, on written application to the IUCr Executive *
00101  *    Secretary, 2 Abbey Square, Chester CH1 2HU, England. The        *
00102  *    nature, terms and duration of the licences granted will be      *
00103  *    determined by the IUCr Executive and Finance Committees.        *
00104  *                                                                    *
00105  * _________________________________________________________________  *
00106  *                                                                    *
00107  * In summary, the IUCr wishes to promote the use of the STAR File    *
00108  * concepts as a standard universal data file. It will insist on      *
00109  * strict compliance with the published syntax for all                *
00110  * applications. To assist with this compliance, the IUCr provides    *
00111  * public domain software for checking the logical integrity of a     *
00112  * CIF, and for validating the data name definitions contained        *
00113  * within a CIF. Detailed information on this software, and the       *
00114  * associated dictionaries, may be obtained from the IUCr Office at   *
00115  * 5 Abbey Square, Chester CH1 2HU, England.                          *
00116  **********************************************************************/
00117 
00118 #ifdef __cplusplus
00119 
00120 extern "C" {
00121 
00122 #endif
00123 
00124 #include "cbf.h"
00125 #include "cbf_alloc.h"
00126 #include "cbf_codes.h"
00127 #include "cbf_file.h"
00128 
00129 #include <stdlib.h>
00130 #include <string.h>
00131 #include <limits.h>
00132 
00133 
00134   /* Create and initialise a file */
00135 
00136 int cbf_make_file (cbf_file **file, FILE *stream)
00137 {
00138     /* Allocate the memory */
00139 
00140   cbf_failnez (cbf_alloc ((void **) file, NULL, sizeof (cbf_file), 1))
00141 
00142 
00143     /* Initialise */
00144 
00145   (*file)->stream = stream;
00146 
00147   (*file)->connections = 1;
00148 
00149   (*file)->bits [0]        = 0;
00150   (*file)->bits [1]        = 0;
00151   (*file)->characters_used = 0;
00152   (*file)->last_read       = 0;
00153   (*file)->line            = 0;
00154   (*file)->column          = 0;
00155   (*file)->buffer_size     = 0;
00156   (*file)->buffer_used     = 0;
00157 
00158   (*file)->buffer          = NULL;
00159   (*file)->digest          = NULL;
00160 
00161   (*file)->read_headers    = 0;
00162   (*file)->write_headers   = 0;
00163   (*file)->write_encoding  = 0;
00164 
00165 
00166     /* Success */
00167 
00168   return 0;
00169 }
00170 
00171 
00172   /* Free a file */
00173 
00174 int cbf_free_file (cbf_file **file)
00175 {
00176   int errorcode;
00177 
00178   errorcode = 0;
00179 
00180   if (file)
00181 
00182     if (*file)
00183     {
00184       if ((*file)->stream)
00185 
00186         if (fclose ((*file)->stream))
00187 
00188           errorcode = CBF_FILECLOSE;
00189 
00190       errorcode |= cbf_free ((void **) &(*file)->buffer, 
00191                                        &(*file)->buffer_size);
00192 
00193       errorcode |= cbf_free ((void **) &(*file)->digest, NULL);
00194       
00195       errorcode |= cbf_free ((void **) file, NULL);
00196     }
00197 
00198 
00199     /* Success? */
00200 
00201   return errorcode;
00202 }
00203 
00204 
00205   /* Add a file connection */
00206 
00207 int cbf_add_fileconnection (cbf_file **file, FILE *stream)
00208 {
00209     /* Does the file pointer exist? */
00210 
00211   if (!file)
00212 
00213     return CBF_ARGUMENT;
00214 
00215 
00216     /* Does the file exist? */
00217 
00218   if (*file)
00219 
00220       /* Does the stream match? */
00221 
00222     if (stream && (*file)->stream != stream)
00223 
00224       return CBF_NOTFOUND;
00225 
00226     else
00227     {
00228       (*file)->connections++;
00229 
00230       return 0;
00231     }
00232 
00233 
00234     /* Create a new file */
00235 
00236   return cbf_make_file (file, stream);
00237 }
00238 
00239 
00240   /* Remove a file connection */
00241 
00242 int cbf_delete_fileconnection (cbf_file **file)
00243 {
00244     /* Does the file pointer exist? */
00245 
00246   if (!file)
00247 
00248     return CBF_ARGUMENT;
00249 
00250 
00251     /* Does the file exist? */
00252 
00253   if (!*file)
00254 
00255     return CBF_ARGUMENT;
00256 
00257 
00258     /* Remove a connection */
00259 
00260   (*file)->connections--;
00261 
00262 
00263     /* Delete the file? */
00264 
00265   if ((*file)->connections == 0)
00266 
00267     return cbf_free_file (file);
00268 
00269 
00270     /* Success */
00271 
00272   return 0;
00273 }
00274 
00275 
00276   /* Count the connections */
00277 
00278 int cbf_file_connections (cbf_file *file)
00279 {
00280   if (!file)
00281 
00282     return 0;
00283 
00284   return file->connections;
00285 }
00286 
00287                     
00288   /* Set the size of the buffer */
00289 
00290 int cbf_set_buffersize (cbf_file *file, size_t size)
00291 {
00292   unsigned int kblock;
00293 
00294   size_t  new_size;
00295 
00296     /* Does the file exist? */
00297 
00298   if (!file)
00299 
00300     return CBF_ARGUMENT;
00301 
00302   kblock = 16;
00303 
00304   if (size > 128*2) kblock = 128;
00305 
00306   if (size > 512*2) kblock = 512;
00307 
00308   if (size > 2048*2) kblock = 2048;
00309 
00310   new_size = ((int)(size/kblock))*kblock+kblock;
00311 
00312     /* Is the size already close enough? */
00313 
00314   if (size > 0 && file->buffer_size >=  size && 
00315                   file->buffer_size <= new_size)
00316 
00317     return 0;
00318 
00319 
00320     /* Reallocate the buffer */
00321 
00322   return cbf_realloc ((void **) &file->buffer, 
00323                                 &file->buffer_size, sizeof (char), new_size);
00324 }
00325 
00326 
00327   /* Empty the buffer */
00328 
00329 int cbf_reset_buffer (cbf_file *file)
00330 {
00331     /* Does the file exist? */
00332 
00333   if (!file)
00334 
00335     return CBF_ARGUMENT;
00336 
00337 
00338     /* Empty the buffer */
00339 
00340   file->buffer_used = 0;
00341   
00342   
00343     /* success */
00344     
00345   return 0;
00346 }
00347 
00348 
00349   /* Add a character to the buffer */
00350 
00351 int cbf_save_character (cbf_file *file, int c)
00352 {
00353   unsigned int new_size, kblock;
00354 
00355     /* Does the file exist? */
00356 
00357   if (!file)
00358 
00359     return CBF_ARGUMENT;
00360 
00361 
00362     /* Expand the buffer? */
00363 
00364   kblock = 16;
00365 
00366   if (file->buffer_used+2 > 128*2) kblock = 128;
00367 
00368   if (file->buffer_used+2 > 512*2) kblock = 512;
00369 
00370   if (file->buffer_used+2 > 2048*2) kblock = 2048;
00371 
00372   new_size = (((int)((file->buffer_used+2)/kblock)))*kblock+kblock;
00373 
00374   if (new_size < file->buffer_used+3) new_size = file->buffer_used+3;
00375 
00376   if (new_size >= file->buffer_size)
00377     cbf_failnez (cbf_set_buffersize (file, new_size))
00378 
00379 
00380     /* Add the character */
00381 
00382   file->buffer [file->buffer_used] = (char) c;
00383 
00384   file->buffer_used++;
00385 
00386   file->buffer [file->buffer_used] = '\0';
00387 
00388 
00389     /* Success */
00390   
00391   return 0;
00392 }
00393 
00394 
00395   /* Retrieve the buffer */
00396 
00397 int cbf_get_buffer (cbf_file *file, const char **buffer,
00398                                          size_t *buffer_size)
00399 {
00400     /* Does the file exist? */
00401 
00402   if (!file)
00403 
00404     return CBF_ARGUMENT;
00405     
00406     
00407     /* Copy the buffer */
00408     
00409   if (buffer)
00410   
00411     if (file->buffer_used <= 0)
00412     
00413       *buffer = NULL;
00414       
00415     else
00416   
00417       *buffer = file->buffer;
00418     
00419     
00420   if (buffer_size)
00421     
00422     *buffer_size = file->buffer_used;
00423     
00424 
00425     /* Success */
00426 
00427   return 0;
00428 }
00429 
00430 
00431   /* Get the file coordinates */
00432 
00433 int cbf_get_filecoordinates (cbf_file *file, unsigned int *line,
00434                                              unsigned int *column)
00435 {
00436     /* Does the file exist? */
00437 
00438   if (!file)
00439 
00440     return CBF_ARGUMENT;
00441 
00442 
00443     /* Read the coordinates */
00444 
00445   if (line)
00446 
00447     *line = file->line;
00448     
00449   if (column)
00450 
00451     *column = file->column;
00452     
00453 
00454     /* Success */
00455 
00456   return 0;
00457 }
00458                                              
00459 
00460   /* Set the file coordinates */
00461 
00462 int cbf_set_filecoordinates (cbf_file *file, unsigned int line,
00463                                              unsigned int column)
00464 {
00465     /* Does the file exist? */
00466 
00467   if (!file)
00468 
00469     return CBF_ARGUMENT;
00470 
00471 
00472     /* Set the coordinates */
00473 
00474   file->line = line;
00475     
00476   file->column = column;
00477     
00478 
00479     /* Success */
00480 
00481   return 0;
00482 }
00483                                              
00484 
00485   /* Read the next bit */
00486 
00487 int cbf_get_bit (cbf_file *file)
00488 {
00489   int bit;
00490   
00491   if (file->bits [0] == 0)
00492   {
00493     file->bits [1] = getc (file->stream);
00494 
00495     if (file->bits [1] == EOF)
00496 
00497       return EOF;
00498 
00499     file->bits [0] = 8;
00500   }
00501   
00502   bit = file->bits [1] & 1;
00503 
00504   file->bits [1] >>= 1;
00505   
00506   file->bits [0]--;
00507 
00508 
00509     /* Success */
00510 
00511   return bit;
00512 }
00513 
00514 
00515   /* Read the next bits (signed) */
00516 
00517 int cbf_get_bits (cbf_file *file, int *bitslist, int bitcount)
00518 {
00519   int bitcode, count, m, maxbits;
00520 
00521 
00522     /* Number of bits in an integer */
00523 
00524   maxbits = sizeof (int) * CHAR_BIT;
00525 
00526 
00527     /* Read the bits in int-sized blocks */
00528 
00529   while (bitcount > maxbits)
00530   {
00531     cbf_failnez (cbf_get_bits (file, bitslist, maxbits))
00532 
00533     bitslist++;
00534 
00535     bitcount -= maxbits;
00536   }
00537 
00538 
00539     /* Read the bits into an int */
00540     
00541   count = file->bits [0];
00542 
00543   bitcode = file->bits [1] & 0x0ff;
00544 
00545   while (count < bitcount)
00546   {
00547     file->bits [1] = getc (file->stream);
00548 
00549     if (file->bits [1] == EOF)
00550 
00551       return CBF_FILEREAD;
00552 
00553     file->bits [0] = 8;
00554 
00555     bitcode |= (file->bits [1] << count) & -(1 << count);
00556 
00557     count += 8;
00558   }
00559 
00560   file->bits [1] = (file->bits [1] >> (file->bits [0] - (count - bitcount)));
00561 
00562   file->bits [0] = count - bitcount;
00563 
00564 
00565     /* Sign-extend */
00566 
00567   m = 1 << (bitcount - 1);
00568 
00569   if (bitcode & m)
00570 
00571     *bitslist = bitcode | -m;
00572 
00573   else
00574 
00575     *bitslist = bitcode & ~-m;
00576 
00577 
00578     /* Success */
00579 
00580   return 0;
00581 }
00582 
00583 
00584   /* Write bits */
00585 
00586 int cbf_put_bits (cbf_file *file, int *bitslist, int bitcount)
00587 {
00588   int resultcode, maxbits, bits0, bits1;
00589 
00590 
00591     /* Number of bits in an integer */
00592 
00593   maxbits = sizeof (int) * CHAR_BIT;
00594 
00595 
00596     /* Write the bits in int-sized blocks */
00597 
00598   while (bitcount > maxbits)
00599   {
00600     cbf_failnez (cbf_put_bits (file, bitslist, maxbits))
00601 
00602     bitslist++;
00603 
00604     bitcount -= maxbits;
00605   }
00606 
00607 
00608   bits0 = file->bits [0];
00609   bits1 = file->bits [1];
00610 
00611 
00612     /* Get the first 8 bits */
00613 
00614   bits1 |= (*bitslist & 0x0ff) << bits0;
00615   bits0 +=  bitcount;
00616 
00617 
00618     /* Write 8 bits? */
00619 
00620   if (bits0 >= 8)
00621   {
00622       /* Add the character to the character buffer */
00623       
00624     file->characters [file->characters_used] = bits1 & 0xff;
00625     
00626     file->characters_used++;
00627     
00628     if (file->characters_used == 64)
00629     {
00630       resultcode = cbf_flush_characters (file);
00631        
00632       if (resultcode)
00633       {
00634         file->bits [0] = bits0;
00635         file->bits [1] = bits1;
00636 
00637         return resultcode;
00638       }
00639     }
00640 
00641     bits0 -= 8;
00642 
00643 
00644       /* Get the remaining bits */
00645 
00646     bits1 = *bitslist >> (bitcount - bits0);
00647 
00648 
00649       /* Write the remaining bits */
00650 
00651     while (bits0 >= 8)
00652     {
00653       file->characters [file->characters_used] = bits1 & 0xff;
00654     
00655       file->characters_used++;
00656     
00657       if (file->characters_used == 64)
00658       {
00659         resultcode = cbf_flush_characters (file);
00660        
00661         if (resultcode)
00662         {
00663           file->bits [0] = bits0;
00664           file->bits [1] = bits1;
00665 
00666           return resultcode;
00667         }
00668       }
00669 
00670       bits1 >>= 8;
00671       bits0 -=  8;
00672     }
00673   }
00674 
00675   bits1 &= ~-(1 << bits0);
00676 
00677   file->bits [0] = bits0;
00678   file->bits [1] = bits1;
00679 
00680 
00681     /* Success */
00682 
00683   return 0;
00684 }
00685 
00686 
00687   /* Read an integer as a series of bits */
00688 
00689 int cbf_get_integer (cbf_file *file, int *val, int valsign,
00690                                                int bitcount)
00691 {
00692   int maxbits, signbits, valbits, sign, errorcode, deval;
00693 
00694 
00695     /* Make sure there is a destination */
00696 
00697   if (!val)
00698   
00699     val = &deval;
00700     
00701 
00702     /* Any bits to read? */
00703 
00704   if (bitcount <= 0)
00705   {
00706     *val = 0;
00707 
00708     return 0;
00709   }
00710 
00711 
00712     /* Number of bits in an integer */
00713 
00714   maxbits = sizeof (int) * CHAR_BIT;
00715 
00716 
00717     /* Number of bits in the value and sign parts */
00718 
00719   signbits = bitcount - sizeof (signed long) * CHAR_BIT;
00720 
00721   if (signbits > 0)
00722 
00723     valbits = bitcount - signbits;
00724 
00725   else
00726 
00727     valbits = bitcount;
00728 
00729 
00730     /* Read the value */
00731 
00732   cbf_failnez (cbf_get_bits (file, val, valbits))
00733 
00734 
00735     /* Fix the sign */
00736 
00737   if (valbits < maxbits && valsign == 0)
00738 
00739     *val &= ~-(1 << valbits);
00740 
00741 
00742     /* Read the sign bits */
00743 
00744   errorcode = 0;
00745 
00746   while (signbits > 0)
00747   {
00748     if (signbits < maxbits)
00749 
00750       cbf_failnez (cbf_get_bits (file, &sign, signbits))
00751 
00752     else
00753 
00754       cbf_failnez (cbf_get_bits (file, &sign, maxbits))
00755 
00756     signbits -= maxbits;
00757 
00758 
00759       /* Overflow? */
00760 
00761     if (sign != -(*val < 0 && valsign))
00762     {
00763       errorcode = CBF_OVERFLOW;
00764 
00765       if (valsign)
00766 
00767         *val = -(sign >= 0) ^ (1 << (maxbits - 1));
00768 
00769       else
00770 
00771         *val = -1;
00772     }
00773   }
00774 
00775   return errorcode;
00776 }
00777 
00778 
00779   /* Write an integer as a series of bits */
00780 
00781 int cbf_put_integer (cbf_file *file, int val, int valsign,
00782                                               int bitcount)
00783 {
00784   int maxbits, signbits, valbits, sign;
00785 
00786 
00787     /* Any bits to write? */
00788 
00789   if (bitcount <= 0)
00790 
00791     return 0;
00792 
00793 
00794     /* Number of bits in an integer */
00795 
00796   maxbits = sizeof (int) * CHAR_BIT;
00797 
00798 
00799     /* Number of bits in the value and sign parts */
00800 
00801   signbits = bitcount - maxbits;
00802 
00803   if (signbits > 0)
00804 
00805     valbits = bitcount - signbits;
00806 
00807   else
00808 
00809     valbits = bitcount;
00810 
00811 
00812     /* Sign value */
00813 
00814   sign = -(val < 0 && valsign);
00815 
00816 
00817     /* Write the value */
00818 
00819   cbf_failnez (cbf_put_bits (file, &val, valbits))
00820 
00821 
00822     /* Write the sign part */
00823 
00824   while (signbits >= maxbits)
00825   {
00826     cbf_failnez (cbf_put_bits (file, &sign, maxbits))
00827 
00828     signbits -= maxbits;
00829   }
00830 
00831   if (signbits > 0)
00832 
00833     cbf_failnez (cbf_put_bits (file, &sign, signbits))
00834 
00835 
00836     /* Success */
00837 
00838   return 0;
00839 }
00840 
00841 
00842   /* Initialize a message digest */
00843   
00844 int cbf_start_digest (cbf_file *file)
00845 {
00846   if (!file)
00847 
00848     return CBF_ARGUMENT;
00849     
00850     
00851     /* Flush the buffers */
00852 
00853   cbf_failnez (cbf_flush_characters (file))
00854   
00855 
00856     /* Allocate the md5 context */
00857     
00858   if (!file->digest)
00859 
00860     cbf_failnez (cbf_alloc ((void **) &file->digest, 
00861                                        NULL, sizeof (MD5_CTX), 1))
00862                                        
00863 
00864     /* Initialize */
00865     
00866   MD5Init (file->digest);
00867 
00868 
00869     /* Success */
00870     
00871   return 0;
00872 }
00873 
00874 
00875   /* Get the message digest */
00876   
00877 int cbf_end_digest (cbf_file *file, char *digest)
00878 {
00879   unsigned char raw_digest [16];
00880   
00881   if (!file || !digest)
00882 
00883     return CBF_ARGUMENT;
00884     
00885   if (!file->digest)
00886   
00887     return CBF_ARGUMENT;
00888   
00889     
00890     /* Flush the buffers */
00891 
00892   cbf_failnez (cbf_flush_characters (file))
00893   
00894 
00895     /* Get the raw digest */
00896     
00897   MD5Final (raw_digest, file->digest);
00898   
00899   
00900     /* Free the md5 context */
00901     
00902   cbf_failnez (cbf_free ((void **) &file->digest, NULL))
00903   
00904   
00905     /* Encode the digest in base-64 */
00906     
00907   cbf_md5digest_to64 (digest, raw_digest);
00908 
00909   
00910     /* Success */
00911     
00912   return 0;
00913 }
00914 
00915 
00916   /* Flush the bit buffer */
00917 
00918 int cbf_flush_bits (cbf_file *file)
00919 {
00920   if (!file)
00921 
00922     return CBF_ARGUMENT;
00923 
00924 
00925     /* Flush any partial bytes into the character buffer */
00926     
00927   cbf_failnez (cbf_put_integer (file, 0, 0, 7))
00928   
00929   
00930     /* Reset the bit buffers */
00931     
00932   file->bits [0] = 0;
00933   file->bits [1] = 0;
00934 
00935 
00936     /* Write the characters */
00937 
00938   return cbf_flush_characters (file);
00939 }
00940 
00941 
00942   /* Flush the character buffer */
00943 
00944 int cbf_flush_characters (cbf_file *file)
00945 {
00946   int done;
00947   
00948   if (!file)
00949 
00950     return CBF_ARGUMENT;
00951 
00952 
00953     /* Write the characters */
00954     
00955   if (file->characters_used == 0)
00956   
00957     return 0;
00958 
00959   done = fwrite (file->characters, 1, file->characters_used, file->stream);
00960 
00961 
00962     /* Update the message digest */
00963 
00964   if (done > 0 && file->digest) 
00965 
00966     MD5Update (file->digest, file->characters, done);
00967 
00968 
00969     /* Make sure the file is really updated */
00970 
00971   if (done > 0)
00972   
00973     fflush (file->stream);
00974 
00975     
00976     /* Remove the characters written */
00977 
00978   if (done < file->characters_used)
00979   {
00980     if (done > 0)
00981     {
00982       memmove (file->characters, file->characters + done, 64 - done);
00983         
00984       file->characters_used = 64 - done;
00985     }
00986 
00987     return CBF_FILEWRITE;
00988   }
00989 
00990   file->characters_used = 0;
00991 
00992 
00993     /* Success */
00994 
00995   return 0;
00996 }
00997 
00998 
00999   /* Discard any bits in the bits buffers */
01000 
01001 int cbf_reset_bits (cbf_file *file)
01002 {
01003   if (!file)
01004 
01005     return CBF_ARGUMENT;
01006     
01007   file->bits [0] = 0;
01008   file->bits [1] = 0;
01009   
01010   return cbf_reset_characters (file);
01011 }
01012 
01013 
01014   /* Discard any characters in the character buffers */
01015 
01016 int cbf_reset_characters (cbf_file *file)
01017 {
01018   if (!file)
01019 
01020     return CBF_ARGUMENT;
01021     
01022   file->characters_used = 0;
01023 
01024 
01025     /* Success */
01026 
01027   return 0;
01028 }
01029 
01030 
01031   /* Get the next character */
01032 
01033 int cbf_get_character (cbf_file *file)
01034 {
01035   if (file->stream)
01036 
01037     file->last_read = fgetc (file->stream);
01038 
01039   else
01040 
01041     file->last_read = EOF;
01042 
01043   return file->last_read;
01044 }
01045 
01046 
01047   /* Read the next character (convert end-of-line and update line and column) */
01048 
01049 int cbf_read_character (cbf_file *file)
01050 {
01051   int last, current;
01052 
01053 
01054     /* Does the file exist? */
01055 
01056   if (!file)
01057 
01058     return EOF;
01059 
01060 
01061     /* Read the next character */
01062 
01063   last = file->last_read;
01064 
01065   current = cbf_get_character (file);
01066 
01067   if ((current == '\n' && last == '\r') ||
01068       (current == '\r' && last == '\n'))
01069 
01070     current = cbf_get_character (file);
01071 
01072 
01073     /* Convert the end-of-line character and update line and column */
01074 
01075   if (current == '\n' || current == '\r')
01076   {
01077     current = '\n';
01078 
01079     file->column = 0;
01080 
01081     file->line++;
01082   }
01083   else
01084 
01085     if (current == '\t')
01086 
01087       file->column = (file->column & ~0x07) + 8;
01088       
01089     else
01090     
01091       file->column++;
01092 
01093   return current;
01094 }
01095 
01096 
01097   /* Put a character */
01098 
01099 int cbf_put_character (cbf_file *file, int c)
01100 {
01101     /* Does the file exist? */
01102 
01103   if (!file)
01104 
01105     return EOF;
01106 
01107 
01108     /* Flush the buffer? */
01109 
01110   if (file->characters_used == 64)
01111   
01112     cbf_failnez (cbf_flush_characters (file))
01113 
01114 
01115     /* Add the character */
01116        
01117   file->characters [file->characters_used] = c & 0xff;
01118     
01119   file->characters_used++;
01120     
01121 
01122     /* Success */
01123     
01124   return 0;
01125 }
01126 
01127 
01128   /* Write a character (convert end-of-line and update line and column) */
01129 
01130 int cbf_write_character (cbf_file *file, int c)
01131 {
01132     /* Does the file exist? */
01133 
01134   if (!file)
01135 
01136     return EOF;
01137 
01138 
01139     /* Write the next character */
01140 
01141   if (c == '\n')
01142   {
01143       /* Line termination */
01144       
01145     if (file->write_encoding & ENC_CRTERM)
01146 
01147       cbf_failnez (cbf_put_character (file, '\r'))
01148 
01149     if (file->write_encoding & ENC_LFTERM)
01150 
01151       cbf_failnez (cbf_put_character (file, '\n'))
01152 
01153 
01154       /* Update line and column */
01155 
01156     if (c == '\n')
01157     {
01158       file->column = 0;
01159 
01160       file->line++;
01161     }
01162   }
01163   else
01164   {
01165     cbf_failnez (cbf_put_character (file, c))
01166 
01167 
01168       /* Update column */
01169 
01170     if (c == '\t')
01171 
01172       file->column = (file->column & ~0x07) + 8;
01173       
01174     else
01175     
01176       file->column++;
01177   }
01178 
01179 
01180     /* Success */
01181 
01182   return 0;
01183 }
01184 
01185 
01186   /* Put a string */
01187 
01188 int cbf_put_string (cbf_file *file, const char *string)
01189 {
01190     /* Does the string exist? */
01191 
01192   if (!string)
01193 
01194     return CBF_ARGUMENT;
01195     
01196 
01197     /* Write the string one character at a time */
01198     
01199   while (*string)
01200   {
01201     cbf_failnez (cbf_put_character (file, *string))
01202     
01203     string++;
01204   }
01205 
01206 
01207     /* Success */
01208 
01209   return 0;
01210 }
01211 
01212 
01213   /* Write a string (convert end-of-line and update line and column) */
01214 
01215 int cbf_write_string (cbf_file *file, const char *string)
01216 {
01217     /* Does the string exist? */
01218 
01219   if (!string)
01220 
01221     return CBF_ARGUMENT;
01222     
01223 
01224     /* Write the string */
01225 
01226   while (*string)
01227   {
01228     cbf_failnez (cbf_write_character (file, *string))
01229     
01230     string++;
01231   }
01232   
01233 
01234     /* Success */
01235 
01236   return 0;
01237 }
01238 
01239 
01240   /* Read a (CR/LF)-terminated line into the buffer */
01241 
01242 int cbf_read_line (cbf_file *file, const char **line)
01243 {
01244   int c;
01245   
01246   
01247     /* Does the file exist? */
01248     
01249   if (!file)
01250 
01251     return CBF_ARGUMENT;
01252 
01253 
01254     /* Empty the buffer */
01255     
01256   file->buffer_used = 0;
01257 
01258   file->column = 0;
01259 
01260 
01261     /* Read the characters */
01262  
01263   do
01264   {
01265     c = cbf_read_character (file);
01266     
01267     if (c == EOF)
01268     
01269       return CBF_FILEREAD;
01270       
01271     cbf_failnez (cbf_save_character (file, c))
01272 
01273   }
01274   while (c != '\n');
01275 
01276 
01277     /* Copy the pointer */
01278     
01279   if (line)
01280   
01281     *line = file->buffer;
01282     
01283 
01284     /* Success */
01285 
01286   return 0;
01287 }
01288 
01289 
01290   /* Read nelem characters into the buffer */
01291 
01292 int cbf_get_block (cbf_file *file, size_t nelem)
01293 {
01294   size_t done;
01295 
01296   
01297     /* Does the file exist? */
01298     
01299   if (!file)
01300 
01301     return CBF_ARGUMENT;
01302 
01303 
01304     /* Set the buffer size */
01305 
01306   cbf_failnez (cbf_set_buffersize (file, nelem))
01307 
01308 
01309     /* Read the characters */
01310 
01311   file->buffer_used = 0;
01312   
01313   while (file->buffer_used < nelem)
01314   {
01315     if (file->stream)
01316     
01317       done = fread (file->buffer + file->buffer_used, 1,
01318                            nelem - file->buffer_used, file->stream);
01319 
01320     else
01321 
01322       done = 0;
01323 
01324     if (done <= 0)
01325 
01326       return CBF_FILEREAD;
01327 
01328     file->buffer_used += done;
01329   }
01330 
01331 
01332     /* Success */
01333 
01334   return 0;
01335 }
01336 
01337 
01338   /* Write nelem characters from the buffer */
01339 
01340 int cbf_put_block (cbf_file *file, size_t nelem)
01341 {
01342   size_t done;
01343 
01344   
01345     /* Does the file exist? */
01346     
01347   if (!file)
01348 
01349     return CBF_ARGUMENT;
01350 
01351 
01352     /* Are there enough characters in the buffer? */
01353 
01354   if (nelem > file->buffer_size)
01355 
01356     return CBF_ARGUMENT;
01357 
01358 
01359     /* Flush the buffers */
01360     
01361   cbf_failnez (cbf_flush_characters (file))
01362   
01363 
01364     /* Write the characters */
01365 
01366   if (file->stream && nelem)
01367     
01368     done = fwrite (file->buffer, 1, nelem, file->stream);
01369 
01370   else
01371 
01372     done = 0;
01373     
01374     
01375     /* Update the message digest */
01376     
01377   if (done > 0 && file->digest)
01378 
01379     MD5Update (file->digest, file->buffer, done);
01380     
01381 
01382     /* Fail? */
01383 
01384   if (done < nelem)
01385 
01386     return CBF_FILEWRITE;
01387 
01388 
01389     /* Success */
01390 
01391   return 0;
01392 }
01393 
01394 
01395   /* Copy characters between files */
01396 
01397 int cbf_copy_file (cbf_file *destination, cbf_file *source, size_t nelem)
01398 {
01399   size_t done, todo;
01400 
01401 
01402     /* Do the files exist? */
01403     
01404   if (!destination || !source)
01405 
01406     return CBF_ARGUMENT;
01407 
01408   if (!destination->stream || !source->stream)
01409 
01410     return CBF_ARGUMENT;
01411 
01412 
01413     /* Flush the buffers */
01414     
01415   cbf_failnez (cbf_flush_characters (destination))
01416   
01417 
01418     /* Copy the characters in blocks of up to 1024 */
01419     
01420   while (nelem > 0)
01421   {
01422     if (nelem >= 1024)
01423 
01424       todo = 1024;
01425 
01426     else
01427 
01428       todo = nelem;
01429 
01430     cbf_failnez (cbf_get_block (source, todo))
01431 
01432     done = fwrite (source->buffer, 1, todo, destination->stream);
01433     
01434     
01435       /* Update the message digest */
01436       
01437     if (done > 0 && destination->digest)
01438 
01439       MD5Update (destination->digest, source->buffer, done);
01440       
01441       
01442       /* Fail? */
01443 
01444     if (done < todo)
01445 
01446       return CBF_FILEWRITE;
01447 
01448     nelem -= done;
01449   }
01450 
01451 
01452     /* Success */
01453 
01454   return 0;
01455 }
01456 
01457 
01458   /* Get the file position */
01459 
01460 int cbf_get_fileposition (cbf_file *file, long int *position)
01461 {
01462   long int file_position;
01463   
01464   
01465     /* Does the file exist? */
01466     
01467   if (!file)
01468 
01469     return CBF_ARGUMENT;
01470     
01471   if (!file->stream)
01472   
01473     return CBF_ARGUMENT;
01474     
01475     
01476     /* Get the position */
01477     
01478   file_position = ftell (file->stream);
01479   
01480   if (file_position == -1L)
01481   
01482     return CBF_FILETELL;
01483     
01484   if (position)
01485   
01486     *position = file_position;
01487     
01488     
01489     /* Success */
01490     
01491   return 0;
01492 }
01493                                              
01494 
01495   /* Set the file position */
01496 
01497 int cbf_set_fileposition (cbf_file *file, long int position, int whence)
01498 {
01499     /* Does the file exist? */
01500     
01501   if (!file)
01502 
01503     return CBF_ARGUMENT;
01504     
01505   if (!file->stream)
01506   
01507     return CBF_ARGUMENT;
01508     
01509     
01510     /* Set the position */
01511     
01512  if (fseek (file->stream, position, whence) < 0)
01513 
01514    return CBF_FILESEEK;
01515     
01516     
01517     /* Success */
01518     
01519   return 0;
01520 }
01521 
01522 
01523 #ifdef __cplusplus
01524 
01525 }
01526 
01527 #endif