SDNV.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2005-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 /*
00018  * This file is a little funky since it's compiled into both C and C++
00019  * (after being #included into sdnv-c.c).
00020  */
00021 #ifdef __cplusplus
00022 #include "SDNV.h"
00023 #include <oasys/debug/DebugUtils.h>
00024 #include <oasys/debug/Log.h>
00025 
00026 #define SDNV_FN(_what) SDNV::_what
00027 
00028 namespace dtn {
00029 
00030 #else // ! __cplusplus
00031 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <oasys/compat/inttypes.h>
00035 
00036 #define SDNV_FN(_what) sdnv_##_what
00037 
00038 //----------------------------------------------------------------------
00039 #define ASSERT(x)                                               \
00040 do {                                                            \
00041     if (! (x)) {                                                \
00042         fprintf(stderr, "ASSERTION FAILED (" #x ") at %s:%d\n", \
00043                 __FILE__, __LINE__);                            \
00044         exit(1);                                                \
00045     }                                                           \
00046 } while (0)
00047             
00048 //----------------------------------------------------------------------
00049 #define log_err_p(p, args...) fprintf(stderr, "error: (" p ") " args);
00050 
00051 #define MAX_LENGTH 10
00052 
00053 #endif // __cplusplus
00054             
00055 //----------------------------------------------------------------------
00056 int
00057 SDNV_FN(encode)(u_int64_t val, u_char* bp, size_t len)
00058 {
00059     u_char* start = bp;
00060 
00061     /*
00062      * Figure out how many bytes we need for the encoding.
00063      */
00064     size_t val_len = 0;
00065     u_int64_t tmp = val;
00066 
00067     do {
00068         tmp = tmp >> 7;
00069         val_len++;
00070     } while (tmp != 0);
00071 
00072     ASSERT(val_len > 0);
00073     ASSERT(val_len <= MAX_LENGTH);
00074 
00075     /*
00076      * Make sure we have enough buffer space.
00077      */
00078     if (len < val_len) {
00079         return -1;
00080     }
00081 
00082     /*
00083      * Now advance bp to the last byte and fill it in backwards with
00084      * the value bytes.
00085      */
00086     bp += val_len;
00087     u_char high_bit = 0; // for the last octet
00088     do {
00089         --bp;
00090         *bp = (u_char)(high_bit | (val & 0x7f));
00091         high_bit = (1 << 7); // for all but the last octet
00092         val = val >> 7;
00093     } while (val != 0);
00094 
00095     ASSERT(bp == start);
00096 
00097     return val_len;
00098 }
00099 
00100 //----------------------------------------------------------------------
00101 size_t
00102 SDNV_FN(encoding_len)(u_int64_t val)
00103 {
00104     u_char buf[16];
00105     int ret = SDNV_FN(encode)(val, buf, sizeof(buf));
00106     ASSERT(ret != -1 && ret != 0);
00107     return ret;
00108 }
00109 
00110 //----------------------------------------------------------------------
00111 int
00112 SDNV_FN(decode)(const u_char* bp, size_t len, u_int64_t* val)
00113 {
00114     const u_char* start = bp;
00115     
00116     if (!val) {
00117         return -1;
00118     }
00119 
00120     /*
00121      * Zero out the existing value, then shift in the bytes of the
00122      * encoding one by one until we hit a byte that has a zero
00123      * high-order bit.
00124      */
00125     size_t val_len = 0;
00126     *val = 0;
00127     do {
00128         if (len == 0)
00129             return -1; // buffer too short
00130         
00131         *val = (*val << 7) | (*bp & 0x7f);
00132         ++val_len;
00133         
00134         if ((*bp & (1 << 7)) == 0)
00135             break; // all done;
00136 
00137         ++bp;
00138         --len;
00139     } while (1);
00140 
00141     /*
00142      * Since the spec allows for infinite length values but this
00143      * implementation only handles up to 64 bits, check for overflow.
00144      * Note that the only supportable 10 byte SDNV must store exactly
00145      * one bit in the first byte of the encoding (i.e. the 64'th bit
00146      * of the original value).
00147      */
00148     if ((val_len > MAX_LENGTH) ||
00149         ((val_len == MAX_LENGTH) && (*start != 0x81)))
00150     {
00151         log_err_p("/dtn/bundle/sdnv", "overflow value in sdnv!!!");
00152         return -1;
00153     }
00154 
00155     // XXX/demmer shouldn't use -1 as indication of both too short of
00156     // a buffer and of error due to overflow or malformed SDNV since
00157     // callers just assume that they need more data to decode and
00158     // don't really check for errors
00159 
00160     return val_len;
00161 }
00162 
00163 #ifdef __cplusplus
00164 } // namespace dtn
00165 #endif
00166 

Generated on Thu Jun 7 12:54:29 2007 for DTN Reference Implementation by  doxygen 1.5.1