Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief UBF library
0003  *   The emulator of UBF library
0004  *   Enduro Execution Library
0005  *   Internal implementation of the library - no entry error checks.
0006  *   Errors are checked on entry pointers only in ubf.c!
0007  *   TODO: Add checks for user passed bfldid type. If bigger than BFLD_CARRAY, then reject with BBADFLD.
0008  *
0009  * @file ubf_impl.c
0010  */
0011 /* -----------------------------------------------------------------------------
0012  * Enduro/X Middleware Platform for Distributed Transaction Processing
0013  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0014  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0015  * This software is released under one of the following licenses:
0016  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0017  * See LICENSE file for full text.
0018  * -----------------------------------------------------------------------------
0019  * AGPL license:
0020  *
0021  * This program is free software; you can redistribute it and/or modify it under
0022  * the terms of the GNU Affero General Public License, version 3 as published
0023  * by the Free Software Foundation;
0024  *
0025  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0026  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0027  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0028  * for more details.
0029  *
0030  * You should have received a copy of the GNU Affero General Public License along 
0031  * with this program; if not, write to the Free Software Foundation, Inc.,
0032  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0033  *
0034  * -----------------------------------------------------------------------------
0035  * A commercial use license is available from Mavimax, Ltd
0036  * contact@mavimax.com
0037  * -----------------------------------------------------------------------------
0038  */
0039 
0040 /*---------------------------Includes-----------------------------------*/
0041 #include <string.h>
0042 #include <stdio.h>
0043 #include <stdlib.h>
0044 #include <memory.h>
0045 
0046 #include <ubf.h>
0047 #include <ubf_int.h>    /* Internal headers for UBF... */
0048 #include <fdatatype.h>
0049 #include <ferror.h>
0050 #include <fieldtable.h>
0051 #include <ndrstandard.h>
0052 #include <ndebug.h>
0053 #include <cf.h>
0054 
0055 /*#define BIN_SEARCH_DEBUG*/
0056 /*---------------------------Externs------------------------------------*/
0057 /*---------------------------Macros-------------------------------------*/
0058 /*---------------------------Enums--------------------------------------*/
0059 /*---------------------------Typedefs-----------------------------------*/
0060 struct ubf_type_cache
0061 {
0062     ssize_t  cache_offset;
0063 };
0064 typedef struct ubf_type_cache ubf_type_cache_t;
0065 
0066 /*---------------------------Globals------------------------------------*/
0067 /*---------------------------Statics------------------------------------*/
0068 
0069 /**
0070  * UBF cache offset table
0071  */
0072 static ubf_type_cache_t M_ubf_type_cache[] = 
0073 {
0074     0, /* SHORT */
0075     EXOFFSET(UBF_header_t,cache_long_off), /* LONG */
0076     EXOFFSET(UBF_header_t,cache_char_off), /* CHAR */
0077     EXOFFSET(UBF_header_t,cache_float_off), /* FLOAT */
0078     EXOFFSET(UBF_header_t,cache_double_off), /* DOUBLE */
0079     EXOFFSET(UBF_header_t,cache_string_off), /* STRING */
0080     EXOFFSET(UBF_header_t,cache_carray_off), /* CARRAY */
0081     EXFAIL, /* INT */
0082     EXFAIL, /* RFU */
0083     EXOFFSET(UBF_header_t,cache_ptr_off), /* PTR */
0084     EXOFFSET(UBF_header_t,cache_ubf_off), /* UBF */
0085     EXOFFSET(UBF_header_t,cache_view_off), /* VIEW */
0086 };
0087 
0088 /*---------------------------Prototypes---------------------------------*/
0089 exprivate inline void ubf_cache_set(UBFH *p_ub, BFLDID fldid, int next_offset);
0090 
0091 /**
0092  * Dump the UBF cache
0093  */
0094 expublic void ubf_cache_dump(UBFH *p_ub, char *msg)
0095 {
0096     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0097     UBF_LOG(log_debug, "%s: ubf cache short, 0: %d", msg, 0);
0098     UBF_LOG(log_debug, "%s: ubf cache long, 1: %d", msg, hdr->cache_long_off);
0099     UBF_LOG(log_debug, "%s: ubf cache char, 2: %d", msg, hdr->cache_char_off);
0100     UBF_LOG(log_debug, "%s: ubf cache float, 3: %d", msg, hdr->cache_float_off);
0101     UBF_LOG(log_debug, "%s: ubf cache double, 4: %d", msg, hdr->cache_double_off);
0102     UBF_LOG(log_debug, "%s: ubf cache string, 5: %d", msg, hdr->cache_string_off);
0103     UBF_LOG(log_debug, "%s: ubf cache carray, 6: %d", msg, hdr->cache_carray_off);
0104     
0105     UBF_LOG(log_debug, "%s: ubf cache ptr, 6: %d", msg, hdr->cache_ptr_off);
0106     UBF_LOG(log_debug, "%s: ubf cache ubf, 6: %d", msg, hdr->cache_view_off);
0107     UBF_LOG(log_debug, "%s: ubf cache view, 6: %d", msg, hdr->cache_ubf_off);
0108 }
0109 /**
0110  * Update the cache (usable after merge)...
0111  */
0112 expublic int ubf_cache_update(UBFH *p_ub)
0113 {
0114     int type;
0115     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0116     BFLDID   *p_bfldid = &hdr->bfldid;
0117     BFLDID   *p_bfldid_start = &hdr->bfldid;
0118     BFLDID   *p_cur;
0119     char *p = (char *)&hdr->bfldid;
0120     dtype_str_t *dtype=NULL;
0121     char *fn = "ubf_cache_update";
0122     int typenext;
0123     int step;
0124     int ret = EXSUCCEED;
0125     int i;
0126     
0127     /* reset cache... */
0128     for (i=1; i<N_DIM(M_ubf_type_cache); i++)
0129     {
0130         if (M_ubf_type_cache[i].cache_offset > EXFAIL)
0131         {
0132             BFLDLEN *offset = (BFLDLEN *)(((char *)hdr) + M_ubf_type_cache[i].cache_offset);
0133             *offset = 0;
0134         }
0135     }
0136 
0137 #ifdef BIN_SEARCH_DEBUG
0138     UBF_LOG(log_debug, "%s: About to update ubf bin-search cache", fn);
0139 #endif
0140     
0141     while (!UBF_EOF(hdr, p_bfldid))
0142     {
0143         /* Got to next position */
0144         /* Get type */
0145         type = (*p_bfldid>>EFFECTIVE_BITS);
0146         
0147 #ifdef BIN_SEARCH_DEBUG
0148         UBF_LOG(log_debug, "%s: Got field: [%d], type %d", fn, *p_bfldid, type);
0149 #endif
0150 
0151         /* Check data type alignity */
0152         if (IS_TYPE_INVALID(type))
0153         {
0154             ndrx_Bset_error_fmt(BALIGNERR, "%s: Invalid field type (%d)", fn, *p_bfldid);
0155             EXFAIL_OUT(ret);
0156         }
0157         
0158         p_cur = p_bfldid;
0159         
0160         /* Get type descriptor */
0161         dtype = &G_dtype_str_map[type];
0162         step = dtype->p_next(dtype, p, NULL);
0163         p+=step;
0164         /* Align error */
0165         if (CHECK_ALIGN(p, p_ub, hdr))
0166         {
0167             ndrx_Bset_error_fmt(BALIGNERR, "%s: Pointing to non UBF area: %p",
0168                                         fn, p);
0169             EXFAIL_OUT(ret);
0170         }
0171         p_bfldid = (BFLDID *)p;
0172         
0173         if (UBF_EOF(hdr, p_bfldid))
0174         {
0175             typenext=EXFAIL;
0176         }
0177         else
0178         {
0179             typenext = (*p_bfldid>>EFFECTIVE_BITS);
0180         }
0181         
0182 #ifdef BIN_SEARCH_DEBUG
0183         UBF_LOG(log_debug, "%s: Next field: [%d], type %d", fn, *p_bfldid, typenext);
0184 #endif
0185         
0186         if (type!=typenext)
0187         {
0188             /* Update the cache */
0189             int offset = (((char *)p_bfldid) - ((char *)p_bfldid_start));
0190             ubf_cache_set(p_ub, *p_cur, offset);
0191         }
0192         else
0193         {
0194 #ifdef BIN_SEARCH_DEBUG
0195             UBF_LOG(log_debug, "%s: Not updating type=%d, typenext=%d", fn, type, typenext);
0196 #endif
0197         }
0198     }
0199     
0200 out:
0201     return ret;
0202 }
0203 
0204 /**
0205  * Set cache absolute values
0206  * @param p_ub UBF buffer
0207  * @param fldid last field ID
0208  * @param next_offset offset of the end of the fldid
0209  */
0210 exprivate inline void ubf_cache_set(UBFH *p_ub, BFLDID fldid, int next_offset)
0211 {
0212     UBF_header_t *uh = (UBF_header_t *)p_ub;
0213     char *fn = "ubf_cache_shift";
0214     int type = (fldid>>EFFECTIVE_BITS);
0215     
0216     switch (type)
0217     {
0218         case BFLD_SHORT:
0219             uh->cache_long_off=next_offset;
0220 #ifdef BIN_SEARCH_DEBUG
0221             UBF_LOG(log_debug, "%s: BFLD_SHORT, uh->cache_long_off => %d", 
0222                     fn, uh->cache_long_off);
0223 #endif
0224         case BFLD_LONG:
0225             uh->cache_char_off=next_offset;
0226 #ifdef BIN_SEARCH_DEBUG
0227             UBF_LOG(log_debug, "%s: BFLD_LONG, uh->cache_char_off=> %d", 
0228                     fn, uh->cache_char_off);
0229 #endif
0230         case BFLD_CHAR:
0231             uh->cache_float_off=next_offset;
0232 #ifdef BIN_SEARCH_DEBUG
0233             UBF_LOG(log_debug, "%s: BFLD_CHAR, uh->cache_float_off=> %d", 
0234                     fn, uh->cache_float_off);
0235 #endif
0236         case BFLD_FLOAT:
0237             uh->cache_double_off=next_offset;
0238 #ifdef BIN_SEARCH_DEBUG
0239             UBF_LOG(log_debug, "%s: BFLD_FLOAT, uh->cache_double_off=> %d", 
0240                     fn, uh->cache_double_off);
0241 #endif
0242         case BFLD_DOUBLE:
0243             uh->cache_string_off=next_offset;
0244 #ifdef BIN_SEARCH_DEBUG
0245             UBF_LOG(log_debug, "%s: BFLD_DOUBLE, uh->cache_string_off=> %d", 
0246                     fn, uh->cache_string_off);
0247 #endif
0248         case BFLD_STRING:
0249             uh->cache_carray_off=next_offset;
0250 #ifdef BIN_SEARCH_DEBUG
0251             UBF_LOG(log_debug, "%s: BFLD_STRING, uh->cache_carray_off=> %d", 
0252                     fn, uh->cache_carray_off);
0253 #endif      
0254         case BFLD_CARRAY:
0255             uh->cache_ptr_off=next_offset;
0256 #ifdef BIN_SEARCH_DEBUG
0257             UBF_LOG(log_debug, "%s: BFLD_CARRAY, uh->cache_ptr_off=> %d", 
0258                     fn, uh->cache_ptr_off);
0259 #endif      
0260         case BFLD_PTR:
0261             uh->cache_ubf_off=next_offset;
0262 #ifdef BIN_SEARCH_DEBUG
0263             UBF_LOG(log_debug, "%s: BFLD_PTR, uh->cache_ubf_off=> %d", 
0264                     fn, uh->cache_ubf_off);
0265 #endif      
0266         case BFLD_UBF:
0267             uh->cache_view_off=next_offset;
0268 #ifdef BIN_SEARCH_DEBUG
0269             UBF_LOG(log_debug, "%s: BFLD_UBF, uh->cache_view_off=> %d", 
0270                     fn, uh->cache_view_off);
0271 #endif
0272             break;
0273             
0274     }
0275 }
0276 /**
0277  * Update fielded buffer cache according to 
0278  * @param p_ub
0279  * @param fldid
0280  * @param size_diff
0281  */
0282 expublic inline void ubf_cache_shift(UBFH *p_ub, BFLDID fldid, int size_diff)
0283 {
0284     UBF_header_t *uh = (UBF_header_t *)p_ub;
0285     char *fn = "ubf_cache_shift";
0286     int type = (fldid>>EFFECTIVE_BITS);
0287     
0288     switch (type)
0289     {
0290         case BFLD_SHORT:
0291             uh->cache_long_off+=size_diff;
0292 #ifdef BIN_SEARCH_DEBUG
0293             UBF_LOG(log_debug, "%s: BFLD_SHORT, uh->cache_long_off+=%d => %d", 
0294                     fn, size_diff, uh->cache_long_off);
0295 #endif
0296         case BFLD_LONG:
0297             uh->cache_char_off+=size_diff;
0298 #ifdef BIN_SEARCH_DEBUG
0299             UBF_LOG(log_debug, "%s: BFLD_LONG, uh->cache_char_off+=%d => %d", 
0300                     fn, size_diff, uh->cache_char_off);
0301 #endif
0302         case BFLD_CHAR:
0303             uh->cache_float_off+=size_diff;
0304 #ifdef BIN_SEARCH_DEBUG
0305             UBF_LOG(log_debug, "%s: BFLD_CHAR, uh->cache_float_off+=%d => %d", 
0306                     fn, size_diff, uh->cache_float_off);
0307 #endif
0308         case BFLD_FLOAT:
0309             uh->cache_double_off+=size_diff;
0310 #ifdef BIN_SEARCH_DEBUG
0311             UBF_LOG(log_debug, "%s: BFLD_FLOAT, uh->cache_double_off+=%d => %d", 
0312                     fn, size_diff, uh->cache_double_off);
0313 #endif
0314         case BFLD_DOUBLE:
0315             uh->cache_string_off+=size_diff;
0316 #ifdef BIN_SEARCH_DEBUG
0317             UBF_LOG(log_debug, "%s: BFLD_DOUBLE, uh->cache_string_off+=%d => %d", 
0318                     fn, size_diff, uh->cache_string_off);
0319 #endif
0320         case BFLD_STRING:
0321             uh->cache_carray_off+=size_diff;
0322 #ifdef BIN_SEARCH_DEBUG
0323             UBF_LOG(log_debug, "%s: BFLD_STRING, uh->cache_carray_off+=%d => %d", 
0324                     fn, size_diff, uh->cache_carray_off);
0325 #endif      
0326         case BFLD_CARRAY:
0327             uh->cache_ptr_off+=size_diff;
0328 #ifdef BIN_SEARCH_DEBUG
0329             UBF_LOG(log_debug, "%s: BFLD_CARRAY, uh->cache_ptr_off+=%d => %d", 
0330                     fn, size_diff, uh->cache_ptr_off);
0331 #endif
0332         case BFLD_PTR:
0333             uh->cache_ubf_off+=size_diff;
0334 #ifdef BIN_SEARCH_DEBUG
0335             UBF_LOG(log_debug, "%s: BFLD_PTR, uh->cache_ubf_off+=%d => %d", 
0336                     fn, size_diff, uh->cache_ubf_off);
0337 #endif
0338         case BFLD_UBF:
0339             uh->cache_view_off+=size_diff;
0340 #ifdef BIN_SEARCH_DEBUG
0341             UBF_LOG(log_debug, "%s: BFLD_UBF, uh->cache_view_off+=%d => %d", 
0342                     fn, size_diff, uh->cache_view_off);
0343 #endif
0344             break;
0345     }
0346    return;
0347 }
0348 
0349 /**
0350  * Get field ID at index
0351  * @param start
0352  * @param i
0353  * @param step
0354  * @return 
0355  */
0356 exprivate inline BFLDID get_fldid_at_idx(char *start, int i, int step)
0357 {
0358     BFLDID fld = *((BFLDID   *)(start + i*step));
0359     
0360     return fld;
0361 }
0362 
0363 /**
0364  * return the occurrence of current field.
0365  * @param start
0366  * @param f
0367  * @param i
0368  * @param step
0369  * @return G
0370  */
0371 exprivate inline int get_fld_occ_from_idx(char *start, BFLDID f, int i, int step)
0372 {
0373     char *cur = start + i*step;
0374     BFLDID cur_fld = *((BFLDID   *)cur);
0375     int occ = -1;
0376     
0377     while (cur_fld == f && cur >=start)
0378     {
0379         occ++;
0380         i--;
0381         cur = start + i*step;
0382         
0383         if (cur>=start)
0384         {
0385             cur_fld = *((BFLDID   *)cur);
0386         }
0387     }
0388     
0389     return occ;
0390     
0391 }
0392 
0393 /**
0394  * Get the ptr to field (or NULL) if given occurrence is not found
0395  * @param start
0396  * @param stop
0397  * @param i
0398  * @param step
0399  * @param req_occ
0400  * @return 
0401  */
0402 exprivate inline char * get_field(char *start, char *stop, BFLDID f, int i, int step, 
0403         int req_occ, int get_last, int *last_occ, char ** last_match, char ** last_checked)
0404 {
0405     char *tmp;
0406     char *cur;
0407     BFLDID   *f1;
0408     
0409     int iocc = get_fld_occ_from_idx(start, f, i, step);
0410     
0411     if (get_last & UBF_BINSRCH_GET_LAST)
0412     {
0413 get_last:
0414         /* operate in last off mode */
0415         tmp = cur = start + step * i;
0416         
0417         /* try to search for last one.... */
0418         while (cur < stop)
0419         {
0420             tmp = start + step * (i+1);
0421             f1 = (BFLDID *)tmp;
0422             if (tmp >= stop)
0423             {
0424                 break;
0425             }
0426             else if (*f1 > f)
0427             {
0428                 break;
0429             }
0430             else if (*f1==f)
0431             {
0432                 i++;
0433                 iocc++;
0434                 cur = tmp;
0435             }
0436         }
0437         if (NULL!=last_occ)
0438         {
0439             /* hm, not sure is it ok? maybe just i? but maint get_loc works as this */
0440 #ifdef BIN_SEARCH_DEBUG
0441             UBF_LOG(log_debug, "*last_occ = %d", *last_occ);
0442 #endif
0443             *last_occ = iocc;
0444         }
0445 
0446         /* for change, we set to next field actually */
0447         if (get_last & UBF_BINSRCH_GET_LAST_CHG)
0448         {
0449             cur = tmp;
0450         }
0451         
0452         if (NULL!=last_match)
0453         {
0454             *last_match = cur;
0455 #ifdef BIN_SEARCH_DEBUG
0456             UBF_LOG(log_debug, "*last_match = %p", last_match);
0457 #endif
0458         }
0459 
0460         if (NULL!=last_checked)
0461         {
0462             *last_checked = cur;
0463 #ifdef BIN_SEARCH_DEBUG
0464             UBF_LOG(log_debug, "*last_match = %p", last_match);
0465 #endif
0466         }
0467         
0468         return NULL;
0469     }
0470     else if (req_occ<=iocc)
0471     {
0472 #ifdef BIN_SEARCH_DEBUG
0473         UBF_LOG(log_debug, "req_occ<=iocc -> %d<=%d", req_occ, iocc);
0474 #endif
0475         return start + step*(i-(iocc-req_occ)); /* step back positions needed */
0476     }
0477     else
0478     {
0479         char *cur = start + step * (i + req_occ-iocc);
0480         BFLDID cur_fld; 
0481         
0482 #ifdef BIN_SEARCH_DEBUG
0483         UBF_LOG(log_debug, "req_occ %d/ iocc %d", req_occ, iocc);
0484 #endif
0485         
0486         if (cur >= stop)
0487         {
0488             /* so for bchg we need here to locate last valid occ.... */
0489             if (get_last & UBF_BINSRCH_GET_LAST_CHG)
0490             {
0491 #ifdef BIN_SEARCH_DEBUG
0492                 UBF_LOG(log_debug, "going to get_last 1");
0493 #endif
0494                 goto get_last;
0495             }
0496             return NULL; /* field not found (out of bounds) */
0497         }
0498         
0499         cur_fld = *((BFLDID   *)cur);
0500         
0501         if (cur_fld==f)
0502         {
0503             return cur;
0504         }
0505         
0506         /* For change mode, roll to last field */
0507         if (get_last & UBF_BINSRCH_GET_LAST_CHG)
0508         {
0509 #ifdef BIN_SEARCH_DEBUG
0510             UBF_LOG(log_debug, "going to get_last 2");
0511 #endif
0512             goto get_last;
0513         }
0514         
0515     }
0516     
0517     return NULL;
0518     
0519 }
0520 
0521 /**
0522  * Get the field by performing binary search. Must be called for proper field types (
0523  * i.e. non string & non carray)
0524  * @param p_ub
0525  * @param bfldid
0526  * @param last_matched - last matched field (can be used together with last_occ),
0527  *                       It is optional (pas NULL if not needed).
0528  * @param last_checked  - if not NULL, then function will try find the last occ 
0529  *      of the type (even not matched).
0530  *      In case of EOF/not found, this might point to address outside 
0531  *      the bytes_used scope!!!
0532  * @param occ - occurrence to get. If less than -1, then get out the count
0533  * @param last_occ last check occurrence
0534  * @return - ptr to field.
0535  */
0536 expublic char * get_fld_loc_binary_search(UBFH * p_ub, BFLDID bfldid, BFLDOCC occ,
0537                             dtype_str_t **fld_dtype, int get_last, 
0538                             int *last_occ, char ** last_checked, char ** last_match)
0539 {
0540     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0541     BFLDID   *p_bfldid_start = &hdr->bfldid;
0542     BFLDID   *p_bfldid_stop  = &hdr->bfldid;
0543     BFLDID   *curf;
0544     BFLDLEN tmp = 0;
0545     BFLDLEN *to_add1 = &tmp; /* default for short */
0546     BFLDLEN *to_add2;
0547     char *start = (char *)&hdr->bfldid;
0548     char *stop;
0549     dtype_str_t *dtype=NULL;
0550     int type = (bfldid>>EFFECTIVE_BITS);
0551     int step;
0552     int fld_got;
0553     char *tmp1;
0554     char *cur;
0555     char * ret=NULL;
0556     int did_search = EXFALSE;
0557     int first, last, middle, last_middle;
0558     int was_found_fldid = EXFALSE;
0559     char fn[] = "get_fld_loc_binary_search";
0560     
0561     if (type > BFLD_SHORT) /* Short is first, thus no need to cache the type */
0562     {
0563         /* start from the typed offset (type cache) */
0564         to_add1 = (BFLDLEN *)(((char *)hdr) + M_ubf_type_cache[type].cache_offset);
0565         p_bfldid_start= (BFLDID *)(((char *)p_bfldid_start) + *to_add1);
0566         start = (char *)p_bfldid_start;
0567     }
0568 
0569     /* stop will be bigger than start.... anyway (take the next field cache offset) */
0570     /* start from the typed offset (type cache) */
0571     to_add2 = (BFLDLEN *)(((char *)hdr) + M_ubf_type_cache[type+1].cache_offset);
0572     p_bfldid_stop= (BFLDID *)(((char *)p_bfldid_stop) + *to_add2);
0573     stop = (char *)p_bfldid_stop;
0574     
0575 #ifdef BIN_SEARCH_DEBUG
0576     /* if type is present then there must be difference between start & stop */
0577     UBF_LOG(log_error, "start = %p stop = %p diff = %d (off 1 %d (%d) off 2 %d (%d))", 
0578         start, stop, stop-start,
0579         *to_add1,
0580         type,
0581         *to_add2,
0582         type+1
0583     );
0584     
0585     ubf_cache_dump(p_ub, "Offsets...");
0586 #endif
0587     
0588     if (stop-start <=0)
0589     {
0590 #ifdef BIN_SEARCH_DEBUG
0591         UBF_LOG(log_warn, "Field not found stop-start < 0!");
0592 #endif
0593         if (NULL!=last_checked )
0594         {
0595 #ifdef BIN_SEARCH_DEBUG
0596             UBF_LOG(log_debug, "Last search = start");
0597 #endif
0598             *last_checked =start;
0599         }
0600         goto out;
0601     }
0602     
0603     /* get the step of the field... (size of block) */
0604     dtype = &G_dtype_str_map[type];
0605     *fld_dtype=dtype;
0606     step = dtype->p_next(dtype, start, NULL);
0607     
0608     first = 0;
0609     last = (stop-start) / step - 1;
0610     
0611 #ifdef BIN_SEARCH_DEBUG
0612     UBF_LOG(log_error, "start %p stop %p, last=%d", start, stop, last);
0613 #endif
0614     
0615     middle = (first+last)/2;
0616     
0617     if (first<=last)
0618     {
0619 #ifdef BIN_SEARCH_DEBUG
0620         int jj;
0621         
0622         UBF_LOG(log_debug, "---- Dumping the search area ----")
0623         for (jj=first; jj<=last; jj++)
0624         {
0625             cur = start + step * (jj);
0626             curf = (BFLDID*)cur;
0627                         
0628             UBF_LOG(log_debug, "Area: %p Field %x (%d)", 
0629                 cur, *curf, *curf);
0630         }
0631         UBF_LOG(log_debug, "---------------------------------")
0632 #endif
0633         did_search = EXTRUE;
0634     }
0635     
0636     while (first <= last)
0637     {
0638 #ifdef BIN_SEARCH_DEBUG
0639         UBF_LOG(log_debug, "Looking for middle: %d (first: %d, last: %d)", 
0640                 middle, first, last);
0641 #endif
0642         last_middle = middle;
0643         fld_got = get_fldid_at_idx(start, middle, step);
0644         
0645 #ifdef BIN_SEARCH_DEBUG
0646         UBF_LOG(log_debug, "Got field %x (%d) search %x (%d)", 
0647                 fld_got, fld_got, bfldid, bfldid);
0648 #endif
0649         
0650         if ( fld_got < bfldid)
0651         {
0652            first = middle + 1;    
0653         }
0654         else if (fld_got == bfldid)
0655         {
0656             was_found_fldid = EXTRUE;
0657             ret=get_field(start, stop, bfldid, middle, step, occ, get_last, 
0658                    last_occ, last_match, last_checked);
0659 
0660            break;
0661         }
0662         else
0663         {
0664            last = middle - 1;
0665         }
0666 
0667         middle = (first + last)/2;
0668     }
0669     
0670     /* Not found, my provide some support for add 
0671      * Search for the end of the last matched occurrence, i.e. we provide the address
0672      * of the next. If it is end of the buffer, it must be 4x bytes of zero...
0673      * even if we matched, we must get the last field.
0674      */
0675     if (NULL!=last_checked && !was_found_fldid)
0676     {
0677         if (did_search)
0678         {
0679             if (NULL==ret)
0680             {
0681                 char *last_ok;
0682                 last_ok = cur = start + step * last_middle;
0683                 
0684                 if (fld_got < bfldid)
0685                 {
0686                     /* Look forward */
0687                     curf = (BFLDID*)cur;
0688                     /* try to search for last one.... */
0689                     while (cur < stop && *curf < bfldid)
0690                     {
0691                         /* last_ok = cur; */
0692                         last_middle++;
0693                         cur = start + step * (last_middle);
0694                         curf = (BFLDID*)cur;
0695 #ifdef BIN_SEARCH_DEBUG
0696                         UBF_LOG(log_debug, "Stepping forward %p", cur);
0697 #endif
0698                     }
0699                 }
0700                 else
0701                 {
0702                     /* Look back - we must stay at field that is first bigger than
0703                      * ours field...
0704                      */
0705                     curf = (BFLDID*)cur;
0706                     /* try to search for last one.... */
0707                     while (cur > start && *curf > bfldid)
0708                     {   
0709                         last_ok = cur;
0710                         last_middle--;
0711                         cur = start + step * (last_middle);
0712                         curf = (BFLDID*)cur;
0713 #ifdef BIN_SEARCH_DEBUG
0714                         UBF_LOG(log_debug, "Stepping back %p", cur);
0715 #endif
0716                     }
0717                     
0718                     cur = last_ok;
0719                     
0720                 }
0721                 
0722                 *last_checked = cur;
0723 #ifdef BIN_SEARCH_DEBUG
0724                 UBF_LOG(log_debug, "*last_checked = %p", *last_checked);
0725 #endif
0726             }
0727             else
0728             {   
0729                 *last_checked = ret;
0730 #ifdef BIN_SEARCH_DEBUG
0731                 UBF_LOG(log_debug, "*last_checked = %p", *last_checked);
0732 #endif
0733             }
0734         }
0735         else
0736         {
0737             *last_checked = start;
0738 #ifdef BIN_SEARCH_DEBUG
0739             UBF_LOG(log_debug, "*last_checked = %p", *last_checked);
0740 #endif
0741         }
0742     }
0743     
0744 out:
0745             
0746 #ifdef BIN_SEARCH_DEBUG
0747     UBF_LOG(log_debug, "%s ret %p", fn, ret);
0748 #endif
0749 
0750     return ret;
0751 }
0752 
0753 
0754 /**
0755  * Returns pointer to Fb of for specified field
0756  * @param p_ub
0757  * @param bfldid
0758  * @param last_matched - last matched field (can be used together with last_occ),
0759  *                       It is optional (pas NULL if not needed).
0760  * @param occ - occurrence to get. If less than -1, then get out the count
0761  * @param last_occ last check occurrence
0762  * @param last_checked - BE WARNED! In case of not found, this will point to hdr+bytes_used 
0763  * (to non existing field address)!
0764  * @return - ptr to field.
0765  */
0766 expublic char * get_fld_loc(UBFH * p_ub, BFLDID bfldid, BFLDOCC occ,
0767                             dtype_str_t **fld_dtype,
0768                             char ** last_checked,
0769                             char **last_matched,
0770                             int *last_occ,
0771                             Bfld_loc_info_t *last_start)
0772 {
0773     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0774     BFLDID   *p_bfldid = &hdr->bfldid;
0775     char *p = (char *)&hdr->bfldid;
0776     dtype_str_t *dtype=NULL;
0777     int iocc=EXFAIL;
0778     int type = (bfldid>>EFFECTIVE_BITS);
0779     int step;
0780     char * ret=NULL;
0781     *fld_dtype=NULL;
0782     int stat = EXSUCCEED;
0783     char fn[] = "get_fld_loc";
0784     int eof;
0785 
0786     *last_occ = EXFAIL;
0787     /*
0788      * Roll the field till the
0789      */
0790     if (NULL!=last_start)
0791     {
0792         p_bfldid = (BFLDID *)last_start->last_checked;
0793         p = (char *)last_start->last_checked;
0794     }
0795     else if (type > BFLD_SHORT) /* Short is first, thus no need to cache the type */
0796     {
0797         /* start from the typed offset (type cache) */
0798         BFLDLEN *to_add = (BFLDLEN *)(((char *)hdr) + M_ubf_type_cache[type].cache_offset);
0799         p_bfldid= (BFLDID *)(((char *)p_bfldid) + *to_add);
0800         p = (char *)p_bfldid;
0801     }
0802     
0803     /* ok we match first... then step to next. */
0804     /* test only if we are not at the end... */
0805     if (!UBF_EOF(hdr, p_bfldid) && bfldid == *p_bfldid)
0806     {
0807         iocc++;
0808         
0809         /* Save last matched position */
0810         if (NULL!=last_matched)
0811             *last_matched = p;
0812     }
0813 
0814     while ( !(eof=UBF_EOF(hdr, p_bfldid))  &&
0815             ( (bfldid != *p_bfldid) || (bfldid == *p_bfldid && (iocc<occ || occ<-1))) &&
0816             bfldid >= *p_bfldid)
0817     {
0818         /*
0819          * Update the start of the new field
0820          * This keeps us in track what was last normal field check.
0821          * This is useful for Update function. As we know buffers are in osrted
0822          * order and any new fields that are find by Bnext in case of update
0823          * should be appended starting for current position in buffer.
0824          */
0825         if (NULL!=last_start && *last_start->last_checked!=*p_bfldid)
0826         {
0827             last_start->last_checked = p_bfldid;
0828         }
0829 
0830         /* Got to next position */
0831         /* Get type */
0832         type = (*p_bfldid>>EFFECTIVE_BITS);
0833 
0834         /* Check data type alignity */
0835         if (IS_TYPE_INVALID(type))
0836         {
0837             ndrx_Bset_error_fmt(BALIGNERR, "%s: Found invalid data type in buffer %d", 
0838                                         fn, type);
0839             stat=EXFAIL;
0840             goto out;
0841         }
0842 
0843         /* Get type descriptor */
0844         dtype = &G_dtype_str_map[type];
0845         step = dtype->p_next(dtype, p, NULL);
0846         p+=step;
0847         
0848         if (EXTRUE==(eof=UBF_EOF(hdr, p)))
0849         {
0850             break;
0851         }
0852             
0853         p_bfldid = (BFLDID *)p;
0854 
0855         if (bfldid == *p_bfldid)
0856         {
0857             iocc++;
0858             
0859             /* Save last matched position */
0860             if (NULL!=last_matched)
0861                 *last_matched = p;
0862         }
0863     }
0864 
0865     /*
0866      * Check that we found correct field!?!
0867      * if not then responding with NULL!
0868      */
0869     if (!eof && bfldid ==*p_bfldid && iocc==occ)
0870     {
0871         type = (*p_bfldid>>EFFECTIVE_BITS);
0872         /* Check data type alignity */
0873         if (IS_TYPE_INVALID(type))
0874         {
0875             
0876             ndrx_Bset_error_fmt(BALIGNERR, "Found invalid data type in buffer %d", type);
0877             stat=EXFAIL;
0878             goto out;
0879         }
0880         else
0881         {
0882             dtype = &G_dtype_str_map[type];
0883             *fld_dtype=dtype;
0884             ret=(char *)p_bfldid;
0885         }
0886     }
0887 
0888     *last_occ = iocc;
0889     /* set up last checked, it could be even next element! */
0890     
0891     if (!eof)
0892     {
0893         *last_checked=(char *)p_bfldid;
0894     }
0895     else
0896     {
0897         /* Last check will go over the boundaries! */
0898         *last_checked=(char *)hdr + hdr->bytes_used;
0899     }
0900     
0901     
0902     UBF_LOG(log_debug, "*last_checked %p, last_occ=%d", *last_checked, *last_occ);
0903     
0904 out:
0905     return ret;
0906 }
0907 
0908 /**
0909  * Checks the buffer to so do we have enought place for new data
0910  * @param p_ub UBF buffer
0911  * @param add_size data to be added
0912  * @return
0913  */
0914 expublic int have_buffer_size(UBFH *p_ub, int add_size, int set_err)
0915 {
0916     int ret=EXFALSE;
0917     UBF_header_t *hdr = (UBF_header_t *)p_ub;
0918     int buf_free = hdr->buf_len - hdr->bytes_used;
0919 
0920     /* Keep last ID as BBADFLDID (already included in size) */
0921     if ( buf_free < add_size)
0922     {
0923         if (set_err)
0924             ndrx_Bset_error_fmt(BNOSPACE, "Buffsize free [%d] new data size [%d]",
0925                     buf_free, add_size);
0926         return EXFALSE;
0927     }
0928     else
0929     {
0930         return EXTRUE;
0931     }
0932 /*
0933     return ret;
0934 */
0935 }
0936 
0937 /**
0938  * Validates parameters entered into function. If not valid, then error will be set
0939  * @param p_ub
0940  * @return
0941  */
0942 expublic inline int validate_entry(UBFH *p_ub, BFLDID bfldid, int occ, int mode)
0943 {
0944     int ret=EXSUCCEED;
0945     UBF_header_t *hdr = (UBF_header_t *) p_ub;
0946     BFLDID *last;
0947     char *p;
0948     if (NULL==p_ub)
0949     {
0950         /* Null buffer */
0951         ndrx_Bset_error_msg(BNOTFLD, "ptr to UBFH is NULL");
0952         EXFAIL_OUT(ret);
0953     }
0954     else if (0!=strncmp(hdr->magic, UBF_MAGIC, UBF_MAGIC_SIZE))
0955     {
0956         ndrx_Bset_error_msg(BNOTFLD, "Invalid FB magic");
0957         EXFAIL_OUT(ret);
0958     }
0959     else if (!(mode & VALIDATE_MODE_NO_FLD) && BBADFLDID==bfldid)
0960     {
0961         /* Invalid arguments? */
0962         ndrx_Bset_error_msg(BBADFLD, "bfldid == BBADFLDID");
0963         EXFAIL_OUT(ret);
0964     }
0965     else if (!(mode & VALIDATE_MODE_NO_FLD) && IS_TYPE_INVALID(bfldid>>EFFECTIVE_BITS))
0966     {   /* Invalid field id */
0967         ndrx_Bset_error_fmt(BBADFLD, "Invalid bfldid (type %d not correct)",
0968                 ((int)bfldid>>EFFECTIVE_BITS));
0969         EXFAIL_OUT(ret);
0970     }
0971     else if (!(mode & VALIDATE_MODE_NO_FLD) && occ < -1)
0972     {
0973         ndrx_Bset_error_msg(BEINVAL, "occ < -1");
0974         EXFAIL_OUT(ret);
0975     }
0976    
0977 out:
0978     return ret;
0979 }
0980 
0981 /**
0982  * Internal version of Baddfast
0983  * @return EXSUCCEED/EXFAIL
0984  */
0985 expublic int ndrx_Baddfast (UBFH *p_ub, BFLDID bfldid, char *buf, BFLDLEN len, 
0986     Bfld_loc_info_t *next_fld)
0987 {
0988     int ret = EXSUCCEED;
0989     
0990     if (NULL==next_fld)
0991     {
0992         ndrx_Bset_error_msg(BEINVAL, "next_fld must not be NULL!");
0993         return EXFAIL;
0994     }
0995     
0996     /* check that rules are OK */
0997     if (BBADFLDID!=next_fld->last_Baddfast &&
0998             bfldid < next_fld->last_Baddfast)
0999     {
1000         ndrx_Bset_error_fmt(BEINVAL, "bfldid (%u) < next_fld->last_Baddfast (%u)!",
1001                 bfldid, next_fld->last_Baddfast);
1002         return EXFAIL;
1003     }
1004     
1005     if (EXSUCCEED==(ret=ndrx_Badd (p_ub, bfldid, buf, len, NULL, next_fld)))
1006     {
1007         /* Support #622 save the result */
1008         next_fld->last_Baddfast = bfldid;
1009     }
1010     
1011     return ret;
1012 }
1013 
1014 /**
1015  * Add value to FB...
1016  * TODO: Move to binary search.
1017  * If adding the first value, the buffer should be large enought and last
1018  * BFLDID should stay at BADFLID, because will not be overwritten.
1019  * Also last entry always must at BBADFLDID! This is the rule.
1020  * @param next_fld ptr to next field after this is added
1021  */
1022 expublic int ndrx_Badd (UBFH *p_ub, BFLDID bfldid, 
1023                     char *buf, BFLDLEN len,
1024                     Bfld_loc_info_t *last_start, Bfld_loc_info_t *next_fld)
1025 {
1026     int ret=EXSUCCEED;
1027     UBF_header_t *hdr = (UBF_header_t *)p_ub;
1028     BFLDID   *p_bfldid = &hdr->bfldid;
1029     char *p = (char *)&hdr->bfldid;
1030     char *last;
1031     int move_size;
1032     int actual_data_size;
1033     int type = (bfldid>>EFFECTIVE_BITS);
1034     char fn[] = "_Badd";
1035     int ntype;
1036     dtype_str_t *ndtype;
1037     int new_dat_size;
1038 /***************************************** DEBUG *******************************/
1039 #ifdef UBF_API_DEBUG
1040     /* Real debug stuff!! */
1041     UBF_header_t *__p_ub_copy;
1042     int __dbg_type;
1043     int __dbg_vallen;
1044     int *__dbg_fldptr_org;
1045     int *__dbg_fldptr_new;
1046     char *__dbg_p_org;
1047     char *__dbg_p_new;
1048     int __dbg_newuse;
1049     int __dbg_olduse;
1050     int __dump_size;
1051     dtype_str_t *__dbg_dtype;
1052     dtype_ext1_t *__dbg_dtype_ext1;
1053     
1054     __p_ub_copy = NDRX_MALLOC(hdr->buf_len);
1055     memcpy(__p_ub_copy, p_ub, hdr->buf_len);
1056     __dbg_type = (bfldid>>EFFECTIVE_BITS);
1057     __dbg_dtype = &G_dtype_str_map[__dbg_type];
1058     __dbg_dtype_ext1 = &G_dtype_ext1_map[__dbg_type];
1059     __dbg_vallen = __dbg_dtype->p_get_data_size(__dbg_dtype, buf, len,
1060                                                 &actual_data_size);
1061     UBF_LOG(log_debug, "Badd: entry, adding\nfld=[%d/%p] "
1062                                     "spec len=%d type[%hd/%s] datalen=%d\n"
1063                                     "FBbuflen=%d FBused=%d FBfree=%d "
1064                                     "FBstart fld=[%s/%d/%p] ",
1065                                     bfldid, bfldid, len,
1066                                     __dbg_type, __dbg_dtype->fldname,
1067                                     __dbg_vallen,
1068                                     hdr->buf_len, hdr->bytes_used,
1069                                     (hdr->buf_len - hdr->bytes_used),
1070                                     ndrx_Bfname_int(bfldid), bfldid, bfldid);
1071     __dbg_dtype_ext1->p_dump_data(__dbg_dtype_ext1, "Adding data", buf, &len);
1072     UBF_DUMP(log_always, "_Badd data to buffer:", buf, actual_data_size);
1073 #endif
1074 /*******************************************************************************/
1075 
1076     UBF_LOG(log_debug, "Badd: bfldid: %d", bfldid);
1077     
1078     ntype = (bfldid>>EFFECTIVE_BITS);
1079     ndtype = &G_dtype_str_map[ntype];
1080     /* Move memory around (i.e. prepare free space to put data in) */
1081     new_dat_size=ndtype->p_get_data_size(ndtype, buf, len, &actual_data_size);
1082     
1083     if (new_dat_size<0)
1084     {
1085         UBF_LOG(log_error, "Invalid data size: %d", new_dat_size);
1086         EXFAIL_OUT(ret);
1087     }
1088 
1089     /* Check required buffer size */
1090     if (!have_buffer_size(p_ub, new_dat_size, EXTRUE))
1091     {
1092         UBF_LOG(log_warn, "Badd failed - out of buffer memory!");
1093         EXFAIL_OUT(ret);
1094     }
1095 
1096     if (NULL!=next_fld && NULL!=next_fld->last_checked)
1097     {
1098     p_bfldid = next_fld->last_checked;
1099     p = (char *)next_fld->last_checked;
1100     }
1101     /* Allow to continue - better performance for concat */
1102     else if (NULL!=last_start)
1103     {
1104         p_bfldid = last_start->last_checked;
1105         p = (char *)last_start->last_checked;
1106     }
1107     else if (UBF_BINARY_SEARCH_OK(bfldid))
1108     {
1109         dtype_str_t *tmp;
1110         get_fld_loc_binary_search(p_ub, bfldid, EXFAIL,
1111                             &tmp, UBF_BINSRCH_GET_LAST_CHG, 
1112                             NULL, &p, NULL);
1113         p_bfldid= (BFLDID *)p;
1114     }
1115     else
1116     {
1117         BFLDLEN *to_add = (BFLDLEN *)(((char *)hdr) + M_ubf_type_cache[type].cache_offset);
1118         p_bfldid= (BFLDID *)(((char *)p_bfldid) + *to_add);
1119         p = (char *)p_bfldid;
1120     }
1121 
1122     /* Seek position where we should insert the data... */
1123     while (!UBF_EOF(hdr, p_bfldid) && bfldid >= *p_bfldid)
1124     {
1125         dtype_str_t *dtype;
1126         int step;
1127         int type;
1128     
1129         /*
1130          * Save the point from which we can continue (suitable for Bconcat)
1131          */
1132         if (NULL!=last_start && *last_start->last_checked!=*p_bfldid)
1133         {
1134             last_start->last_checked = p_bfldid;
1135         }
1136 
1137         /* Got to next position */
1138         /* Get type */
1139         type = (*p_bfldid>>EFFECTIVE_BITS);
1140         if (IS_TYPE_INVALID(type))
1141         {
1142             ndrx_Bset_error_fmt(BALIGNERR, "%s: Unknown data type referenced %d",
1143                                         fn, type);
1144             EXFAIL_OUT(ret);
1145         }
1146         /* Get type descriptor */
1147         dtype = &G_dtype_str_map[type];
1148         step = dtype->p_next(dtype, p, NULL);
1149 
1150         /* Move to next... */
1151         p+=step;
1152         /* Align error */
1153         if (CHECK_ALIGN(p, p_ub, hdr))
1154         {
1155             ndrx_Bset_error_fmt(BALIGNERR, "%s: Pointing to non UBF area: %p "
1156                     "(offset: %ld)", fn, p, (long)(p-((char *)hdr)));
1157             EXFAIL_OUT(ret);
1158         }
1159         p_bfldid = (BFLDID *)p;
1160     }
1161 
1162     if (UBF_EOF(hdr, p_bfldid))
1163     {
1164         /* Copy data here! */
1165         if (EXSUCCEED!=ndtype->p_put_data(ndtype, p, bfldid, buf, len))
1166         {
1167             EXFAIL_OUT(ret);
1168         }
1169         
1170         hdr->bytes_used+=new_dat_size;
1171         
1172         /* Update type offset cache: */
1173         ubf_cache_shift(p_ub, bfldid, new_dat_size);
1174         
1175     }
1176     else
1177     {
1178         last = (char *)hdr;
1179         last+=(hdr->bytes_used-1);
1180 
1181         /* Get the size to be moved */
1182         move_size = (last-p+1);
1183         /* Get some free space here!
1184          * So from last element we take off current position,
1185          * so we get length. to which we should move.
1186          */
1187         memmove(p+new_dat_size, p, move_size);
1188         /* Put the data in! */
1189         if (EXSUCCEED!=ndtype->p_put_data(ndtype, p, bfldid, buf, len))
1190         {
1191             EXFAIL_OUT(ret);
1192         }
1193         /* Update the pointer of last bit! */
1194         hdr->bytes_used+=new_dat_size;
1195         
1196         /* Update type offset cache: */
1197         ubf_cache_shift(p_ub, bfldid, new_dat_size);
1198         
1199     }
1200     
1201     if (NULL!=next_fld)
1202     {
1203         /* so mark as next by data size */
1204         next_fld->last_checked = (BFLDID *)(p + new_dat_size);
1205     }
1206     
1207 out:
1208 /***************************************** DEBUG *******************************/
1209 #ifdef UBF_API_DEBUG
1210     __dbg_olduse = (__p_ub_copy->buf_len - __p_ub_copy->bytes_used);
1211     __dbg_newuse = (hdr->buf_len - hdr->bytes_used);
1212 
1213     /* Do bellow to print out end element (last) of the array - should be bbadfldid */
1214     __dbg_p_org = (char *)__p_ub_copy;
1215     __dbg_p_org+= (__p_ub_copy->bytes_used - FF_USED_BYTES);
1216 
1217     __dbg_p_new = (char *)hdr;
1218     __dbg_p_new+= (hdr->bytes_used - FF_USED_BYTES);
1219 
1220     __dbg_fldptr_org = (int *)__dbg_p_org;
1221     __dbg_fldptr_new = (int *)__dbg_p_new;
1222 
1223     UBF_LOG(log_debug, "Badd: returns=%d\norg_used=%d new_used=%d diff=%d "
1224                                 "org_start=%d/%p new_start=%d/%p\n"
1225                                 "old_finish=%d/%p, new_finish=%d/%p",
1226                                 ret,
1227                                 __dbg_olduse,
1228                                 __dbg_newuse,
1229                                 (__dbg_olduse - __dbg_newuse),
1230                                 __p_ub_copy->bfldid, __p_ub_copy->bfldid,
1231                                 hdr->bfldid, hdr->bfldid,
1232                                 *__dbg_fldptr_org, *__dbg_fldptr_org,
1233                                 *__dbg_fldptr_new, *__dbg_fldptr_new);
1234     /* Check the last four bytes before the end */
1235     __dbg_p_org-= FF_USED_BYTES;
1236     __dbg_p_new-= FF_USED_BYTES;
1237     __dbg_fldptr_org = (int *)__dbg_p_org;
1238     __dbg_fldptr_new = (int *)__dbg_p_new;
1239     UBF_LOG(log_debug, "Badd: last %d bytes of data\n org=%p new %p",
1240                           FF_USED_BYTES, *__dbg_fldptr_org, *__dbg_fldptr_new);
1241     UBF_DUMP_DIFF(log_always, "After Badd", __p_ub_copy, p_ub, hdr->buf_len);
1242     __dump_size=hdr->bytes_used;
1243     UBF_DUMP(log_always, "Used buffer dump after: ",p_ub, __dump_size);
1244     NDRX_FREE(__p_ub_copy);
1245 #endif
1246 /*******************************************************************************/
1247     return ret;
1248 }
1249 
1250 /**
1251  * Change field content...
1252  * @param
1253  * @param
1254  * @param
1255  * @param
1256  * @param
1257  * @param upd_only - when is set to EXTRUE update only existing fields 
1258  * and not add new fields in p_ub, otherwise update existing fields and 
1259  * add new fields when they not exist in p_fb
1260  * @return
1261  */
1262 expublic int ndrx_Bchg (UBFH *p_ub, BFLDID bfldid, BFLDOCC occ,
1263                             char * buf, BFLDLEN len,
1264                             Bfld_loc_info_t *last_start, int upd_only)
1265 {
1266     int ret=EXSUCCEED;
1267 
1268     UBF_header_t *hdr = (UBF_header_t *)p_ub;
1269     BFLDID   *p_bfldid = &hdr->bfldid;
1270     dtype_str_t *dtype;
1271     char *p;
1272     int last_occ=-1;
1273     dtype_ext1_t *ext1_map;
1274     int i;
1275     char *last;
1276     int move_size;
1277     char *last_checked=NULL;
1278     int elem_empty_size;
1279     int target_elem_size;
1280     int actual_data_size;
1281 /***************************************** DEBUG *******************************/
1282 #ifdef UBF_API_DEBUG
1283     /* Real debug stuff!! */
1284     UBF_header_t *__p_ub_copy;
1285     int __dbg_type;
1286     int __dbg_vallen;
1287     int *__dbg_fldptr_org;
1288     int *__dbg_fldptr_new;
1289     char *__dbg_p_org;
1290     char *__dbg_p_new;
1291     int __dbg_newuse;
1292     int __dbg_olduse;
1293     dtype_str_t *__dbg_dtype;
1294     dtype_ext1_t *__dbg_dtype_ext1;
1295     int __dump_size;
1296 #endif
1297 /*******************************************************************************/
1298     /* Call other functions on standard criteria */
1299     if (occ == -1)
1300     {
1301         UBF_LOG(log_debug, "Bchg: calling Badd, because occ == -1!");
1302         return Badd(p_ub, bfldid, buf, len); /* <<<< RETURN HERE! */
1303     }
1304     else if (NULL==buf)
1305     {
1306         UBF_LOG(log_debug, "Bchg: calling Bdel, because buf == NULL!");
1307         return Bdel(p_ub, bfldid, occ); /* <<<< RETURN HERE! */
1308     }
1309 /***************************************** DEBUG *******************************/
1310 #ifdef UBF_API_DEBUG
1311     __p_ub_copy = NDRX_MALLOC(hdr->buf_len);
1312     memcpy(__p_ub_copy, p_ub, hdr->buf_len);
1313     __dbg_type = (bfldid>>EFFECTIVE_BITS);
1314     __dbg_dtype = &G_dtype_str_map[__dbg_type];
1315     __dbg_dtype_ext1 = &G_dtype_ext1_map[__dbg_type];
1316     __dbg_vallen = __dbg_dtype->p_get_data_size(__dbg_dtype, buf, len,
1317                                                 &actual_data_size);
1318     UBF_LOG(log_debug, "Bchg: entry, adding\nfld=[%d/%p] occ=[%d] "
1319                                     "spec len=%d type[%hd/%s] datalen=%d\n"
1320                                     "FBbuflen=%d FBused=%d FBfree=%d "
1321                                     "FBstart fld=[%s/%d/%p] ",
1322                                     bfldid, bfldid, occ, len,
1323                                     __dbg_type, __dbg_dtype->fldname,
1324                                     __dbg_vallen,
1325                                     hdr->buf_len, hdr->bytes_used,
1326                                     (hdr->buf_len - hdr->bytes_used),
1327                                     ndrx_Bfname_int(bfldid), bfldid, bfldid);
1328     __dbg_dtype_ext1->p_dump_data(__dbg_dtype_ext1, "Bchg data", buf, &len);
1329     UBF_DUMP(log_always, "Bchg data to buffer:", buf, actual_data_size);
1330 #endif
1331 /*******************************************************************************/
1332     UBF_LOG(log_debug, "%s: changing %d occ=%d", __func__, bfldid, occ);
1333     
1334     if (UBF_BINARY_SEARCH_OK(bfldid))
1335     {
1336         p = get_fld_loc_binary_search(p_ub, bfldid, occ, &dtype,
1337                             UBF_BINSRCH_GET_LAST_CHG, &last_occ, &last_checked, NULL);
1338     }
1339     else
1340     {
1341        p=get_fld_loc(p_ub, bfldid, occ, &dtype, 
1342                                 &last_checked, NULL, &last_occ, last_start);
1343     }
1344     
1345     if (NULL!=p)
1346     {
1347        /* Play slightly differently here - get the existing data size */
1348         int existing_size;
1349         int must_have_size;
1350         UBF_LOG(log_debug, "Bchg: Field present, checking buff sizes");
1351 
1352         existing_size = dtype->p_next(dtype, p, NULL);
1353         target_elem_size = dtype->p_get_data_size(dtype, buf, len, &actual_data_size);
1354 
1355         /* Which may happen for badly formatted data! */
1356         if (EXFAIL==target_elem_size)
1357         {
1358             ndrx_Bset_error_msg(BEINVAL, "Failed to get data size - corrupted data?");
1359             EXFAIL_OUT(ret);
1360         }
1361 
1362         /* how much we are going to add */
1363         must_have_size = target_elem_size - existing_size;
1364         if ( must_have_size>0 && !have_buffer_size(p_ub, must_have_size, EXTRUE))
1365         {
1366             EXFAIL_OUT(ret);
1367         }
1368 
1369         if (must_have_size!=0)
1370         { 
1371             BFLDLEN debug_before;
1372             int real_move = must_have_size;
1373             if (real_move < 0 )
1374                 real_move = -real_move;
1375             /* Free up space in memory if required (i.e. do the move) */
1376             last = (char *)hdr;
1377             last+=(hdr->bytes_used-1);
1378             move_size = (last-(p+existing_size)+1);
1379 
1380             UBF_LOG(log_debug, "Bchg: memmove: %d bytes "
1381                             "from addr %p to addr %p", real_move,
1382                              p+existing_size, p+existing_size+must_have_size);
1383 
1384             /* Free up, or make more memory to be used! */
1385             memmove(p+existing_size + must_have_size, p+existing_size, move_size); 
1386             
1387             debug_before = hdr->bytes_used;
1388             
1389             hdr->bytes_used+=must_have_size;
1390             
1391             UBF_LOG(log_debug, "%s: bytes_used: %d (+%d)-> %d",
1392                 __func__, debug_before, must_have_size, hdr->bytes_used);
1393            
1394             /* Update type offset cache: */
1395             ubf_cache_shift(p_ub, bfldid, must_have_size);
1396             
1397             /* Reset last bytes to 0 */
1398             if (must_have_size < 0)
1399             {
1400                 /* Reset trailing stuff to 0 - this should be tested! */
1401                 /*TODO: Opt ???
1402                 memset(p+existing_size + must_have_size+move_size, 0, real_move);
1403                  * */
1404             }
1405         }
1406 
1407         /* Put the actual data there, buffer sizes already resized above */
1408         if (EXSUCCEED!=dtype->p_put_data(dtype, p, bfldid, buf, len))
1409         {
1410             ndrx_Bset_error_msg(BEINVAL, "Failed to put data into FB - corrupted data?");
1411             EXFAIL_OUT(ret);
1412         }
1413     }
1414     else
1415     {
1416         if (EXTRUE == upd_only)
1417         {
1418             UBF_LOG(log_debug, "%s: Update only!! Field %d not found occ=%d",
1419                     __func__, bfldid, occ);
1420             goto out;
1421         }
1422         /* We know something about last field?  */
1423         int missing_occ;
1424         int must_have_size;
1425         int empty_elem_tot_size;
1426         BFLDLEN debug_before;
1427         
1428 #if 0
1429         -- this is always set, even to invalid addr.
1430         if (NULL==last_checked)
1431         {
1432             /* so element was not found, calculate "virtual address" */
1433             last_checked = ((char *)hdr) + hdr->bytes_used;
1434         }
1435 #endif
1436         
1437         p = last_checked;
1438         p_bfldid = (BFLDID *)last_checked;
1439         int type;
1440 
1441         UBF_LOG(log_debug, "Bchg: Field not present. last_occ=%d",
1442                 last_occ);
1443         /*
1444          * Read data type again, because we do not have it in case if it is not
1445          * exact match!
1446          */
1447         type = (bfldid>>EFFECTIVE_BITS);
1448         dtype = &G_dtype_str_map[type];
1449 
1450         ext1_map = &G_dtype_ext1_map[dtype->fld_type];
1451 
1452         /* 1. Have to calculate new size, if elem was not preset at all (last_occ = -1),
1453          * then for example occ=0, last_occ = -1, which makes:
1454          * 0 - (-1) - 1 = 0, meaning that there is nothing missing.
1455          */
1456         missing_occ = occ - last_occ - 1; /* -1 cos end elem is ours */
1457         UBF_LOG(log_debug, "Missing empty positions: %d (occ: %d, last_occ: %d)", 
1458                 missing_occ, occ, last_occ);
1459         
1460         elem_empty_size = ext1_map->p_empty_sz(ext1_map);
1461         empty_elem_tot_size = missing_occ * ext1_map->p_empty_sz(ext1_map);
1462 
1463         target_elem_size = dtype->p_get_data_size(dtype, buf, len, &actual_data_size);
1464 
1465 
1466         if (EXFAIL==target_elem_size)
1467         {
1468             ndrx_Bset_error_msg(BEINVAL, "Failed to get data size - corrupted data?");
1469             EXFAIL_OUT(ret);
1470         }
1471 
1472         must_have_size=empty_elem_tot_size+target_elem_size;
1473         UBF_LOG(log_debug, "About to add data %d bytes (total used: %d, total: %d), "
1474                 "target_elem_size: %d, empty_elem_tot_size: %d, missing_occ: %d",
1475                 must_have_size, hdr->bytes_used, hdr->buf_len,
1476                 target_elem_size, empty_elem_tot_size, missing_occ);
1477         
1478         if (!have_buffer_size(p_ub, must_have_size, EXTRUE))
1479         {
1480             EXFAIL_OUT(ret);
1481         }
1482         
1483         /* Free up space in memory if required (i.e. do the move) */
1484         last = (char *)hdr;
1485         last+=(hdr->bytes_used-1);
1486         /* Get the size to be moved */
1487         move_size = (last-p+1); /* <<< p is incorrect here! */
1488         /* Get some free space here!
1489          * So from last element we take off current position,
1490          * so we get lenght. to which we should move.
1491          */
1492         if (move_size > 0)
1493         {
1494             UBF_LOG(log_debug, "Bchg: memmove: %d bytes "
1495                             "from addr %p to addr %p", move_size,
1496                             p, p+must_have_size);
1497             memmove(p+must_have_size, p, move_size);
1498         }
1499 
1500         /* We have space, so now produce empty nodes */
1501         for (i=0; i<missing_occ; i++)
1502         {
1503             ext1_map->p_put_empty(ext1_map, p, bfldid);
1504             p+=elem_empty_size;
1505         }
1506         /* Now load the data by itself - do not check the
1507          * result it should work out OK.
1508          */
1509         if (EXSUCCEED!=dtype->p_put_data(dtype, p, bfldid, buf, len))
1510         {
1511             /* We have failed! */
1512             ndrx_Bset_error_msg(BEINVAL, "Failed to put data into FB - corrupted data?");
1513             EXFAIL_OUT(ret);
1514         }       
1515         debug_before = hdr->bytes_used;
1516         /* Finally increase the buffer usage! */
1517         hdr->bytes_used+=must_have_size;
1518         
1519         UBF_LOG(log_debug, "%s: bytes_used: %d (+%d)-> %d",
1520             __func__, debug_before, must_have_size, hdr->bytes_used);
1521         
1522         
1523         /* Update type offset cache: */
1524         ubf_cache_shift(p_ub, bfldid, must_have_size);
1525         
1526     }
1527     
1528 out:
1529 /***************************************** DEBUG *******************************/
1530 #ifdef UBF_API_DEBUG
1531     __dbg_olduse = (__p_ub_copy->buf_len - __p_ub_copy->bytes_used);
1532     __dbg_newuse = (hdr->buf_len - hdr->bytes_used);
1533 
1534     /* Do bellow to print out end element (last) of the array - should be bbadfldid */
1535     __dbg_p_org = (char *)__p_ub_copy;
1536     __dbg_p_org+= (__p_ub_copy->bytes_used - FF_USED_BYTES);
1537 
1538     __dbg_p_new = (char *)hdr;
1539     __dbg_p_new+= (hdr->bytes_used - FF_USED_BYTES);
1540 
1541     __dbg_fldptr_org = (int *)__dbg_p_org;
1542     __dbg_fldptr_new = (int *)__dbg_p_new;
1543 
1544     UBF_LOG(log_debug, "Bchg: returns=%d\norg_used=%d new_used=%d diff=%d "
1545                                 "org_start=%d/%p new_start=%d/%p\n"
1546                                 "old_finish=%d/%p, new_finish=%d/%p",
1547                                 ret,
1548                                 __dbg_olduse,
1549                                 __dbg_newuse,
1550                                 (__dbg_olduse - __dbg_newuse),
1551                                 __p_ub_copy->bfldid, __p_ub_copy->bfldid,
1552                                 hdr->bfldid, hdr->bfldid,
1553                                 *__dbg_fldptr_org, *__dbg_fldptr_org,
1554                                 *__dbg_fldptr_new, *__dbg_fldptr_new);
1555     /* Check the last four bytes before the end */
1556     __dbg_p_org-= FF_USED_BYTES;
1557     __dbg_p_new-= FF_USED_BYTES;
1558     __dbg_fldptr_org = (int *)__dbg_p_org;
1559     __dbg_fldptr_new = (int *)__dbg_p_new;
1560     UBF_LOG(log_debug, "Bchg: last %d bytes of data\n org=%p new %p",
1561                           FF_USED_BYTES, *__dbg_fldptr_org, *__dbg_fldptr_new);
1562     UBF_DUMP_DIFF(log_always, "After Bchg diff: ", __p_ub_copy, p_ub, hdr->buf_len);
1563 
1564     __dump_size=hdr->bytes_used;
1565     UBF_DUMP(log_always, "Used buffer dump after: ",p_ub, __dump_size);
1566 
1567     NDRX_FREE(__p_ub_copy);
1568 #endif
1569 /*******************************************************************************/
1570 
1571     return ret;
1572 }
1573 
1574 /**
1575  * Get the total occurrance count.
1576  * Internal version - no error checking.
1577  * @param p_ub
1578  * @param bfldid
1579  * @return
1580  */
1581 expublic BFLDOCC ndrx_Boccur (UBFH * p_ub, BFLDID bfldid)
1582 {
1583     dtype_str_t *fld_dtype;
1584     BFLDID *p_last=NULL;
1585     int ret=EXFAIL;
1586 
1587     UBF_LOG(log_debug, "_Boccur: bfldid: %d", bfldid);
1588 
1589     /* using -2 for looping throught te all occurrances! */
1590     if (UBF_BINARY_SEARCH_OK(bfldid))
1591     {
1592         get_fld_loc_binary_search(p_ub, bfldid, EXFAIL, &fld_dtype, 
1593                     UBF_BINSRCH_GET_LAST, &ret, NULL, NULL);
1594     }
1595     else
1596     {
1597         get_fld_loc(p_ub, bfldid, -2,
1598                                 &fld_dtype,
1599                                 (char **)&p_last,
1600                                 NULL,
1601                                 &ret,
1602                                 NULL);
1603     }
1604     if (EXFAIL==ret)
1605     {
1606         /* field not found! */
1607         ret=0;
1608     }
1609     else
1610     {
1611         /* found (but zero based) so have to increment! */
1612         ret+=1;
1613     }
1614 
1615     UBF_LOG(log_debug, "_Boccur: return %d", ret);
1616 
1617     return ret;
1618 }
1619 
1620 /**
1621  * Check the field presence
1622  * Internal version - no error checking.
1623  */
1624 expublic int _Bpres (UBFH *p_ub, BFLDID bfldid, BFLDOCC occ)
1625 {
1626     dtype_str_t *fld_dtype;
1627     BFLDID *p_last=NULL;
1628     int last_occ;
1629     int ret=EXTRUE;
1630     char *ret_ptr;
1631 
1632     UBF_LOG(log_debug, "_Bpres: bfldid: %d occ: %d", bfldid, occ);
1633     
1634 
1635     if (UBF_BINARY_SEARCH_OK(bfldid))
1636     {
1637         ret_ptr = get_fld_loc_binary_search(p_ub, bfldid, occ, &fld_dtype, 
1638                 UBF_BINSRCH_GET_LAST_NONE, NULL, NULL, NULL);
1639     }
1640     else
1641     {
1642         ret_ptr = get_fld_loc(p_ub, bfldid, occ,
1643                                 &fld_dtype,
1644                                 (char **)&p_last,
1645                                 NULL,
1646                                 &last_occ,
1647                                 NULL);
1648     }
1649     
1650     if (NULL!=ret_ptr)
1651     {
1652         ret=EXTRUE;
1653     }
1654     else
1655     {
1656         ret=EXFALSE;
1657     }
1658 
1659 
1660     UBF_LOG(log_debug, "_Boccur: return %d", ret);
1661 
1662     return ret;
1663 }
1664 
1665 /**
1666  * Get the next occurrence. This will iterate over the all FB. Inside it uses
1667  * static pointer & counter for fields.
1668  *
1669  * Search must start with BFIRSTFLDID
1670  * @param p_ub
1671  * @param bfldid
1672  * @param occ
1673  * @param buf
1674  * @param len
1675  * @param d_ptr - pointer to start of the data (result is similar of Bfind result)
1676  * @return 0 - not found/ 1 - entry found.
1677  */
1678 expublic int ndrx_Bnext(Bnext_state_t *state, UBFH *p_ub, BFLDID *bfldid,
1679                                 BFLDOCC *occ, char *buf, BFLDLEN *len,
1680                                 char **d_ptr)
1681 {
1682     int found=EXSUCCEED;
1683     UBF_header_t *hdr = (UBF_header_t *)p_ub;
1684     BFLDID prev_fld;
1685     int step;
1686     int type;
1687     dtype_str_t *dtype;
1688     char *p;
1689     char fn[] = "ndrx_Bnext";
1690     #ifdef UBF_API_DEBUG
1691     dtype_ext1_t *__dbg_dtype_ext1;
1692     #endif
1693 
1694     if (*bfldid == BFIRSTFLDID)
1695     {
1696         state->p_cur_bfldid = &hdr->bfldid;
1697         state->cur_occ = 0;
1698         state->p_ub = p_ub;
1699         state->size = hdr->bytes_used;
1700         p = (char *)&hdr->bfldid;
1701     }
1702     else if (*bfldid==BBADFLDOCC)
1703     {
1704         /* used internally to search from particular positions */
1705         p = (char *)state->p_cur_bfldid;
1706     }
1707     else
1708     {
1709         /* Get current field type */
1710         prev_fld = *state->p_cur_bfldid;
1711         /* Get data type */
1712         type=*state->p_cur_bfldid>>EFFECTIVE_BITS;
1713 
1714         /* Align error */
1715         if (IS_TYPE_INVALID(type))
1716         {
1717             ndrx_Bset_error_fmt(BALIGNERR, "Invalid data type: %d", type);
1718             found=EXFAIL;
1719             goto out;
1720         }
1721 
1722         dtype=&G_dtype_str_map[type];
1723         p=(char *)state->p_cur_bfldid;
1724         /* Get step to next */
1725         step = dtype->p_next(dtype, p, NULL);
1726         p+=step;
1727 
1728         /* Align error */
1729         if (CHECK_ALIGN(p, p_ub, hdr))
1730         {
1731             ndrx_Bset_error_fmt(BALIGNERR, "%s: Pointing to non UBF area: %p", fn, p);
1732             found=EXFAIL;
1733             goto out;
1734         }
1735         
1736         /* Move to next */
1737         state->p_cur_bfldid = (BFLDID *)p;
1738         if (!UBF_EOF(hdr, state->p_cur_bfldid) && prev_fld==*state->p_cur_bfldid)
1739         {
1740             state->cur_occ++;
1741         }
1742         else
1743         {
1744             state->cur_occ=0;
1745         }
1746     }
1747     
1748     /* return the results */
1749     if (!UBF_EOF(hdr, state->p_cur_bfldid))
1750     {
1751         /* Return the value if needed */
1752         *bfldid = *state->p_cur_bfldid;
1753         *occ = state->cur_occ;
1754         UBF_LOG(log_debug, "%s: Found field buf=%p fldid=%d occ %d",
1755                                             fn, p_ub, *bfldid, *occ);
1756 
1757         found = 1;
1758         /* Return the value */
1759         type=*state->p_cur_bfldid>>EFFECTIVE_BITS;
1760 
1761         if (IS_TYPE_INVALID(type))
1762         {
1763             ndrx_Bset_error_fmt(BALIGNERR, "Invalid data type: %d", type);
1764             found=EXFAIL;
1765             goto out;
1766         }
1767         dtype=&G_dtype_str_map[type];
1768         
1769         /*
1770          * Return the pointer to start of the field.
1771          */
1772         if (NULL!=d_ptr)
1773         {
1774             int dlen;
1775             dtype_ext1_t *dtype_ext1;
1776             /* Return the pointer to the data */
1777             dtype_ext1 = &G_dtype_ext1_map[type];
1778             dlen = dtype_ext1->hdr_size;
1779             
1780             if (NULL!=dtype_ext1->p_prep_ubfp)
1781             {
1782                 *d_ptr=dtype_ext1->p_prep_ubfp(dtype_ext1, &state->vstorage, p);
1783             }
1784             else
1785             {
1786                 *d_ptr=p+dlen;
1787             }
1788         }
1789 
1790         if (NULL!=buf)
1791         {
1792             
1793             /* Prepare layout for view? Assuming data starts after the
1794              * header?
1795              */
1796             if (BFLD_VIEW==type)
1797             {
1798                 /* format the buf accordingly...*/
1799                 UBF_LOG(log_debug, "Bnext on view -> setting data=%p + d",
1800                         buf, sizeof(BVIEWFLD));
1801                 BVIEWFLD *vf = (BVIEWFLD *)buf;
1802                 vf->data=buf+sizeof(BVIEWFLD);
1803                 
1804                 if (NULL!=len)
1805                 {
1806                     if (*len < sizeof(BVIEWFLD))
1807                     {
1808                         ndrx_Bset_error_fmt(BNOSPACE, "Minimums size for view is "
1809                                 "sizeof BVIEWFLD (%d) but have: %d",
1810                                 sizeof(BVIEWFLD), *len);
1811                         found=EXFAIL;
1812                         goto out;
1813                     }
1814                     else
1815                     {
1816                         /* reduce the output len... */
1817                         *len-=sizeof(BVIEWFLD);
1818                     }
1819                     
1820                 }
1821             }
1822             
1823             if (EXSUCCEED!=dtype->p_get_data(dtype, (char *)p, buf, len))
1824             {
1825                 found=EXFAIL;
1826                 goto out;
1827             }
1828 #ifdef UBF_API_DEBUG
1829             else
1830             {
1831                 /* Dump found value */
1832                 __dbg_dtype_ext1 = &G_dtype_ext1_map[type];
1833                 __dbg_dtype_ext1->p_dump_data(__dbg_dtype_ext1, "_Bnext got data",
1834                                                 buf, len);
1835             }
1836 #endif
1837         }
1838         else if (NULL!=len)
1839         {
1840             /* return length only... */
1841             dtype->p_next(dtype, p, len);
1842         }
1843         else
1844         {
1845             UBF_LOG(log_info, "%s: Buffer null - not returning value", fn);
1846         }
1847     }
1848     else
1849     {
1850         UBF_LOG(log_debug, "%s: Reached End Of Buffer", fn);
1851         /* do not return anything */
1852         found = 0; /* End Of Buffer */
1853     }
1854     
1855 out:
1856     return found;
1857 }
1858 
1859 /**
1860  * Internal version of data type conversation.
1861  * This allocates output buffer.
1862  * @param to_len
1863  * @param to_type
1864  * @param from_buf
1865  * @param from_type
1866  * @param from_len - THIS MUST BE SET! Provided for user by API function,
1867  *                      but internally for performance reasons, this is not processed
1868  *                      here.
1869  * @return NULL on failure/ptr to allocted memory if OK.
1870  */
1871 expublic char * ndrx_Btypcvt (BFLDLEN * to_len, int to_type,
1872                     char *from_buf, int from_type, BFLDLEN from_len)
1873 {
1874     char *alloc_buf=NULL;
1875     BFLDLEN  cvn_len=0;
1876     char *ret=NULL;
1877     char fn[]="_Btypcvt";
1878 
1879 /***************************************** DEBUG *******************************/
1880     #ifdef UBF_API_DEBUG
1881     dtype_ext1_t *__dbg_dtype_ext1;
1882     #endif
1883 /*******************************************************************************/
1884 
1885     UBF_LOG(log_debug, "%s: entered, from %d to %d", fn,
1886                                         from_type, to_type);
1887 
1888     /* Allocate the buffer dynamically */
1889     if (NULL==(ret=ndrx_ubf_get_cbuf(from_type, to_type, NULL, from_buf, from_len, &alloc_buf,
1890                                 &cvn_len, CB_MODE_ALLOC, 0)))
1891     {
1892         /* error should be already set */
1893         UBF_LOG(log_error, "%s: Malloc failed!", fn);
1894         goto out;
1895     }
1896     
1897     /* Run the conversation */
1898     if (NULL==ndrx_ubf_convert(from_type, CNV_DIR_OUT, from_buf, from_len,
1899                         to_type, ret, &cvn_len))
1900     {
1901         /* if fails, error should be already set! */
1902         /* remove allocated memory */
1903         NDRX_FREE(alloc_buf);
1904         alloc_buf=NULL;
1905         ret=NULL;
1906         goto out;
1907     }
1908 
1909     /* return output len if requested */
1910     if (NULL!=to_len)
1911         *to_len=cvn_len;
1912 
1913 out:
1914     UBF_LOG(log_debug, "%s: return %p", fn, ret);
1915 
1916 /***************************************** DEBUG *******************************/
1917     #ifdef UBF_API_DEBUG
1918     if (NULL!=ret)
1919     {
1920         __dbg_dtype_ext1 = &G_dtype_ext1_map[to_type];
1921         __dbg_dtype_ext1->p_dump_data(__dbg_dtype_ext1, "_Btypcvt got data", ret,
1922                                                                            to_len);
1923     }
1924     #endif
1925 /*******************************************************************************/
1926 
1927     return ret;
1928 }
1929 
1930 /**
1931  * Back-end for Blen
1932  * @param p_ub
1933  * @param bfldid
1934  * @param occ
1935  * @return 
1936  */
1937 expublic int ndrx_Blen (UBFH *p_ub, BFLDID bfldid, BFLDOCC occ)
1938 {
1939     dtype_str_t *fld_dtype;
1940     BFLDID *p_last=NULL;
1941     int ret=EXSUCCEED;
1942     char *p;
1943 
1944     UBF_LOG(log_debug, "_Blen: bfldid: %d, occ: %d", bfldid, occ);
1945 
1946     /* using -2 for looping through all occurrences! */
1947     
1948     
1949     if (UBF_BINARY_SEARCH_OK(bfldid))
1950     {
1951         p=get_fld_loc_binary_search(p_ub, bfldid, occ, &fld_dtype, 
1952                     UBF_BINSRCH_GET_LAST_NONE, NULL, NULL, NULL);
1953     }
1954     else
1955     {
1956         p=get_fld_loc(p_ub, bfldid, occ,
1957                                 &fld_dtype,
1958                                 (char **)&p_last,
1959                                 NULL,
1960                                 &ret,
1961                                 NULL);
1962     }
1963     
1964     if (EXFAIL!=ret && NULL!=p)
1965     {
1966         
1967         fld_dtype->p_next(fld_dtype, p, &ret);
1968     }
1969     else
1970     {
1971         /* Field not found */
1972         ndrx_Bset_error(BNOTPRES);
1973         ret=EXFAIL;
1974     }
1975 
1976     UBF_LOG(log_debug, "_Boccur: return %d", ret);
1977 
1978     return ret;
1979 }
1980 
1981 /**
1982  * Count all occurrences of the fields in the buffer
1983  * @param p_ub - UBF buffer
1984  * @return Number of all occurrences of the fields in buffer, -1 FAIL
1985  */
1986 expublic BFLDOCC ndrx_Bnum(UBFH *p_ub)
1987 {
1988     BFLDOCC fldcount = 0;
1989     char fn[] = "_Bnum";
1990     #ifdef UBF_API_DEBUG
1991     dtype_ext1_t *__dbg_dtype_ext1;
1992     #endif
1993     /* Seems this caused tricks for multi threading.*/
1994     static __thread Bnext_state_t state;
1995     BFLDID bfldid;
1996     BFLDOCC occ;
1997 
1998     memset(&state, 0, sizeof(state));
1999     bfldid= BFIRSTFLDID;
2000 
2001     while(1==ndrx_Bnext(&state, p_ub, &bfldid, &occ, NULL, NULL, NULL))
2002     {
2003         fldcount++;
2004     }
2005 
2006     return fldcount;
2007 }
2008 
2009 /**
2010  * Allocates buffer & do the initialisation
2011  * Assuming that using GLIBC which returns already aligned.
2012  * @param f - number of fields
2013  * @param v - field size
2014  * @param len_set directly allocate from given bytes
2015  * @return ptr to UBF buffer or NULL
2016  */
2017 expublic UBFH * ndrx_Balloc (BFLDOCC f, BFLDLEN v, long len_set)
2018 {
2019     UBFH *p_ub=NULL;
2020     long alloc_size;
2021     
2022     if (EXFAIL!=len_set)
2023     {
2024         alloc_size = len_set;
2025     }
2026     else
2027     {
2028         /* Bug #394 */
2029         alloc_size = ndrx_Bneeded(f, v);
2030     }
2031     
2032     if ( alloc_size > MAXUBFLEN)
2033     {
2034         ndrx_Bset_error_fmt(BEINVAL, "Requesting %ld, but min is 1 and max is %ld bytes",
2035                 alloc_size, MAXUBFLEN);
2036     }
2037     else
2038     {
2039         p_ub=NDRX_MALLOC(alloc_size);
2040         if (NULL==p_ub)
2041         {
2042             ndrx_Bset_error_fmt(BMALLOC, "Failed to alloc %ld bytes", alloc_size);
2043         }
2044         else
2045         {
2046             if (EXSUCCEED!=Binit(p_ub, alloc_size))
2047             {
2048                 NDRX_FREE(p_ub); /* Free up allocated memory! */
2049                 p_ub=NULL;
2050                 UBF_LOG(log_error, "Balloc failed - abort Balloc!");
2051             }
2052         }
2053     }
2054     
2055     UBF_LOG(log_debug, "Balloc: Returning %p!", p_ub);
2056     
2057     return p_ub;
2058 }
2059 
2060 
2061 /**
2062  * Reallocate the memory
2063  * Assuming that using GLIBC which is already aligned
2064  * 
2065  * @param p_Fb
2066  * @param f
2067  * @param v
2068  * @param[in] len_set preferred length 
2069  * @return reallocated UBF buffer or NULL on failure
2070  */
2071 expublic UBFH * ndrx_Brealloc (UBFH *p_ub, BFLDOCC f, BFLDLEN v, long len_set)
2072 {
2073     UBF_header_t *hdr = (UBF_header_t *)p_ub;
2074     long alloc_size;
2075     
2076     UBF_LOG(log_debug, "Brealloc: enter p_ub=%p f=%d v=%d len_set=%ld", 
2077         p_ub, (int)f, (int)v, len_set);
2078     
2079     if (EXFAIL!=len_set)
2080     {
2081         alloc_size = len_set;
2082     }
2083     else
2084     {
2085         alloc_size = ndrx_Bneeded(f, v);
2086     }
2087 
2088     /*
2089      * New buffer size should not be smaller that used.
2090      */
2091     if ( alloc_size < hdr->bytes_used || alloc_size > MAXUBFLEN)
2092     {
2093         ndrx_Bset_error_fmt(BEINVAL, "Requesting %ld, but min is %ld and max is %ld bytes",
2094                 alloc_size, hdr->buf_len+1, MAXUBFLEN);
2095         Bfree(p_ub);
2096         p_ub=NULL;
2097     }
2098     else
2099     {
2100         p_ub=NDRX_REALLOC(p_ub, alloc_size);
2101         if (NULL==p_ub)
2102         {
2103             ndrx_Bset_error_fmt(BMALLOC, "Failed to alloc %ld bytes", alloc_size);
2104             p_ub=NULL;
2105         }
2106         else
2107         {
2108             long reset_size;
2109             char * p=(char *)p_ub;
2110             /* reset the header pointer */
2111             hdr = (UBF_header_t *)p_ub;
2112             reset_size = alloc_size-hdr->buf_len;
2113 #if 0
2114             if (reset_size>0)
2115             {
2116                 /* Now we need to set buffer ending to 0
2117                  * and we should increase
2118                  */
2119                 UBF_LOG(log_debug, "Resetting reallocated memory to 0. "
2120                                     "From %p %d bytes",
2121                                     p+hdr->buf_len, reset_size);
2122 
2123                 memset(p+hdr->buf_len, 0, reset_size);
2124             }
2125 #endif
2126             /* Update FB to new size. */
2127             hdr->buf_len+=reset_size;
2128         }
2129     }
2130     
2131     UBF_LOG(log_debug, "Brealloc: Returning %p!", p_ub);
2132 
2133     return p_ub;
2134 }
2135 
2136 /* vim: set ts=4 sw=4 et smartindent: */