cbf_binary.c

Go to the documentation of this file.
00001 /**********************************************************************
00002  * cbf_binary -- handle simple binary values                          *
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_tree.h"
00126 #include "cbf_codes.h"
00127 #include "cbf_compress.h"
00128 #include "cbf_context.h"
00129 #include "cbf_binary.h"
00130 #include "cbf_read_mime.h"
00131 
00132 #include <stdlib.h>
00133 #include <string.h>
00134 #include <ctype.h>
00135 #include <limits.h>
00136 
00137 
00138   /* Parse a binary text value */
00139   
00140 int cbf_get_bintext (cbf_node  *column, unsigned int row,
00141                      int       *type,
00142                      int       *id, 
00143                      cbf_file **file,
00144                      long      *start,
00145                      size_t    *size,
00146                      int       *checked_digest,
00147                      char      *digest,
00148                      int       *bits,
00149                      int       *sign,
00150             unsigned int       *compression)
00151 {
00152   cbf_file *file_text;
00153 
00154   long start_text, size_text;
00155 
00156   int id_text, type_text, checked_digest_text, bits_text, sign_text;
00157 
00158   unsigned int compression_text;
00159   
00160   char digest_text [25];
00161 
00162   const char *text;
00163 
00164 
00165     /* Check that the value is binary */
00166 
00167   if (!cbf_is_binary (column, row))
00168 
00169     return CBF_ASCII;
00170 
00171 
00172     /* Get the value */
00173 
00174   cbf_failnez (cbf_get_columnrow (&text, column, row))
00175     
00176     
00177     /* Parse it */
00178     
00179   type_text = *text;
00180 
00181   sscanf (text + 1, " %x %p %lx %lx %d %24s %x %d %u", 
00182                       &id_text, 
00183                       &file_text, 
00184                       &start_text, 
00185                       &size_text, 
00186                       &checked_digest_text, 
00187                        digest_text, 
00188                       &bits_text, 
00189                       &sign_text,
00190                       &compression_text);
00191 
00192 
00193     /* Copy the values */
00194     
00195   if (type)
00196   
00197     *type = type_text;
00198     
00199   if (id)
00200   
00201     *id = id_text;
00202     
00203   if (file)
00204   
00205     *file = file_text;
00206     
00207   if (start)
00208   
00209     *start = start_text;
00210    
00211   if (size)
00212  
00213     *size = size_text;
00214    
00215   if (checked_digest)
00216   
00217     *checked_digest = checked_digest_text;
00218     
00219   if (digest)
00220   
00221     strcpy (digest, digest_text);
00222     
00223   if (bits)
00224   
00225     *bits = bits_text;
00226     
00227   if (sign)
00228   
00229     *sign = sign_text;
00230 
00231   if (compression)
00232 
00233     *compression = compression_text;
00234     
00235     
00236     /* Success */
00237     
00238   return 0;
00239 }  
00240    
00241 
00242   /* Set a binary text value */
00243   
00244 int cbf_set_bintext (cbf_node *column, unsigned int row,
00245                      int         type,
00246                      int         id, 
00247                      cbf_file   *file,
00248                      long        start,
00249                      long        size,
00250                      int         checked_digest,
00251                      const char *digest,
00252                      int         bits,
00253                      int         sign,
00254             unsigned int         compression)
00255 {
00256   char text [(((sizeof (void *) +
00257                 sizeof (long int) * 2 +
00258                 sizeof (int) * 3) * CHAR_BIT) >> 2) + 55];
00259                 
00260   const char *new_text;
00261 
00262   int errorcode;
00263   
00264 
00265     /* Check that the digest has the correct format */
00266     
00267   if (!cbf_is_base64digest (digest))
00268   {
00269     digest = "------------------------";
00270     
00271     checked_digest = 0;
00272   }
00273 
00274 
00275     /* Create the new text */                
00276 
00277   sprintf (text, "%x %p %lx %lx %1d %24s %x %d %u", 
00278                    id, 
00279                    file, 
00280                    start, 
00281                    size, 
00282                    checked_digest != 0,
00283                    digest, 
00284                    bits, 
00285                    sign,
00286                    compression);
00287     
00288   new_text = cbf_copy_string (NULL, text, type);
00289 
00290   if (!new_text)
00291     
00292     return CBF_ALLOC;
00293 
00294 
00295     /* Add a new connection to the file */
00296 
00297   cbf_onfailnez (cbf_add_fileconnection (&file, NULL),
00298                  cbf_free_string (NULL, new_text))
00299 
00300 
00301     /* Set the new value */
00302 
00303   errorcode = cbf_set_columnrow (column, row, new_text, 1);
00304 
00305   if (errorcode)
00306   {
00307     cbf_free_string (NULL, new_text);
00308     
00309     return errorcode | cbf_delete_fileconnection (&file);
00310   }
00311 
00312   
00313     /* Success */
00314     
00315   return 0;
00316 }
00317 
00318 
00319   /* Is this a binary value? */
00320 
00321 int cbf_is_binary (cbf_node *column, unsigned int row)
00322 {
00323   const char *text;
00324   
00325   
00326     /* Get the value */
00327 
00328   if (cbf_get_columnrow (&text, column, row))
00329   
00330     return 0;
00331   
00332   if (text)
00333 
00334     return (*text == CBF_TOKEN_BIN     || 
00335             *text == CBF_TOKEN_TMP_BIN || 
00336             *text == CBF_TOKEN_MIME_BIN);
00337       
00338       
00339     /* Fail */
00340 
00341   return 0;
00342 }
00343 
00344 
00345   /* Is this an encoded binary value? */
00346 
00347 int cbf_is_mimebinary (cbf_node *column, unsigned int row)
00348 {
00349   const char *text;
00350   
00351   
00352     /* Get the value */
00353 
00354   if (cbf_get_columnrow (&text, column, row))
00355   
00356    return 0;
00357   
00358   if (text)
00359 
00360     return (*text == CBF_TOKEN_MIME_BIN);
00361         
00362       
00363     /* Fail */
00364 
00365   return 0;
00366 }
00367 
00368 
00369   /* Free a value */
00370 
00371 int cbf_free_value (cbf_context *context, cbf_node *column, unsigned int row)
00372 {
00373   cbf_file *file;
00374 
00375   const char *text;
00376 
00377   int is_binary, type;
00378 
00379 
00380     /* Check the argument */
00381 
00382   if (!column)
00383 
00384     return CBF_ARGUMENT;
00385     
00386     
00387     /* Is the value binary? */
00388     
00389   is_binary = cbf_is_binary (column, row);
00390   
00391 
00392     /* Parse the (binary) value */
00393     
00394   if (is_binary)
00395       
00396     cbf_failnez (cbf_get_bintext (column, row, &type, NULL, &file, NULL, 
00397                                            NULL, NULL, NULL, NULL, NULL, NULL))
00398 
00399     
00400     /* Get the ASCII value */
00401 
00402   cbf_failnez (cbf_get_columnrow (&text, column, row))
00403   
00404 
00405     /* Set the value to null */
00406       
00407   cbf_failnez (cbf_set_columnrow (column, row, NULL, 0))
00408     
00409 
00410     /* And free it */
00411 
00412   cbf_free_string (NULL, text);
00413 
00414   if (is_binary)
00415 
00416     if (type == CBF_TOKEN_TMP_BIN)
00417 
00418       cbf_failnez (cbf_close_temporary (context, &file))
00419       
00420     else
00421 
00422       cbf_failnez (cbf_delete_fileconnection (&file))
00423   
00424   
00425     /* Success */
00426     
00427   return 0;
00428 }
00429 
00430 
00431   /* Set a binary value */
00432 
00433 int cbf_set_binary (cbf_node *column, unsigned int row,
00434                     unsigned int compression,  int binary_id, 
00435                     void *value, size_t elsize, int elsign,
00436                     size_t nelem)
00437 {
00438   cbf_file *tempfile;
00439 
00440   char digest [25];
00441   
00442   size_t size;
00443   
00444   long start;
00445   
00446   int bits;
00447 
00448 
00449     /* Remove the old value */
00450 
00451   cbf_failnez (cbf_set_columnrow (column, row, NULL, 1))
00452 
00453 
00454     /* Get the temporary file */
00455 
00456   cbf_failnez (cbf_open_temporary (column->context, &tempfile))
00457 
00458 
00459     /* Move to the end of the temporary file */
00460 
00461   if (cbf_set_fileposition (tempfile, 0, SEEK_END))
00462 
00463     return CBF_FILESEEK | cbf_delete_fileconnection (&tempfile);
00464 
00465 
00466     /* Get the starting location */
00467 
00468   if (cbf_get_fileposition (tempfile, &start))
00469 
00470     return CBF_FILETELL | cbf_delete_fileconnection (&tempfile);
00471     
00472 
00473     /* Add the binary data to the temporary file */
00474 
00475   cbf_onfailnez (cbf_compress (value, elsize, elsign, nelem,
00476                                compression, tempfile,
00477                                &size, &bits, digest),
00478                  cbf_delete_fileconnection (&tempfile))
00479 
00480 
00481     /* Set the value */
00482     
00483   cbf_onfailnez (cbf_set_bintext (column, row, CBF_TOKEN_TMP_BIN,
00484                                   binary_id, tempfile, start, size,
00485                                   1, digest, bits, elsign != 0, compression),
00486                  cbf_delete_fileconnection (&tempfile))
00487 
00488 
00489     /* Success */
00490 
00491   return 0;
00492 }
00493     
00494 
00495   /* Check the message digest */
00496   
00497 int cbf_check_digest (cbf_node *column, unsigned int row)
00498 {
00499   cbf_file *file;
00500 
00501   long start;
00502   
00503   size_t size;
00504 
00505   char old_digest [25], new_digest [25];
00506 
00507   int id, bits, sign, type, checked_digest;
00508 
00509   unsigned int compression;
00510 
00511 
00512     /* Parse the value */
00513     
00514   cbf_failnez (cbf_get_bintext (column, row, &type, &id, &file, 
00515                                 &start, &size, &checked_digest, 
00516                                 old_digest, &bits, &sign, &compression))
00517 
00518 
00519     /* Recalculate and compare the digest? */
00520 
00521   if ((file->read_headers & MSG_DIGEST) && !checked_digest)
00522   
00523     if (cbf_is_base64digest (old_digest))
00524     {
00525         /* Is it encoded? */
00526     
00527       if (cbf_is_mimebinary (column, row))
00528       {
00529           /* Convert the value to a normal binary value */
00530       
00531         cbf_failnez (cbf_mime_temp (column, row))
00532     
00533     
00534           /* Rerun the function */
00535 
00536         return cbf_check_digest (column, row);
00537       }
00538 
00539 
00540         /* Position the file */
00541 
00542       cbf_failnez (cbf_set_fileposition (file, start, SEEK_SET))
00543 
00544         /* Recalculate and check the digest */
00545 
00546       cbf_failnez (cbf_md5digest (file, size, new_digest))
00547 
00548       if (strcmp (old_digest, new_digest) != 0)
00549                  
00550         return CBF_FORMAT;
00551       
00552       
00553         /* Change the text to show that the digest has been checked */
00554       
00555       cbf_failnez (cbf_set_bintext (column, row, type,
00556                                     id, file, start, size,
00557                                     1, new_digest, bits, sign, compression))
00558     }
00559   
00560   
00561     /* Success */
00562     
00563   return 0;
00564 }
00565 
00566 
00567   /* Get the parameters of a binary value */
00568   
00569 int cbf_binary_parameters (cbf_node *column, 
00570                            unsigned int row, unsigned int *compression,
00571                            int *id, 
00572                            int *eltype, size_t *elsize, 
00573                            int *elsigned, 
00574                            int *elunsigned,
00575                            size_t *nelem,
00576                            int *minelem, int *maxelem)
00577 {
00578   cbf_file *file;
00579 
00580   long start;
00581 
00582   size_t size, file_elsize, file_nelem;
00583 
00584   int text_bits, errorcode;
00585   
00586   
00587     /* Check the digest (this will also decode it if necessary) */
00588 
00589   cbf_failnez (cbf_check_digest (column, row))
00590   
00591 
00592     /* Is it an encoded binary section? */
00593     
00594   if (cbf_is_mimebinary (column, row))
00595   {
00596 
00597       /* Convert the value to a normal binary value */
00598       
00599     cbf_failnez (cbf_mime_temp (column, row))
00600     
00601     
00602       /* Rerun the function */
00603 
00604     return cbf_binary_parameters (column, row, 
00605                                   compression,
00606                                   id, 
00607                                   eltype, elsize, 
00608                                   elsigned, elunsigned,
00609                                   nelem,
00610                                   minelem, maxelem);
00611   }
00612 
00613 
00614     /* Parse the value */
00615 
00616   cbf_failnez (cbf_get_bintext (column, row, NULL,
00617                                 id, &file, &start, &size, NULL,
00618                                 NULL, &text_bits, NULL, compression))
00619 
00620 
00621     /* Position the file at the start of the binary section */
00622     
00623   cbf_failnez (cbf_set_fileposition (file, start, SEEK_SET))
00624 
00625   
00626     /* Get the parameters */
00627 
00628   errorcode = cbf_decompress_parameters (eltype, &file_elsize, elsigned, 
00629                                          elunsigned, 
00630                                          &file_nelem, minelem, maxelem,
00631                                          *compression, file);
00632 
00633   if (!errorcode)
00634   {
00635     if (elsize)
00636   
00637       if (file_elsize > 0)
00638   
00639         *elsize = file_elsize;
00640         
00641       else
00642 
00643         *elsize = (text_bits + CHAR_BIT - 1) / CHAR_BIT;    
00644         
00645     if (nelem)
00646     
00647       if (file_nelem > 0)
00648       
00649         *nelem = file_nelem;
00650         
00651       else
00652       
00653         *nelem = (size * 8) / text_bits;
00654   }
00655 
00656   return errorcode;
00657 }
00658 
00659                    
00660   /* Get a binary value */
00661   
00662 int cbf_get_binary (cbf_node *column, unsigned int row, int *id,
00663                     void *value, size_t elsize, int elsign,
00664                     size_t nelem, size_t *nelem_read)
00665 {
00666   cbf_file *file;
00667 
00668   long start;
00669 
00670   int eltype_file, elsigned_file, elunsigned_file, 
00671                    minelem_file, maxelem_file, bits, sign;
00672 
00673   unsigned int compression;
00674 
00675   size_t nelem_file;
00676 
00677 
00678     /* Check the digest (this will also decode it if necessary) */
00679 
00680   cbf_failnez (cbf_check_digest (column, row))
00681   
00682 
00683     /* Is it an encoded binary section? */
00684     
00685   if (cbf_is_mimebinary (column, row))
00686   {
00687       /* Convert the value to a normal binary value */
00688       
00689     cbf_failnez (cbf_mime_temp (column, row))
00690     
00691     
00692       /* Rerun the function */
00693 
00694     return cbf_get_binary (column, row, 
00695                            id, value, elsize, elsign,
00696                            nelem, nelem_read);
00697   }
00698 
00699 
00700     /* Parse the value */
00701 
00702   cbf_failnez (cbf_get_bintext (column, row, NULL,
00703                                 id, &file, &start, NULL, 
00704                                  NULL, NULL, &bits, &sign, &compression))
00705   
00706 
00707     /* Position the file at the start of the binary section */
00708 
00709   cbf_failnez (cbf_set_fileposition (file, start, SEEK_SET))
00710 
00711   
00712     
00713     /* Get the parameters and position the file */
00714 
00715   cbf_failnez (cbf_decompress_parameters (&eltype_file, NULL,
00716                                           &elsigned_file, &elunsigned_file,
00717                                           &nelem_file,
00718                                           &minelem_file, &maxelem_file,
00719                                           compression, 
00720                                           file))
00721 
00722 
00723     /* Decompress the binary data */
00724 
00725   return cbf_decompress (value, elsize, elsign, nelem, nelem_read,
00726                          compression, bits, sign, file);
00727 }
00728 
00729                     
00730 #ifdef __cplusplus
00731 
00732 }
00733 
00734 #endif