cbf_codes.c

Go to the documentation of this file.
00001 /**********************************************************************
00002  * cbf_codes -- convert between encoded and unencoded binary          *
00003  *              calculate message digest                              *
00004  *                                                                    *
00005  * Version 0.6 13 January 1999                                        *
00006  *                                                                    *
00007  *            Paul Ellis (ellis@ssrl.slac.stanford.edu) and           *
00008  *         Herbert J. Bernstein (yaya@bernstein-plus-sons.com)        *
00009  **********************************************************************/
00010   
00011 /**********************************************************************
00012  *                               NOTICE                               *
00013  * Creative endeavors depend on the lively exchange of ideas. There   *
00014  * are laws and customs which establish rights and responsibilities   *
00015  * for authors and the users of what authors create.  This notice     *
00016  * is not intended to prevent you from using the software and         *
00017  * documents in this package, but to ensure that there are no         *
00018  * misunderstandings about terms and conditions of such use.          *
00019  *                                                                    *
00020  * Please read the following notice carefully.  If you do not         *
00021  * understand any portion of this notice, please seek appropriate     *
00022  * professional legal advice before making use of the software and    *
00023  * documents included in this software package.  In addition to       *
00024  * whatever other steps you may be obliged to take to respect the     *
00025  * intellectual property rights of the various parties involved, if   *
00026  * you do make use of the software and documents in this package,     *
00027  * please give credit where credit is due by citing this package,     *
00028  * its authors and the URL or other source from which you obtained    *
00029  * it, or equivalent primary references in the literature with the    *
00030  * same authors.                                                      *
00031  *                                                                    *
00032  * Some of the software and documents included within this software   *
00033  * package are the intellectual property of various parties, and      *
00034  * placement in this package does not in any way imply that any       *
00035  * such rights have in any way been waived or diminished.             *
00036  *                                                                    *
00037  * With respect to any software or documents for which a copyright    *
00038  * exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT.   *
00039  *                                                                    *
00040  * Even though the authors of the various documents and software      *
00041  * found here have made a good faith effort to ensure that the        *
00042  * documents are correct and that the software performs according     *
00043  * to its documentation, and we would greatly appreciate hearing of   *
00044  * any problems you may encounter, the programs and documents any     *
00045  * files created by the programs are provided **AS IS** without any   *
00046  * warranty as to correctness, merchantability or fitness for any     *
00047  * particular or general use.                                         *
00048  *                                                                    *
00049  * THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF    *
00050  * PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE   *
00051  * PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS   *
00052  * OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE          *
00053  * PROGRAMS OR DOCUMENTS.                                             *
00054  **********************************************************************/
00055  
00056 /**********************************************************************
00057  *                          The IUCr Policy                           *
00058  *                                 on                                 *
00059  *     the Use of the Crystallographic Information File (CIF)         *
00060  *                                                                    *
00061  * The Crystallographic Information File (Hall, Allen & Brown,        *
00062  * 1991) is, as of January 1992, the recommended method for           *
00063  * submitting publications to Acta Crystallographica Section C. The   *
00064  * International Union of Crystallography holds the Copyright on      *
00065  * the CIF, and has applied for Patents on the STAR File syntax       *
00066  * which is the basis for the CIF format.                             *
00067  *                                                                    *
00068  * It is a principal objective of the IUCr to promote the use of      *
00069  * CIF for the exchange and storage of scientific data. The IUCr's    *
00070  * sponsorship of the CIF development was motivated by its            *
00071  * responsibility to its scientific journals, which set the           *
00072  * standards in crystallographic publishing. The IUCr intends that    *
00073  * CIFs will be used increasingly for electronic submission of        *
00074  * manuscripts to these journals in future. The IUCr recognises       *
00075  * that, if the CIF and the STAR File are to be adopted as a means    *
00076  * for universal data exchange, the syntax of these files must be     *
00077  * strictly and uniformly adhered to. Even small deviations from      *
00078  * the syntax would ultimately cause the demise of the universal      *
00079  * file concept. Through its Copyrights and Patents the IUCr has      *
00080  * taken the steps needed to ensure strict conformance with this      *
00081  * syntax.                                                            *
00082  *                                                                    *
00083  * The IUCr policy on the use of the CIF and STAR File processes is   *
00084  * as follows:                                                        *
00085  * _________________________________________________________________  *
00086  *                                                                    *
00087  *  * 1 CIFs and STAR Files may be generated, stored or transmitted,  *
00088  *    without permission or charge, provided their purpose is not     *
00089  *    specifically for profit or commercial gain, and provided that   *
00090  *    the published syntax is strictly adhered to.                    *
00091  *  * 2 Computer software may be developed for use with CIFs or STAR  *
00092  *    files, without permission or charge, provided it is distributed *
00093  *    in the public domain. This condition also applies to software   *
00094  *    for which a charge is made, provided that its primary function  *
00095  *    is for use with files that satisfy condition 1 and that it is   *
00096  *    distributed as a minor component of a larger package of         *
00097  *    software.                                                       *
00098  *  * 3 Permission will be granted for the use of CIFs and STAR Files *
00099  *    for specific commercial purposes (such as databases or network  *
00100  *    exchange processes), and for the distribution of commercial     *
00101  *    CIF/STAR software, on written application to the IUCr Executive *
00102  *    Secretary, 2 Abbey Square, Chester CH1 2HU, England. The        *
00103  *    nature, terms and duration of the licences granted will be      *
00104  *    determined by the IUCr Executive and Finance Committees.        *
00105  *                                                                    *
00106  * _________________________________________________________________  *
00107  *                                                                    *
00108  * In summary, the IUCr wishes to promote the use of the STAR File    *
00109  * concepts as a standard universal data file. It will insist on      *
00110  * strict compliance with the published syntax for all                *
00111  * applications. To assist with this compliance, the IUCr provides    *
00112  * public domain software for checking the logical integrity of a     *
00113  * CIF, and for validating the data name definitions contained        *
00114  * within a CIF. Detailed information on this software, and the       *
00115  * associated dictionaries, may be obtained from the IUCr Office at   *
00116  * 5 Abbey Square, Chester CH1 2HU, England.                          *
00117  **********************************************************************/
00118 
00119 /**********************************************************************
00120  * Substantial portions of this code were derived from the mpack      *
00121  * routine codes.c, which contains the following two notices          *
00122  **********************************************************************/
00123 
00124 /**********************************************************************
00125  * First notice from mpack routine codes.c:                           *
00126  *                                                                    *
00127  * (C) Copyright 1993,1994 by Carnegie Mellon University              *
00128  * All Rights Reserved.                                               *
00129  *                                                                    *
00130  * Permission to use, copy, modify, distribute, and sell this         *
00131  * software and its documentation for any purpose is hereby granted   *
00132  * without fee, provided that the above copyright notice appear       *
00133  * in all copies and that both that copyright notice and this         *
00134  * permission notice appear in supporting documentation, and that     *
00135  * the name of Carnegie Mellon University not be used in advertising  *
00136  * or publicity  pertaining to distribution of the software without   *
00137  * specific, written prior permission.  Carnegie Mellon University    *
00138  * makes no representations about the suitability of this software    *
00139  * for any purpose.  It is provided "as is" without express or        *
00140  * implied warranty.                                                  *
00141  *                                                                    *
00142  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO *
00143  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY *
00144  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE       *
00145  * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY   *
00146  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,    *
00147  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS     *
00148  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR            *
00149  * PERFORMANCE OF THIS SOFTWARE.                                      *
00150  **********************************************************************/
00151 
00152 /**********************************************************************
00153  * Second  notice from mpack routine codes.c:                         *
00154  *                                                                    *
00155  * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)   *
00156  *                                                                    *
00157  * Permission to use, copy, modify, and distribute this material      *
00158  * for any purpose and without fee is hereby granted, provided        *
00159  * that the above copyright notice and this permission notice         *
00160  * appear in all copies, and that the name of Bellcore not be         *
00161  * used in advertising or publicity pertaining to this                *
00162  * material without the specific, prior written permission            *
00163  * of an authorized representative of Bellcore.  BELLCORE             *
00164  * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY         *
00165  * OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS",         *
00166  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.                         *
00167  **********************************************************************/
00168 
00169 #ifdef __cplusplus
00170 
00171 extern "C" {
00172 
00173 #endif
00174 
00175 #include "cbf_codes.h"
00176 
00177 #include <stdlib.h>
00178 #include <string.h>
00179 #include <ctype.h>
00180 
00181 
00182   /* Check a 24-character base-64 MD5 digest */
00183 
00184 int cbf_is_base64digest (const char *encoded_digest)
00185 {
00186   static char basis_64 [] =
00187 
00188        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00189        
00190   if (!encoded_digest)
00191   
00192     return 0;
00193 
00194   if (strlen (encoded_digest) != 24)
00195 
00196     return 0;
00197     
00198   return strspn (encoded_digest, basis_64) == 22 &&
00199                  encoded_digest [22] == '=' &&
00200                  encoded_digest [23] == '=';
00201 }
00202 
00203 
00204   /* Encode a 16-character MD5 digest in base-64 (25 characters) */
00205 
00206 int cbf_md5digest_to64 (char *encoded_digest, const unsigned char *digest)
00207 {
00208   static char basis_64 [] =
00209 
00210        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00211 
00212   int todo;
00213   
00214   if (!encoded_digest || !digest)
00215   
00216     return CBF_ARGUMENT;
00217   
00218 
00219     /* Encode the 16 characters in base 64 */
00220     
00221   for (todo = 0; todo < 18; todo += 3)
00222   {
00223     encoded_digest [0] = basis_64 [((digest [todo + 0] >> 2) & 0x03f)];
00224 
00225     if (todo < 15)
00226     {
00227       encoded_digest [1] = basis_64 [((digest [todo + 0] << 4) & 0x030) |
00228                                      ((digest [todo + 1] >> 4) & 0x00f)];
00229       encoded_digest [2] = basis_64 [((digest [todo + 1] << 2) & 0x03c) |
00230                                      ((digest [todo + 2] >> 6) & 0x003)];
00231       encoded_digest [3] = basis_64 [((digest [todo + 2])      & 0x03f)];
00232     }
00233     else
00234     {
00235       encoded_digest [1] = basis_64 [((digest [todo + 0] << 4) & 0x030)];
00236 
00237       encoded_digest [2] = encoded_digest [3] = '=';
00238     }
00239 
00240     encoded_digest += 4;
00241   } 
00242   
00243   *encoded_digest  = '\0';
00244 
00245   return 0;
00246 }    
00247 
00248 
00249   /* Calculate the MD5 digest (25 characters) of a block of data */
00250 
00251 int cbf_md5digest (cbf_file *file, size_t size, char *digest)
00252 {
00253   MD5_CTX context;
00254   
00255   unsigned char rawdigest [17];
00256 
00257   unsigned int todo;
00258   
00259   const char *buffer;
00260 
00261 
00262     /* Initialise the MD5 context */
00263 
00264   MD5Init (&context);
00265 
00266 
00267     /* Update the digest in blocks of 1024 */
00268 
00269   while (size > 0)
00270   {
00271     if (size >= 1024)
00272 
00273       todo = 1024;
00274 
00275     else
00276 
00277       todo = size;
00278 
00279     cbf_failnez (cbf_get_block (file, todo))
00280     
00281     cbf_failnez (cbf_get_buffer (file, &buffer, NULL))
00282 
00283     MD5Update (&context, buffer, todo);
00284 
00285     size -= todo;
00286   }
00287   
00288   
00289     /* Get the final digest */
00290     
00291   MD5Final (rawdigest, &context);
00292 
00293   cbf_md5digest_to64 (digest, rawdigest);
00294 
00295 
00296     /* Success */
00297     
00298   return 0;
00299 }
00300 
00301 
00302   /* Convert binary data to quoted-printable text */
00303 
00304 int cbf_toqp (cbf_file *infile, cbf_file *outfile, size_t size)
00305 {
00306   static char basis_16 [] = "0123456789ABCDEF";
00307 
00308   int c;
00309     
00310     
00311     /* Check the arguments */
00312       
00313   if (!infile || !outfile)
00314     
00315     return CBF_ARGUMENT;
00316 
00317 
00318     /* Copy the characters */      
00319     
00320   while (size > 0)
00321   {
00322       /* Read the next character */
00323         
00324     c = cbf_get_character (infile);
00325       
00326     if (c == EOF)
00327       
00328       return CBF_FILEREAD;
00329     
00330     size--;
00331 
00332     if (outfile->column > 74)
00333       
00334       cbf_failnez (cbf_write_string (outfile, "=\n"))
00335 
00336     if ((c <= 31)  ||
00337         (c >= 39 && c <= 41) ||
00338         (c >= 43 && c <= 47) ||
00339         (c == 58)  ||
00340         (c == 61)  ||
00341         (c == 63)  ||
00342         (c >= 127) || 
00343         (c == ';' && outfile->column == 0))
00344     {
00345         /* Base-16 */
00346         
00347       if (outfile->column > 72)
00348       
00349         cbf_failnez (cbf_write_string (outfile, "=\n"))
00350       
00351       cbf_failnez (cbf_write_character (outfile, '='))
00352       cbf_failnez (cbf_write_character (outfile, basis_16 [(c >> 4) & 0x0f]))
00353       cbf_failnez (cbf_write_character (outfile, basis_16 [c & 0x0f]))
00354     }
00355     else
00356 
00357         /* Base-256 */
00358         
00359       cbf_failnez (cbf_write_character (outfile, c))
00360   }
00361   
00362   if (outfile->column)
00363 
00364     cbf_failnez (cbf_write_string (outfile, "=\n"))
00365 
00366 
00367     /* Flush the buffer */
00368 
00369   cbf_failnez (cbf_flush_characters (outfile))
00370 
00371    
00372     /* Success */
00373     
00374   return 0;
00375 }
00376 
00377 
00378   /* Convert binary data to base-64 text */
00379 
00380 int cbf_tobase64 (cbf_file *infile, cbf_file *outfile, size_t size)
00381 {
00382   static char basis_64 [] =
00383 
00384        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00385 
00386   int c [3];
00387     
00388   int read;
00389     
00390   while (size > 0)
00391   {
00392       /* Read up to 3 characters */
00393         
00394     c [1] = c [2] = 0;
00395 
00396     for (read = 0; read < 3 && read < size; read++)
00397     {
00398       c [read] = cbf_get_character (infile);
00399         
00400       if (c [read] == EOF)
00401         
00402         return CBF_FILEREAD;
00403     }
00404 
00405     size -= read;
00406 
00407     if (outfile->column > 71)
00408     
00409       cbf_failnez (cbf_write_character (outfile, '\n'))
00410 
00411 
00412       /* Write a 24-bit chunk in base-64 */
00413       
00414     cbf_failnez (cbf_write_character (outfile, 
00415                                         basis_64 [(c [0] >> 2) & 0x03f]))
00416     cbf_failnez (cbf_write_character (outfile, 
00417                                         basis_64 [((c [0] << 4) & 0x030) |
00418                                                   ((c [1] >> 4) & 0x00f)]))
00419                                                      
00420     if (read == 1)
00421     
00422       cbf_failnez (cbf_write_string (outfile, "=="))
00423       
00424     else
00425     {
00426       cbf_failnez (cbf_write_character (outfile, 
00427                                         basis_64 [((c [1] << 2) & 0x03c) |
00428                                                   ((c [2] >> 6) & 0x003)]))
00429     
00430       if (read == 2)
00431 
00432         cbf_failnez (cbf_write_character (outfile, '='))
00433 
00434       else 
00435 
00436         cbf_failnez (cbf_write_character (outfile, basis_64 [c [2] & 0x03f]))
00437     }
00438   }
00439   
00440   if (outfile->column)
00441 
00442     cbf_failnez (cbf_write_character (outfile, '\n'))
00443 
00444     
00445     /* Flush the buffer */
00446 
00447   cbf_failnez (cbf_flush_characters (outfile))
00448 
00449    
00450     /* Success */
00451     
00452   return 0;
00453 }
00454 
00455 
00456   /* Convert binary data to base-8/base-10/base-16 text */
00457 
00458 int cbf_tobasex (cbf_file *infile, cbf_file *outfile, size_t size,
00459                                                       size_t elsize,
00460                                                       unsigned int base)
00461 {
00462   int c [8];
00463   
00464   int count, read;
00465   
00466   long l;
00467   
00468   unsigned long block_count;
00469   
00470   char line [96], number [64];
00471   
00472 
00473     /* Check the arguments */
00474     
00475   if (elsize > 8 || (base != 8 && base != 10 && base != 16))
00476   
00477     return CBF_ARGUMENT;
00478   
00479 
00480   block_count = 0;
00481 
00482   while (size > 0)
00483   {
00484       /* End of a 512-element block? */
00485 
00486     if ((block_count % 512) == 0)
00487     {
00488       if (outfile->column)
00489 
00490         cbf_failnez (cbf_write_character (outfile, '\n'))
00491         
00492       if (block_count)
00493       
00494         cbf_failnez (cbf_write_string (outfile, "#\n"))
00495         
00496       if (base == 8)
00497 
00498         cbf_failnez (cbf_write_string (outfile, "# Octal encoding"))
00499         
00500       else
00501       
00502         if (base == 10)
00503 
00504           cbf_failnez (cbf_write_string (outfile, "# Decimal encoding"))
00505           
00506         else
00507         
00508           cbf_failnez (cbf_write_string (outfile, "# Hexadecimal encoding"))
00509 
00510       sprintf (line, ", byte %lu", (unsigned long) block_count * elsize);
00511 
00512       cbf_failnez (cbf_write_string (outfile, line))
00513 
00514       if (outfile->write_encoding & ENC_FORWARD)
00515 
00516         cbf_failnez (cbf_write_string (outfile, ", byte order 1234...\n#\n"))
00517                              
00518       else
00519     
00520         cbf_failnez (cbf_write_string (outfile, ", byte order ...4321\n#\n"))
00521     }
00522 
00523 
00524       /* Read up to elsize characters */
00525         
00526     memset (c, 0, sizeof (c));
00527 
00528     for (read = 0; read < elsize && read < size; read++)
00529     {
00530       c [read] = cbf_get_character (infile);
00531         
00532       if (c [read] == EOF)
00533         
00534         return CBF_FILEREAD;
00535     }
00536     
00537     size -= read;
00538     
00539     block_count++;
00540 
00541 
00542       /* Make the number */
00543 
00544     number [0] = '\0';
00545     
00546     if ((outfile->write_encoding & ENC_BACKWARD) && read < elsize)
00547 
00548       for (count = read; count < elsize; count++)
00549 
00550         strcat (number, "==");
00551 
00552     l = 0;
00553     
00554     if (outfile->write_encoding & ENC_FORWARD)
00555 
00556       for (count = read - 1; count >= 0; count--)
00557         
00558         l = (l << 8) | (c [count] & 0x0ff);
00559 
00560     else
00561 
00562       for (count = 0; count < read; count++)
00563         
00564         l = (l << 8) | (c [count] & 0x0ff);
00565 
00566     if (base == 8)
00567 
00568       sprintf (number + strlen (number), "%lo", l);
00569       
00570     else
00571 
00572       if (base == 10)
00573     
00574         sprintf (number + strlen (number), "%lu", l);
00575         
00576       else
00577 
00578         sprintf (number + strlen (number), "%lX", l);
00579     
00580     if ((outfile->write_encoding & ENC_FORWARD) && read < elsize)
00581 
00582       for (count = read; count < elsize; count++)
00583 
00584         strcat (number, "==");
00585 
00586 
00587       /* Write the number */    
00588 
00589     if (outfile->column + strlen (number) > 74)
00590 
00591       cbf_failnez (cbf_write_character (outfile, '\n'))
00592 
00593     if (outfile->column)
00594 
00595       cbf_failnez (cbf_write_character (outfile, ' '))
00596 
00597     else
00598     {
00599         /* Start a new line */
00600         
00601       if (base == 8)
00602       
00603         cbf_failnez (cbf_write_character (outfile, 'O'))
00604         
00605       else
00606       
00607         if (base == 10)
00608         
00609           cbf_failnez (cbf_write_character (outfile, 'D'))
00610           
00611         else
00612         
00613           cbf_failnez (cbf_write_character (outfile, 'H'))
00614       
00615       sprintf (line, "%1u", (unsigned int) elsize);
00616       
00617       cbf_failnez (cbf_write_string (outfile, line))
00618 
00619       if (outfile->write_encoding & ENC_FORWARD)
00620       
00621         cbf_failnez (cbf_write_string (outfile, "> "))
00622         
00623       else
00624       
00625         cbf_failnez (cbf_write_string (outfile, "< "))
00626     }
00627 
00628     cbf_failnez (cbf_write_string (outfile, number))
00629   }
00630   
00631   if (outfile->column)
00632 
00633     cbf_failnez (cbf_write_character (outfile, '\n'))
00634 
00635     
00636     /* Flush the buffer */
00637 
00638   cbf_failnez (cbf_flush_characters (outfile))
00639 
00640    
00641     /* Success */
00642 
00643   return 0;
00644 }
00645 
00646 
00647   /* Convert quoted-printable text to binary data */
00648 
00649 int cbf_fromqp (cbf_file *infile, cbf_file *outfile, size_t size, 
00650                                                      size_t *readsize,
00651                                                      char *digest)
00652 {
00653   MD5_CTX context;
00654   
00655   unsigned char buffer [64], rawdigest [17];
00656 
00657   int c, bufsize;
00658   
00659   char val [3], *end;
00660     
00661   size_t count;
00662 
00663 
00664     /* Initialise the MD5 context */
00665     
00666   if (digest)
00667 
00668     MD5Init (&context);
00669 
00670 
00671   bufsize = 0;    
00672   
00673   count = 0;
00674     
00675   val [2] = '\0';
00676 
00677   while (count < size)
00678   {
00679       /* Read the (first) character */
00680       
00681     c = cbf_read_character (infile);
00682     
00683     if (c == EOF)
00684     
00685       return CBF_FILEREAD;
00686       
00687       
00688       /* Decode it */
00689       
00690     if (c == '=')
00691     {
00692         /* Get the second character */
00693         
00694       c = cbf_read_character (infile);
00695       
00696       if (c == EOF)
00697       
00698         return CBF_FILEREAD;
00699         
00700       if (c != '\n')
00701       {
00702           /* Get the third character */
00703         
00704         val [0] = c;
00705 
00706         c = cbf_read_character (infile);
00707 
00708         if (c == EOF)
00709       
00710           return CBF_FILEREAD;
00711           
00712         val [1] = c;
00713           
00714         
00715           /* Calculate the value */
00716           
00717         c = strtoul (val, &end, 16);
00718         
00719         if (end != &val [2])
00720         
00721           return CBF_FORMAT;
00722       }
00723     } 
00724     
00725     
00726       /* Save it */
00727       
00728     if (outfile)
00729 
00730       cbf_failnez (cbf_put_character (outfile, c))
00731 
00732     if (digest)
00733     {
00734       buffer [bufsize] = c;
00735       
00736       bufsize++;
00737 
00738       if (bufsize > 63)
00739       {
00740         MD5Update (&context, buffer, 64);
00741 
00742         bufsize = 0;
00743       }
00744     }
00745 
00746     count++;
00747   }
00748   
00749   
00750     /* Get the digest */
00751 
00752   if (digest)
00753   {
00754     if (bufsize)
00755 
00756       MD5Update (&context, buffer, bufsize);
00757 
00758     MD5Final (rawdigest, &context);
00759 
00760     cbf_md5digest_to64 (digest, rawdigest);
00761   }
00762 
00763 
00764     /* Flush the buffer */
00765 
00766   if (outfile)
00767   
00768     cbf_failnez (cbf_flush_characters (outfile))
00769 
00770 
00771     /* Save the number of characters read */
00772     
00773   if (readsize)
00774   
00775     *readsize = count;
00776     
00777     
00778     /* Success */
00779     
00780   return 0;
00781 }
00782 
00783 
00784   /* Convert base-64 text to binary data */
00785 
00786 int cbf_frombase64 (cbf_file *infile, cbf_file *outfile, size_t size,
00787                                                          size_t *readsize,
00788                                                          char *digest)
00789 {
00790   static int decode_64 [256] = {
00791   
00792     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00793     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00794     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 
00795     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 64, -1, -1, 
00796     -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 
00797     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 
00798     -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 
00799     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 
00800     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00801     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00802     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00803     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00804     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00805     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00806     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
00807     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
00808     
00809     };
00810 
00811   MD5_CTX context;
00812   
00813   unsigned char buffer [64], rawdigest [17];
00814     
00815   int c [4], d [3], bufsize;
00816   
00817   int read, write;
00818     
00819   size_t count;
00820 
00821 
00822     /* Initialise the MD5 context */
00823     
00824   if (digest)
00825 
00826     MD5Init (&context);
00827 
00828 
00829   count = 0;
00830 
00831   bufsize = 0;
00832   
00833   while (count < size)
00834   {
00835       /* Read 4 characters */
00836       
00837     for (read = 0; read < 4; read++)
00838     
00839       do
00840       {
00841         c [read] = cbf_read_character (infile);
00842         
00843         if (c [read] == EOF)
00844         
00845           return CBF_FILEREAD;
00846       }
00847       while (decode_64 [c [read] & 0x0ff] < 0);
00848 
00849 
00850       /* End of data? */
00851       
00852     if (c [0] == '=' || c [1] == '=')
00853     
00854       break;
00855 
00856 
00857       /* Valid combinations: xxxx xxx= xx== */
00858       
00859     c [0] = decode_64 [c [0] & 0x0ff];
00860     c [1] = decode_64 [c [1] & 0x0ff];
00861     c [2] = decode_64 [c [2] & 0x0ff];
00862     c [3] = decode_64 [c [3] & 0x0ff];
00863 
00864     d [0] = ((c [0] << 2) & 0x0fc) | ((c [1] >> 4) & 0x003);
00865     d [1] = ((c [1] << 4) & 0x0f0) | ((c [2] >> 2) & 0x00f);
00866     d [2] = ((c [2] << 6) & 0x0c0) | ((c [3]     ) & 0x03f);
00867     
00868     if (c [2] == 64)
00869     
00870       read = 1;
00871       
00872     else
00873     
00874       if (c [3] == 64)
00875       
00876         read = 2;
00877         
00878       else
00879       
00880         read = 3;
00881         
00882         
00883       /* Save the data */
00884       
00885     for (write = 0; write < read; write++)
00886     {
00887       if (outfile)
00888 
00889         cbf_failnez (cbf_put_character (outfile, d [write]))
00890 
00891       if (digest)
00892       {
00893         buffer [bufsize] = (unsigned char) d [write];
00894       
00895         bufsize++;
00896 
00897         if (bufsize > 63)
00898         {
00899           MD5Update (&context, buffer, 64);
00900 
00901           bufsize = 0;
00902         }
00903       }
00904     }
00905 
00906     count += read;
00907   }
00908 
00909 
00910     /* Get the digest */
00911 
00912   if (digest)
00913   {
00914     if (bufsize)
00915 
00916       MD5Update (&context, buffer, bufsize);
00917 
00918     MD5Final (rawdigest, &context);
00919 
00920     cbf_md5digest_to64 (digest, rawdigest);
00921   }
00922 
00923 
00924     /* Flush the buffer */
00925 
00926   if (outfile)
00927   
00928     cbf_failnez (cbf_flush_characters (outfile))
00929 
00930 
00931     /* Save the number of characters read */
00932     
00933   if (readsize)
00934   
00935     *readsize = count;
00936     
00937     
00938     /* Success */
00939     
00940   return 0;
00941 }
00942 
00943 
00944   /* Convert base-8/base-10/base-16 text to binary data */
00945 
00946 int cbf_frombasex (cbf_file *infile, cbf_file *outfile, size_t size, 
00947                                                         size_t *readsize,
00948                                                         char *digest)
00949 {
00950   MD5_CTX context;
00951   
00952   unsigned char buffer [64], rawdigest [17];
00953 
00954   int c, bufsize;
00955   
00956   char val [80], *end;
00957  
00958   int read, write, base, direction, elsize, valcount, padding;
00959     
00960   size_t count;
00961 
00962   unsigned long l;
00963 
00964 
00965     /* Defaults */
00966     
00967   base = 10;
00968   
00969   direction = 1;
00970   
00971   elsize = 4;
00972 
00973   count = 0;
00974   
00975   valcount = 0;
00976   
00977   padding = 0;
00978   
00979   bufsize = 0;
00980 
00981 
00982     /* Initialise the MD5 context */
00983 
00984   if (digest)
00985 
00986     MD5Init (&context);
00987 
00988 
00989   while (count < size)
00990   {
00991       /* Read the (first) character */
00992       
00993     c = cbf_read_character (infile);
00994     
00995     if (c == EOF)
00996     
00997       return CBF_FILEREAD;
00998       
00999       
01000       /* Interpret it */
01001       
01002     if (c == '>')
01003     {
01004       direction = 1;
01005       
01006       c = ' ';
01007     }
01008     else
01009         
01010       if (c == '<')
01011       {
01012         direction = -1;
01013         
01014         c = ' ';
01015       }
01016       else
01017       
01018         if (c == '#')
01019         {
01020             /* Comment */
01021             
01022           do
01023             
01024             c = cbf_read_character (infile);
01025             
01026           while (c != EOF && c != '\n');
01027           
01028           if (c == EOF)
01029           
01030             return CBF_FORMAT;
01031         }
01032 
01033     switch (infile->column)
01034     {
01035       case 1:
01036 
01037         if (c == 'O' || c == 'o')
01038               
01039           base = 8;
01040 
01041         else
01042 
01043           if (c == 'D' || c == 'd')
01044 
01045             base = 10;
01046 
01047           else
01048 
01049             if (c == 'H' || c == 'h')
01050 
01051               base = 16;
01052 
01053             else
01054 
01055               return CBF_FORMAT;
01056               
01057         break;
01058 
01059       case 2:
01060             
01061         if (isdigit (c) && c != '0')
01062         
01063           elsize = c - '0';
01064           
01065       case 3:
01066 
01067         break;
01068 
01069       default:
01070       
01071         if (!isspace (c))
01072         
01073           if (c == '=')
01074           
01075             padding++;
01076             
01077           else
01078           {
01079               /* Save the character */
01080              
01081             if (valcount > 78)
01082           
01083               return CBF_FORMAT;
01084             
01085             val [valcount] = c;
01086           
01087             valcount++;
01088           }
01089         else
01090         
01091           if (valcount)
01092           {
01093               /* Convert the number */
01094             
01095             val [valcount] = '\0';
01096           
01097             l = strtoul (val, &end, base);
01098         
01099             if (end != &val [valcount])
01100         
01101               return CBF_FORMAT;
01102         
01103       
01104               /* Save the binary data */
01105               
01106             if ((padding % 2) || padding > 6)
01107             
01108               return CBF_FORMAT;
01109               
01110             read = elsize - padding / 2;
01111         
01112             for (write = 0; write < read; write++)
01113             {
01114               if (direction < 0)
01115               
01116                 c = (unsigned char) ((l >> ((read - write - 1) * 8)) & 0x0ff);
01117 
01118               else
01119 
01120                 c = (unsigned char) ((l >> (write * 8)) & 0x0ff);
01121 
01122               if (outfile)
01123               
01124                 cbf_failnez (cbf_put_character (outfile, c))
01125 
01126               if (digest)
01127               {
01128                 buffer [bufsize] = (unsigned char) c;
01129       
01130                 bufsize++;
01131 
01132                 if (bufsize > 63)
01133                 {
01134                   MD5Update (&context, buffer, 64);
01135 
01136                   bufsize = 0;
01137                 }
01138               }
01139             }
01140          
01141             count += read;
01142             
01143             valcount = 0;
01144             
01145             padding = 0;
01146           }
01147     }
01148   }
01149 
01150 
01151     /* Get the digest */
01152 
01153   if (digest)
01154   {
01155     if (bufsize)
01156 
01157       MD5Update (&context, buffer, bufsize);
01158 
01159     MD5Final (rawdigest, &context);
01160 
01161     cbf_md5digest_to64 (digest, rawdigest);
01162   }
01163 
01164 
01165     /* Flush the buffer */
01166 
01167   if (outfile)
01168   
01169     cbf_failnez (cbf_flush_characters (outfile))
01170 
01171 
01172     /* Save the number of characters read */
01173     
01174   if (readsize)
01175   
01176     *readsize = count;
01177     
01178     
01179     /* Success */
01180     
01181   return 0;
01182 }  
01183 
01184 #ifdef __cplusplus
01185 
01186 }
01187 
01188 #endif