servlib/bundling/SDNV.cc
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2005-2006 Intel Corporation
       
     3  * 
       
     4  *    Licensed under the Apache License, Version 2.0 (the "License");
       
     5  *    you may not use this file except in compliance with the License.
       
     6  *    You may obtain a copy of the License at
       
     7  * 
       
     8  *        http://www.apache.org/licenses/LICENSE-2.0
       
     9  * 
       
    10  *    Unless required by applicable law or agreed to in writing, software
       
    11  *    distributed under the License is distributed on an "AS IS" BASIS,
       
    12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    13  *    See the License for the specific language governing permissions and
       
    14  *    limitations under the License.
       
    15  */
       
    16 
       
    17 /*
       
    18  * This file is a little funky since it's compiled into both C and C++
       
    19  * (after being #included into sdnv-c.c).
       
    20  */
       
    21 
       
    22 #ifdef HAVE_CONFIG_H
       
    23 #  include <dtn-config.h>
       
    24 #endif
       
    25 
       
    26 #ifdef __cplusplus
       
    27 #include "SDNV.h"
       
    28 #include <oasys/debug/DebugUtils.h>
       
    29 #include <oasys/debug/Log.h>
       
    30 
       
    31 #define SDNV_FN(_what) SDNV::_what
       
    32 
       
    33 namespace dtn {
       
    34 
       
    35 #else // ! __cplusplus
       
    36 
       
    37 #include <stdio.h>
       
    38 #include <stdlib.h>
       
    39 #include <oasys/compat/inttypes.h>
       
    40 
       
    41 #define SDNV_FN(_what) sdnv_##_what
       
    42 
       
    43 //----------------------------------------------------------------------
       
    44 #define ASSERT(x)                                               \
       
    45 do {                                                            \
       
    46     if (! (x)) {                                                \
       
    47         fprintf(stderr, "ASSERTION FAILED (" #x ") at %s:%d\n", \
       
    48                 __FILE__, __LINE__);                            \
       
    49         exit(1);                                                \
       
    50     }                                                           \
       
    51 } while (0)
       
    52             
       
    53 //----------------------------------------------------------------------
       
    54 #define log_err_p(p, args...) fprintf(stderr, "error: (" p ") " args);
       
    55 
       
    56 #define MAX_LENGTH 10
       
    57 
       
    58 #endif // __cplusplus
       
    59             
       
    60 //----------------------------------------------------------------------
       
    61 int
       
    62 SDNV_FN(encode)(u_int64_t val, u_char* bp, size_t len)
       
    63 {
       
    64     u_char* start = bp;
       
    65 
       
    66     /*
       
    67      * Figure out how many bytes we need for the encoding.
       
    68      */
       
    69     size_t val_len = 0;
       
    70     u_int64_t tmp = val;
       
    71 
       
    72     do {
       
    73         tmp = tmp >> 7;
       
    74         val_len++;
       
    75     } while (tmp != 0);
       
    76 
       
    77     ASSERT(val_len > 0);
       
    78     ASSERT(val_len <= MAX_LENGTH);
       
    79 
       
    80     /*
       
    81      * Make sure we have enough buffer space.
       
    82      */
       
    83     if (len < val_len) {
       
    84         return -1;
       
    85     }
       
    86 
       
    87     /*
       
    88      * Now advance bp to the last byte and fill it in backwards with
       
    89      * the value bytes.
       
    90      */
       
    91     bp += val_len;
       
    92     u_char high_bit = 0; // for the last octet
       
    93     do {
       
    94         --bp;
       
    95         *bp = (u_char)(high_bit | (val & 0x7f));
       
    96         high_bit = (1 << 7); // for all but the last octet
       
    97         val = val >> 7;
       
    98     } while (val != 0);
       
    99 
       
   100     ASSERT(bp == start);
       
   101 
       
   102     return val_len;
       
   103 }
       
   104 
       
   105 //----------------------------------------------------------------------
       
   106 size_t
       
   107 SDNV_FN(encoding_len)(u_int64_t val)
       
   108 {
       
   109     u_char buf[16];
       
   110     int ret = SDNV_FN(encode)(val, buf, sizeof(buf));
       
   111     ASSERT(ret != -1 && ret != 0);
       
   112     return ret;
       
   113 }
       
   114 
       
   115 //----------------------------------------------------------------------
       
   116 int
       
   117 SDNV_FN(decode)(const u_char* bp, size_t len, u_int64_t* val)
       
   118 {
       
   119     const u_char* start = bp;
       
   120     
       
   121     if (!val) {
       
   122         return -1;
       
   123     }
       
   124 
       
   125     /*
       
   126      * Zero out the existing value, then shift in the bytes of the
       
   127      * encoding one by one until we hit a byte that has a zero
       
   128      * high-order bit.
       
   129      */
       
   130     size_t val_len = 0;
       
   131     *val = 0;
       
   132     do {
       
   133         if (len == 0)
       
   134             return -1; // buffer too short
       
   135         
       
   136         *val = (*val << 7) | (*bp & 0x7f);
       
   137         ++val_len;
       
   138         
       
   139         if ((*bp & (1 << 7)) == 0)
       
   140             break; // all done;
       
   141 
       
   142         ++bp;
       
   143         --len;
       
   144     } while (1);
       
   145 
       
   146     /*
       
   147      * Since the spec allows for infinite length values but this
       
   148      * implementation only handles up to 64 bits, check for overflow.
       
   149      * Note that the only supportable 10 byte SDNV must store exactly
       
   150      * one bit in the first byte of the encoding (i.e. the 64'th bit
       
   151      * of the original value).
       
   152      * This is OK because a spec update says that behavior
       
   153      * is undefined for values > 64 bits.
       
   154      */
       
   155     if ((val_len > MAX_LENGTH) ||
       
   156         ((val_len == MAX_LENGTH) && (*start != 0x81)))
       
   157     {
       
   158         log_err_p("/dtn/bundle/sdnv", "overflow value in sdnv!!!");
       
   159         return -1;
       
   160     }
       
   161 
       
   162     // XXX/demmer shouldn't use -1 as indication of both too short of
       
   163     // a buffer and of error due to overflow or malformed SDNV since
       
   164     // callers just assume that they need more data to decode and
       
   165     // don't really check for errors
       
   166 
       
   167     return val_len;
       
   168 }
       
   169 
       
   170 //----------------------------------------------------------------------
       
   171 size_t
       
   172 SDNV_FN(len)(const u_char* bp)
       
   173 {
       
   174     size_t          val_len = 1;
       
   175     
       
   176     for ( ; *bp++ & 0x80; ++val_len )
       
   177         ;
       
   178     return val_len;
       
   179 }
       
   180 
       
   181 #ifdef __cplusplus
       
   182 } // namespace dtn
       
   183 #endif
       
   184