convert.c

Go to the documentation of this file.
00001 /*                       C O N V E R T . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup conv */
00023 /*@{*/
00024 /** @file convert.c
00025  * 
00026  * @brief
00027  * Routines to translate data formats.  The data formats are:
00028  *
00029  * \li Host/Network             is the data in host format or local format
00030  * \li  signed/unsigned         Is the data signed?
00031  * \li char/short/int/long/double
00032  *                              Is the data 8bits, 16bits, 32bits, 64bits
00033  *                              or a double?
00034  *
00035  * The method of conversion is to convert up to double then back down the
00036  * the expected output format.
00037  *
00038  * @author Christopher T. Johnson
00039  *
00040  *  @par Source
00041  *      The U. S. Army Research Laboratory                      @n
00042  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00043  */
00044 
00045 #ifndef lint
00046 static const char libbu_convert_RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbu/convert.c,v 14.10 2006/08/31 05:50:24 lbutler Exp $ (ARL)";
00047 #endif
00048 
00049 #include "common.h"
00050 
00051 
00052 
00053 #include <stdio.h>
00054 #include <ctype.h>
00055 #ifdef HAVE_STRING_H
00056 #include <string.h>
00057 #else
00058 #include <strings.h>
00059 #endif
00060 #include "machine.h"
00061 #include "vmath.h"
00062 #include "bu.h"
00063 
00064 
00065 /* bu_cv_cookie 
00066  *
00067  * @brief
00068  * Set's a bit vector after parsing an input string.
00069  *
00070  * Set up the conversion tables/flags for vert.
00071  * 
00072  * @param in    format description.
00073  * 
00074  * @return a 32 bit vector.
00075  *
00076  * Format description:
00077  *      [channels][h|n][s|u] c|s|i|l|d|8|16|32|64 [N|C|L]
00078  *
00079  * @n channels must be null or 1
00080  * @n Host | Network
00081  * @n signed | unsigned
00082  * @n char | short | integer | long | double | number of bits of integer
00083  * @n Normalize | Clip | low-order
00084  */
00085 int
00086 bu_cv_cookie(char *in)                  /* input format */
00087 {
00088         char *p;
00089         int collector;
00090         int result = 0x0000;    /* zero/one channel, Net, unsigned, char, clip */
00091 
00092         if (!in) return 0;
00093         if (!*in) return 0;
00094 
00095 
00096         collector = 0;
00097         for (p=in; *p && isdigit(*p); ++p) collector = collector*10 + (*p - '0');
00098         if (collector > 255) {
00099                 collector = 255;
00100         } else if (collector == 0) {
00101                 collector = 1;
00102         }
00103         result = collector;     /* number of channels set '|=' */
00104 
00105         if (!*p) return 0;
00106 
00107         if (*p == 'h') {
00108                 result |= CV_HOST_MASK;
00109                 ++p;
00110         } else if (*p == 'n') {
00111                 ++p;
00112         }
00113 
00114         if (!*p) return 0;
00115         if (*p == 'u') {
00116                 ++p;
00117         } else if (*p == 's') { /* could be 'signed' or 'short' */
00118                 char *p2;
00119                 p2 = p+1;
00120                 if (*p2 && (islower(*p2) || isdigit(*p2))) {
00121                         result |= CV_SIGNED_MASK;
00122                         ++p;
00123                 }
00124         }
00125 
00126         if (!*p) return 0;
00127         switch (*p) {
00128         case 'c':
00129         case '8':
00130                 result |= CV_8;
00131                 break;
00132         case '1':
00133                 p++;
00134                 if (*p != '6') return 0;
00135                 /* fall through */
00136         case 's':
00137                 result |= CV_16;
00138                 break;
00139         case '3':
00140                 p++;
00141                 if (*p != '2') return 0;
00142                 /* fall through */
00143         case 'i':
00144                 result |= CV_32;
00145                 break;
00146         case '6':
00147                 p++;
00148                 if (*p != '4') return 0;
00149                 /* fall through */
00150         case 'l':
00151                 result |= CV_64;
00152                 break;
00153         case 'd':
00154                 result |= CV_D;
00155                 break;
00156         default:
00157                 return 0;
00158         }
00159         p++;
00160 
00161         if (!*p) return(result);
00162         if (*p == 'N') {
00163                 result |= CV_NORMAL;
00164         } else if (*p == 'C') {
00165                 result |= CV_CLIP;
00166         } else if (*p == 'L') {
00167                 result |= CV_LIT;
00168         } else {
00169                 return 0;
00170         }
00171         return(result);
00172 }
00173 
00174 /**
00175  *
00176  */
00177 void
00178 bu_cv_fmt_cookie( char * buf, size_t buflen, int cookie )
00179 {
00180         register char *cp = buf;
00181         unsigned int    len;
00182 
00183         if( buflen == 0 )       {
00184                 fprintf( stderr, "bu_cv_pr_cookie:  call me with a bigger buffer\n");
00185                 return;
00186         }
00187         buflen--;
00188         if( cookie == 0 )  {
00189                 strncpy( cp, "bogus!", buflen );
00190                 return;
00191         }
00192 
00193         sprintf( cp, "%d", cookie & CV_CHANNEL_MASK );
00194         len = strlen(cp);
00195         cp += len;
00196         if( buflen < len )
00197         {
00198                 fprintf( stderr, "bu_cv_pr_cookie:  call me with a bigger buffer\n");
00199                 return;
00200         }
00201         buflen -= len;
00202 
00203         if( buflen == 0 )       {
00204                 fprintf( stderr, "bu_cv_pr_cookie:  call me with a bigger buffer\n");
00205                 return;
00206         }
00207         if( cookie & CV_HOST_MASK )  {
00208                 *cp++ = 'h';
00209                 buflen--;
00210         } else {
00211                 *cp++ = 'n';
00212                 buflen--;
00213         }
00214 
00215         if( buflen == 0 )       {
00216                 fprintf( stderr, "bu_cv_pr_cookie:  call me with a bigger buffer\n");
00217                 return;
00218         }
00219         if( cookie & CV_SIGNED_MASK )  {
00220                 *cp++ = 's';
00221                 buflen--;
00222         } else {
00223                 *cp++ = 'u';
00224                 buflen--;
00225         }
00226 
00227         if( buflen == 0 )       {
00228                 fprintf( stderr, "bu_cv_pr_cookie:  call me with a bigger buffer\n");
00229                 return;
00230         }
00231         switch( cookie & CV_TYPE_MASK )  {
00232         case CV_8:
00233                 *cp++ = '8';
00234                 buflen--;
00235                 break;
00236         case CV_16:
00237                 strncpy( cp, "16", buflen );
00238                 cp += 2;
00239                 buflen -= 2;
00240                 break;
00241         case CV_32:
00242                 strncpy( cp, "32", buflen );
00243                 cp += 2;
00244                 buflen -= 2;
00245                 break;
00246         case CV_64:
00247                 strncpy( cp, "64", buflen );
00248                 cp += 2;
00249                 buflen -= 2;
00250                 break;
00251         case CV_D:
00252                 *cp++ = 'd';
00253                 buflen -= 1;
00254                 break;
00255         default:
00256                 *cp++ = '?';
00257                 buflen -= 1;
00258                 break;
00259         }
00260 
00261         if( buflen == 0 )       {
00262                 fprintf( stderr, "bu_cv_pr_cookie:  call me with a bigger buffer\n");
00263                 return;
00264         }
00265         switch( cookie & CV_CONVERT_MASK )  {
00266         case CV_CLIP:
00267                 *cp++ = 'C';
00268                 buflen -= 1;
00269                 break;
00270         case CV_NORMAL:
00271                 *cp++ = 'N';
00272                 buflen -= 1;
00273                 break;
00274         case CV_LIT:
00275                 *cp++ = 'L';
00276                 buflen -= 1;
00277                 break;
00278         default:
00279                 *cp++ = 'X';
00280                 buflen -= 1;
00281                 break;
00282         }
00283         *cp = '\0';
00284 }
00285 
00286 /**
00287  *
00288  *
00289  */
00290 void
00291 bu_cv_pr_cookie( char *title, int cookie )
00292 {
00293         char    buf[128];
00294 
00295         bu_cv_fmt_cookie( buf, sizeof(buf), cookie );
00296         fprintf( stderr, "%s cookie '%s' (x%x)\n", title, buf, cookie );
00297 }
00298 
00299 /**             c v
00300  * @brief
00301  * convert from one format to another.
00302  *
00303  * 
00304  * @param in    input pointer
00305  * @param out   output pointer
00306  * @param count number of entries to convert.
00307  * @param size  size of output buffer.
00308  * @param infmt input format
00309  * @param outfmt        output format
00310  *
00311  */
00312 int
00313 cv(genptr_t out, char *outfmt, size_t size, genptr_t in, char *infmt, int count)
00314 {
00315         int     incookie, outcookie;
00316         incookie = bu_cv_cookie(infmt);
00317         outcookie = bu_cv_cookie(outfmt);
00318         return(bu_cv_w_cookie(out, outcookie, size, in, incookie, count));
00319 }
00320 
00321 /**
00322  *                      C V _ O P T I M I Z E
00323  *
00324  *  It is always more efficient to handle host data, rather than network.
00325  *  If host and network formats are the same, and the request was for
00326  *  network format, modify the cookie to request host format.
00327  */
00328 int
00329 bu_cv_optimize(register int cookie)
00330 {
00331         static int Indian = IND_NOTSET;
00332         int     fmt;
00333 
00334         if( cookie & CV_HOST_MASK )
00335                 return cookie;          /* already in most efficient form */
00336 
00337         /* This is a network format request */
00338         fmt  =  cookie & CV_TYPE_MASK;
00339 
00340         /* Run time check:  which kind of integers does this machine have? */
00341         if (Indian == IND_NOTSET) {
00342                 size_t soli = sizeof(long int);
00343                 unsigned long int       testval = 0;
00344                 register int            i;
00345                 for (i=0; i<4; i++) {
00346                         ((char *)&testval)[i] = i+1;
00347                 }
00348 
00349                 if (soli == 8) {
00350                         Indian = IND_CRAY;      /* is this good enough? */
00351                         if ( ( (testval >> 31) >> 1 ) == 0x01020304) {
00352                                 Indian = IND_BIG; /* XXX 64bit */
00353                         } else if (testval == 0x04030201) {
00354                                 Indian = IND_LITTLE;    /* 64 bit */
00355                         } else {
00356                                 bu_bomb("bu_cv_optimize: can not tell indian of host.\n");
00357                         }
00358                 } else if (testval == 0x01020304) {
00359                         Indian = IND_BIG;
00360                 } else if (testval == 0x04030201) {
00361                         Indian = IND_LITTLE;
00362                 } else if (testval == 0x02010403) {
00363                         Indian = IND_ILL;
00364                 }
00365         }
00366 
00367         switch(fmt)  {
00368         case CV_D:
00369 #               if IEEE_FLOAT
00370                         cookie |= CV_HOST_MASK; /* host uses network fmt */
00371 #               endif
00372                 return cookie;
00373         case CV_8:
00374                 return cookie | CV_HOST_MASK;   /* bytes already host format */
00375         case CV_16:
00376         case CV_32:
00377         case CV_64:
00378                 /* host is big-endian, so is network */
00379                 if( Indian == IND_BIG )
00380                         cookie |= CV_HOST_MASK;
00381                 return cookie;
00382         }
00383         return 0;                       /* ERROR */
00384 }
00385 
00386 /**
00387  *                      C V _ I T E M L E N
00388  *
00389  *  Returns the number of bytes each "item" of type "cookie" occupies.
00390  */
00391 int
00392 bu_cv_itemlen(register int cookie)
00393 {
00394         register int    fmt = (cookie & CV_TYPE_MASK) >> CV_TYPE_SHIFT;
00395         static int host_size_table[8] = {0, sizeof(char),
00396                                                                                                                                          sizeof(short), sizeof(int),
00397                                                                                                                                          sizeof(long int), sizeof(double)};
00398         static int net_size_table[8] = {0,1,2,4,8,8};
00399 
00400         if( cookie & CV_HOST_MASK )
00401                 return host_size_table[fmt];
00402         return net_size_table[fmt];
00403 }
00404 
00405 
00406 /**     bu_cv_ntohss
00407  *
00408  * @brief
00409  * Network TO Host Signed Short
00410  *
00411  * It is assumed that this routine will only be called if there is
00412  * real work to do.  Ntohs does no checking to see if it is reasonable
00413  * to do any conversions.
00414  *
00415  *
00416  * @param in    generic pointer for input.
00417  * @param count number of shorts to be generated.
00418  * @param out   short pointer for output
00419  * @param size  number of bytes of space reserved for out.
00420  *
00421  *
00422  * @return      number of conversions done.
00423  */
00424 int
00425 bu_cv_ntohss(register short int *out, size_t size, register genptr_t in, int count)
00426 {
00427         int limit;
00428         register int i;
00429 
00430         limit = size / sizeof(signed short);
00431         if (limit < count) count = limit;
00432 
00433         for (i=0; i<count; i++) {
00434                 *out++ = ((signed char *)in)[0] << 8 | ((unsigned char *)in)[1];
00435                 /* XXX This needs sign extension here for the case of
00436                  * XXX a negative 2-byte input on a 4 or 8 byte machine.
00437                  * XXX The "signed char" trick isn't enough.
00438                  * XXX Use your Cyber trick w/magic numbers or something.
00439                  */
00440                 in = ((char *)in) + 2;
00441         }
00442         return(count);
00443 }
00444 
00445 /**
00446  *
00447  *
00448  */
00449 int
00450 bu_cv_ntohus(register short unsigned int *out, size_t size, register genptr_t in, int count)
00451 {
00452         int limit;
00453         register int i;
00454 
00455         limit = size / sizeof(unsigned short);
00456         if (limit < count) count = limit;
00457 
00458         for (i=0; i<count; i++) {
00459                 *out++ = ((unsigned char *)in)[0]<<8 |
00460                         ((unsigned char *)in)[1];
00461                 in = ((char *)in) + 2;
00462         }
00463         return(count);
00464 }
00465 /**
00466  *
00467  *
00468  */
00469 int
00470 bu_cv_ntohsl(register long int *out, size_t size, register genptr_t in, int count)
00471 {
00472         int limit;
00473         register int i;
00474 
00475         limit = size / sizeof(signed long int);
00476         if (limit < count) count = limit;
00477 
00478         for (i=0; i<count; i++) {
00479                 *out++ = ((signed char *)in)[0] << 24 |
00480                     ((unsigned char *)in)[1] << 16 |
00481                     ((unsigned char *)in)[2] << 8  |
00482                     ((unsigned char *)in)[3];
00483                 /* XXX Sign extension here */
00484                 in = ((char *)in) + 4;
00485         }
00486 
00487         return(count);
00488 }
00489 /**
00490  *
00491  *
00492  */
00493 int
00494 bu_cv_ntohul(register long unsigned int *out, size_t size, register genptr_t in, int count)
00495 {
00496         int limit;
00497         register int i;
00498 
00499         limit = size / sizeof(unsigned long int);
00500         if (limit < count) count = limit;
00501 
00502         for (i=0; i<count; i++) {
00503                 *out++ = ((unsigned char *)in)[0] << 24 |
00504                         ((unsigned char *)in)[1] << 16 |
00505                     ((unsigned char *)in)[2] <<  8 |
00506                         ((unsigned char *)in)[3];
00507                 in = ((char *)in) + 4;
00508         }
00509         return(count);
00510 }
00511 
00512 /*****/
00513 /**
00514  *
00515  *
00516  */
00517 int
00518 bu_cv_htonss(genptr_t out, size_t size, register short int *in, int count)
00519 {
00520         int             limit;
00521         register int    i;
00522         register unsigned char *cp = (unsigned char *)out;
00523         register int    val;
00524 
00525         limit = size / 2;
00526         if( count > limit )  count = limit;
00527 
00528         for (i=0; i<count; i++) {
00529                 *cp++ = (val = *in++)>>8;
00530                 *cp++ = val;
00531         }
00532         return(count);
00533 }
00534 /**
00535  *
00536  *
00537  */
00538 int
00539 bu_cv_htonus(genptr_t out, size_t size, register short unsigned int *in, int count)
00540 {
00541         int             limit;
00542         register int    i;
00543         register unsigned char *cp = (unsigned char *)out;
00544         register int    val;
00545 
00546         limit = size / 2;
00547         if( count > limit )  count = limit;
00548 
00549         for (i=0; i<count; i++) {
00550                 *cp++ = (val = *in++)>>8;
00551                 *cp++ = val;
00552         }
00553         return(count);
00554 }
00555 /**
00556  *
00557  *
00558  */
00559 int
00560 bu_cv_htonsl(genptr_t out, size_t size, register long int *in, int count)
00561 {
00562         int             limit;
00563         register int    i;
00564         register unsigned char *cp = (unsigned char *)out;
00565         register long   val;
00566 
00567         limit = size / 4;
00568         if( count > limit )  count = limit;
00569 
00570         for (i=0; i<count; i++) {
00571                 *cp++ = (val = *in++)>>24;
00572                 *cp++ = val>>16;
00573                 *cp++ = val>> 8;
00574                 *cp++ = val;
00575         }
00576         return(count);
00577 }
00578 /**
00579  *
00580  *
00581  */
00582 int
00583 bu_cv_htonul(genptr_t out, size_t size, register long unsigned int *in, int count)
00584 {
00585         int             limit;
00586         register int    i;
00587         register unsigned char *cp = (unsigned char *)out;
00588         register long   val;
00589 
00590         limit = size / 4;
00591         if( count > limit ) {
00592                 count = limit;
00593         }
00594 
00595         for (i=0; i<count; i++) {
00596                 *cp++ = (val = *in++)>>24;
00597                 *cp++ = val>>16;
00598                 *cp++ = val>> 8;
00599                 *cp++ = val;
00600         }
00601         return(count);
00602 }
00603 
00604 
00605 /** bu_cv_w_cookie
00606  *
00607  * @brief
00608  * convert with cookie
00609  *
00610  * @param in            input pointer
00611  * @param incookie      input format cookie.
00612  * @param count         number of entries to convert.
00613  * @param out           output pointer.
00614  * @param outcookie     output format cookie.
00615  * @param size          size of output buffer in bytes;
00616  *
00617  *
00618  * A worst case would be:       ns16 on vax to ns32
00619 @code
00620  *      ns16    -> hs16
00621  *              -> hd
00622  *              -> hs32
00623  *              -> ns32
00624 @endcode 
00625  * The worst case is probably the easiest to deal with because all steps are
00626  * done.  The more difficult cases are when only a subset of steps need to
00627  * be done.
00628  *
00629  * @par Method:
00630 @code
00631  *      HOSTDBL defined as true or false
00632  *      if ! hostother then
00633  *              hostother = (Indian == IND_BIG) ? SAME : DIFFERENT;
00634  *      fi
00635  *      if (infmt == double) then
00636  *              if (HOSTDBL == SAME) {
00637  *                      inIsHost = host;
00638  *              fi
00639  *      else
00640  *              if (hostother == SAME) {
00641  *                      inIsHost = host;
00642  *              fi
00643  *      fi
00644  *      if (outfmt == double) then
00645  *              if (HOSTDBL == SAME) {
00646  *                      outIsHost == host;
00647  *      else
00648  *              if (hostother == SAME) {
00649  *                      outIsHost = host;
00650  *              fi
00651  *      fi
00652  *      if (infmt == outfmt) {
00653  *              if (inIsHost == outIsHost) {
00654  *                      copy(in,out)
00655  *                      exit
00656  *              else if (inIsHost == net) {
00657  *                      ntoh?(in,out);
00658  *                      exit
00659  *              else
00660  *                      hton?(in,out);
00661  *                      exit
00662  *              fi
00663  *      fi
00664  *
00665  *      while not done {
00666  *              from = in;
00667  *
00668  *              if (inIsHost == net) {
00669  *                      ntoh?(from,t1);
00670  *                      from = t1;
00671  *              fi
00672  *              if (infmt != double ) {
00673  *                      if (outIsHost == host) {
00674  *                              to = out;
00675  *                      else
00676  *                              to = t2;
00677  *                      fi
00678  *                      castdbl(from,to);
00679  *                      from = to;
00680  *              fi
00681  *
00682  *              if (outfmt == double ) {
00683  *                      if (outIsHost == net) {
00684  *                              hton?(from,out);
00685  *                      fi
00686  *              else
00687  *                      if (outIsHost == host) {
00688  *                              dblcast(from,out);
00689  *                      else
00690  *                              dblcast(from,t3);
00691  *                              hton?(t3,out);
00692  *                      fi
00693  *              fi
00694  *      done
00695 @endcode
00696  */
00697 int
00698 bu_cv_w_cookie(genptr_t out, int outcookie, size_t size, genptr_t in,  int incookie,  int       count)
00699 {
00700         int     work_count = 4096;
00701         int     number_done = 0;
00702         int     inIsHost,outIsHost,infmt,outfmt,insize,outsize;
00703         size_t  bufsize;
00704         genptr_t        t1,t2,t3;
00705         genptr_t        from;
00706         genptr_t        to;
00707         genptr_t        hold;
00708         register int i;
00709 
00710         /*
00711          * Work_count is the size of the working buffer.  If count is smaller
00712          * than the default work_count (4096) use the smaller number.
00713          */
00714 
00715         if (work_count > count)
00716                 work_count = count;
00717 
00718         incookie = bu_cv_optimize( incookie );
00719         outcookie = bu_cv_optimize( outcookie );
00720 
00721         /*
00722          * break out the conversion code and the format code.
00723          * Conversion is net<-->host.
00724          * Format is 8/16/32/64/D casting.
00725          */
00726         inIsHost = incookie & CV_HOST_MASK;     /* not zero if host */
00727         outIsHost= outcookie& CV_HOST_MASK;
00728         infmt  =  incookie & CV_TYPE_MASK;
00729         outfmt = outcookie & CV_TYPE_MASK;
00730         /*
00731          * Find the number of bytes required for one item of each kind.
00732          */
00733         outsize = bu_cv_itemlen( outcookie );
00734         insize = bu_cv_itemlen( incookie );
00735 
00736         /*
00737          * If the input format is the same as the output format then the
00738          * most that has to be done is a host to net or net to host conversion.
00739          */
00740         if (infmt == outfmt) {
00741 
00742                 /*
00743                  * Input format is the same as output format, do we need to do a
00744                  * host/net conversion?
00745                  */
00746                 if (inIsHost == outIsHost) {
00747 
00748                         /*
00749                          * No conversion required.
00750                          * Check the amount of space remaining before doing the bcopy.
00751                          */
00752                         if ((unsigned int)count * outsize > size) {
00753                     number_done = size / outsize;
00754                         } else {
00755                     number_done = count;
00756                         }
00757 
00758                         /*
00759                          * This is the simplest case, binary copy and out.
00760                          */
00761                         (void) bcopy((genptr_t) in, (genptr_t) out, (size_t)number_done * outsize);
00762                         return(number_done);
00763 
00764                         /*
00765                          * Well it's still the same format but the conversion are different.
00766                          * Only one of the *vert variables can be HOST therefore if
00767                          * inIsHost != HOST then outIsHost must be host format.
00768                          */
00769 
00770                 } else if (inIsHost != CV_HOST_MASK) { /* net format */
00771                         switch(incookie & (CV_SIGNED_MASK | CV_TYPE_MASK)) {
00772                         case CV_SIGNED_MASK | CV_16:
00773                     return(     bu_cv_ntohss((signed short *)out, size, in, count));
00774                         case CV_16:
00775                     return( bu_cv_ntohus((unsigned short *)out, size, in, count));
00776                         case CV_SIGNED_MASK | CV_32:
00777                     return( bu_cv_ntohsl((signed long *)out, size, in, count));
00778                         case CV_32:
00779                     return( bu_cv_ntohul((unsigned long *)out, size, in, count));
00780                         case CV_D:
00781                     (void) ntohd((unsigned char *)out, (unsigned char *)in, count);
00782                     return(count);
00783                         }
00784 
00785                         /*
00786                          * Since inIsHost != outIsHost and inIsHost == HOST then outIsHost must
00787                          * be in net format.  call the correct subroutine to do the conversion.
00788                          */
00789                 } else {
00790                         switch(incookie & (CV_SIGNED_MASK | CV_TYPE_MASK)) {
00791                         case CV_SIGNED_MASK | CV_16:
00792                     return(     bu_cv_htonss(out, size, (short *)in, count));
00793                         case CV_16:
00794                     return( bu_cv_htonus(out, size, (unsigned short *)in, count));
00795                         case CV_SIGNED_MASK | CV_32:
00796                     return( bu_cv_htonsl(out, size, (long *)in, count));
00797                         case CV_32:
00798                     return( bu_cv_htonul(out, size, (unsigned long *)in, count));
00799                         case CV_D:
00800                     (void) htond((unsigned char *)out, (unsigned char *)in, count);
00801                     return(count);
00802                         }
00803                 }
00804         }
00805         /*
00806          * If we get to this point then the input format is known to be
00807          * of a diffrent type than the output format.  This will require
00808          * a cast to, from or to and from double.
00809          *
00810          * Because the number of steps is not known initially, we get
00811          * three working buffers.  The size of a double is the largest of
00812          * any of the sizes we may be dealing with.
00813          */
00814 
00815         bufsize = work_count * sizeof(double);
00816         t1 = (genptr_t) bu_malloc(bufsize, "vert.c: t1");
00817         t2 = (genptr_t) bu_malloc(bufsize, "vert.c: t2");
00818         t3 = (genptr_t) bu_malloc(bufsize, "vert.c: t3");
00819 
00820         /*
00821          * From here on we will be working on a chunk of process at a time.
00822          */
00823         while ( size >= (unsigned int)outsize  && number_done < count) {
00824                 int remaining;
00825 
00826                 /*
00827                  * Size is the number of bytes that the caller said was available.
00828                  * We need the check to make sure that we will not convert too many
00829                  * entries, overflowing the output buffer.
00830                  */
00831 
00832                 /*
00833                  * Get number of full entries that can be converted
00834                  */
00835                 remaining = size / outsize;
00836 
00837                 /*
00838                  * If number of entries that would fit in the output buffer is
00839                  * larger than the number of entries left to convert(based on
00840                  * count and number done), set remaining to request count minus
00841                  * the number of conversions already completed.
00842                  */
00843                 if (remaining > count - number_done) {
00844                         remaining = count - number_done;
00845                 }
00846                 /*
00847                  * If we are in the last chunk, set the work count to take up
00848                  * the slack.
00849                  */
00850                 if (remaining < work_count) work_count = remaining;
00851 
00852                 /*
00853                  * All input at any stage will come from the "from" pointer.  We
00854                  * start with the from pointer pointing to the input buffer.
00855                  */
00856                 from = in;
00857 
00858                 /*
00859                  * We will be processing work_count entries of insize bytes each, so
00860                  * we set the in pointer to be ready for the next time through the loop.
00861                  */
00862                 in = ((char *) in) + work_count * insize;
00863 
00864                 /*
00865                  * If the input is in net format convert it host format.
00866                  * Because we know that the input format is not equal to the output
00867                  * this means that there will be at least two conversions taking place
00868                  * if the input is in net format.  (from net to host then at least one cast)
00869                  */
00870                 if (inIsHost != CV_HOST_MASK) { /* net format */
00871                         switch(incookie & (CV_SIGNED_MASK | CV_TYPE_MASK)) {
00872                         case CV_SIGNED_MASK | CV_16:
00873                                 (void) bu_cv_ntohss((short *)t1, bufsize , from, work_count);
00874                                 break;
00875                         case CV_16:
00876                                 (void) bu_cv_ntohus((unsigned short *)t1, bufsize , from, work_count);
00877                                 break;
00878                         case CV_SIGNED_MASK | CV_32:
00879                                 (void) bu_cv_ntohsl((long *)t1, bufsize , from, work_count);
00880                                 break;
00881                         case CV_32:
00882                                 (void) bu_cv_ntohul((unsigned long *)t1, bufsize , from, work_count);
00883                                 break;
00884                         case CV_D:
00885                                 (void) ntohd((unsigned char *)t1, (unsigned char *)from, work_count);
00886                                 break;
00887                         }
00888                         /*
00889                          * Point the "from" pointer to the host format.
00890                          */
00891                         from = t1;
00892                 }
00893 
00894 
00895                 /*
00896                  * "From" is a pointer to a HOST format buffer.
00897                  */
00898 
00899                 /*
00900                  * If the input format is not double then there must be a cast to
00901                  * double.
00902                  */
00903                 if (infmt != CV_D) {
00904 
00905                         /*
00906                          * if the output conversion is HOST and output format is DOUBLE
00907                          * then this will be the last step.
00908                          */
00909                         if (outIsHost == CV_HOST_MASK && outfmt == CV_D) {
00910                     to = out;
00911                         } else {
00912                     to = t2;
00913                         }
00914 
00915                         hold = to;
00916                         /*
00917                          * Cast the input format to double.
00918                          */
00919                         switch(incookie & (CV_SIGNED_MASK | CV_TYPE_MASK)) {
00920                         case CV_SIGNED_MASK | CV_8:
00921                     for (i=0; i< work_count; i++) {
00922                                         *((double *)to) = *((signed char *)from);
00923                                         to = (genptr_t)(((double *)to) + 1);
00924                                         from = ((char *)from) + 1;
00925                     }
00926                     break;
00927                         case CV_8:
00928                     for(i=0; i < work_count; i++) {
00929                                         *((double *)to) = *((unsigned char *)from);
00930                                         to = (genptr_t)(((double *)to) + 1);
00931                                         from = (genptr_t)(((unsigned char *)from) + 1);
00932                     }
00933                     break;
00934                         case CV_SIGNED_MASK | CV_16:
00935                     for (i=0; i < work_count; i++) {
00936                                         *((double *)to) = *((signed short *)from);
00937                                         to = (genptr_t)(((double *)to) + 1);
00938                                         from = (genptr_t)(((signed short *)from) + 1);
00939                     }
00940                     break;
00941                         case CV_16:
00942                     for (i=0; i < work_count; i++) {
00943                                         *((double *)to) = *((unsigned short *)from);
00944                                         to = (genptr_t)(((double *)to) + 1);
00945                                         from = (genptr_t)(((unsigned short *)from) + 1);
00946                     }
00947                     break;
00948                         case CV_SIGNED_MASK | CV_32:
00949                     for (i=0; i < work_count; i++) {
00950                                         *((double *)to) = *((signed long int *)from);
00951                                         to = (genptr_t)(((double *)to) + 1);
00952                                         from =  (genptr_t)(((signed long int *)from) + 1);
00953                     }
00954                     break;
00955                         case CV_32:
00956                     for (i=0; i < work_count; i++) {
00957                                         *((double *)to) = *((unsigned long int *) from);
00958                                         to = (genptr_t)(((double *)to) + 1);
00959                                         from = (genptr_t)(((unsigned long int *)from) + 1);
00960                     }
00961                     break;
00962                         default:
00963                                 fprintf( stderr, "Unimplemented input format\n");
00964                                 break;
00965                         }
00966                         from = hold;
00967                 }
00968 
00969                 if (outfmt != CV_D) {
00970                         /*
00971                          * The input point is now pointing to a double in host format.  If the
00972                          * output is also in host format then the next conversion will be
00973                          * the last conversion, set the destination to reflect this.
00974                          */
00975 
00976                         if (outIsHost == CV_HOST_MASK) {
00977                     to = out;
00978                         } else {
00979                     to = t3;
00980                         }
00981 
00982                         /*
00983                          * The ouput format is something other than DOUBLE (tested for earlier),
00984                          * do a cast from double to requested format.
00985                          */
00986                         hold = to;
00987 
00988                         switch (outcookie & (CV_SIGNED_MASK | CV_TYPE_MASK)) {
00989                         case CV_SIGNED_MASK | CV_8:
00990                     for (i=0; i<work_count; i++) {
00991                                         *((signed char *)to) = *((double *)from);
00992                                         to = (genptr_t)(((signed char *)to) + 1);
00993                                         from = (genptr_t)(((double *)from) + 1);
00994                     }
00995                     break;
00996                         case CV_8:
00997                     for (i=0; i<work_count; i++) {
00998                                         *((unsigned char *)to) =
00999                                                 (unsigned char)(*((double *)from));
01000                                         to = (genptr_t)(((unsigned char *)to) + 1);
01001                                         from = (genptr_t)(((double *)from) + 1);
01002                     }
01003                     break;
01004                         case CV_SIGNED_MASK | CV_16:
01005                     for (i=0; i<work_count; i++) {
01006                                         *((signed short int *)to) =
01007                                                 *((double *)from);
01008                                         to = (genptr_t)(((signed short int *)to) + 1);
01009                                         from = (genptr_t)(((double *)from) + 1);
01010                     }
01011                     break;
01012                         case CV_16:
01013                     for (i=0; i<work_count; i++) {
01014                                         *((unsigned short int *)to) =
01015                                                 *((double *)from);
01016                                         to = (genptr_t)(((unsigned short int *)to) + 1);
01017                                         from = (genptr_t)(((double *)from) + 1);
01018                     }
01019                     break;
01020                         case CV_SIGNED_MASK | CV_32:
01021                     for (i=0; i<work_count; i++) {
01022                                         *((signed long int *)to) =
01023                                                 *((double *)from);
01024                                         to = (genptr_t)(((signed long int *)to) + 1);
01025                                         from = (genptr_t)(((double *)from) + 1);
01026                     }
01027                     break;
01028                         case CV_32:
01029                     for (i=0; i<work_count; i++) {
01030                                         *((unsigned long int *)to) =
01031                                                 *((double *)from);
01032                                         to = (genptr_t)(((unsigned long int *)to) + 1);
01033                                         from = (genptr_t)(((double *)from) + 1);
01034                     }
01035                     break;
01036                         default:
01037                                 fprintf( stderr, "Unimplemented output format\n");
01038                                 break;
01039 
01040                         }
01041                         from = hold;
01042                         /*
01043                          * The input is now pointing to a host formated buffer of the requested
01044                          * output format.
01045                          */
01046 
01047                         /*
01048                          * If the output conversion is network then do a host to net call
01049                          * for either 16 or 32 bit values using Host TO Network All Short | Long
01050                          */
01051                         if (outIsHost != CV_HOST_MASK) {
01052                                 switch (outfmt) {
01053                                 case CV_D:
01054                                         (void) htond((unsigned char *)out,
01055                                                                                          (unsigned char *)from,
01056                                                                                          work_count);
01057                                         break;
01058                                 case CV_16 | CV_SIGNED_MASK:
01059                                         (void) bu_cv_htonss(out, bufsize, from,
01060                                                                                                                         work_count);
01061                                         break;
01062                                 case CV_16:
01063                                         (void) bu_cv_htonus(out, bufsize, from,
01064                                                                                                                         work_count);
01065                                         break;
01066                                 case CV_32 | CV_SIGNED_MASK:
01067                                         (void) bu_cv_htonsl(out, bufsize, from,
01068                                                                                                                         work_count);
01069                                         break;
01070                                 case CV_32:
01071                                         (void) bu_cv_htonul(out, bufsize, from,
01072                                                                                                                         work_count);
01073                                         break;
01074                                 }
01075                         }
01076 
01077                 }
01078                 /*
01079                  * move the output pointer.
01080                  * reduce the amount of space remaining in the output buffer.
01081                  * Increment the count of values converted.
01082                  */
01083                 out = ((char *)out) + work_count * outsize;
01084                 size -= work_count * outsize;
01085                 number_done += work_count;
01086         }
01087         /*
01088          * All Done!  Clean up and leave.
01089          */
01090         bu_free(t1, "vert.c: t1");
01091         bu_free(t2, "vert.c: t2");
01092         bu_free(t3, "vert.c: t3");
01093         return(number_done);
01094 }
01095 /*@}*/
01096 /*
01097  * Local Variables:
01098  * mode: C
01099  * tab-width: 8
01100  * c-basic-offset: 4
01101  * indent-tabs-mode: t
01102  * End:
01103  * ex: shiftwidth=4 tabstop=8
01104  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6