Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief ubf<->json conversion lib
0003  *
0004  * @file ubf2exjson.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 #include <stdio.h>
0035 #include <stdlib.h>
0036 #include <string.h>
0037 #include <memory.h>
0038 #include <ctype.h>
0039 #include <errno.h>
0040 
0041 #include <userlog.h>
0042 
0043 #include <ndrstandard.h>
0044 #include <ndebug.h>
0045 
0046 #include <exparson.h>
0047 #include <ubf2exjson.h>
0048 #include <ubf.h>
0049 #include <atmi_int.h>
0050 #include <typed_buf.h>
0051 #include <fieldtable.h>
0052 #include <exbase64.h>
0053 #include <view2exjson.h>
0054 #include "tperror.h"
0055 
0056 
0057 /*------------------------------Externs---------------------------------------*/
0058 /*------------------------------Macros----------------------------------------*/
0059 #define IS_INT(X) (BFLD_SHORT == X || BFLD_LONG == X)
0060 #define IS_NUM(X) (BFLD_FLOAT == X || BFLD_DOUBLE == X)
0061 #define IS_BIN(X) (BFLD_CARRAY == X)
0062 
0063 /* TODO: Fix atmi buffer size to match size of ATMI buffer size. */
0064 #define CARR_BUFFSIZE       NDRX_MSGSIZEMAX
0065 #define CARR_BUFFSIZE_B64   (4 * (CARR_BUFFSIZE) / 3)
0066 /*------------------------------Enums-----------------------------------------*/
0067 /*------------------------------Typedefs--------------------------------------*/
0068 /*------------------------------Globals---------------------------------------*/
0069 /*------------------------------Statics---------------------------------------*/
0070 /*------------------------------Prototypes------------------------------------*/
0071 
0072 
0073 exprivate long round_long( double r ) {
0074     return (r > 0.0) ? (r + 0.5) : (r - 0.5); 
0075 }
0076 
0077 /**
0078  * Load VIEW or UBF object
0079  * @param p_ub parent UBF into which load the data
0080  * @param fldnm field name in json (UBF field name)
0081  * @param fldid resolved filed id
0082  * @param fldtyp UBF field type
0083  * @param bin_buf temporary working space
0084  * @param bin_buf_len working space length
0085  * @param innerobj data object under the field in JSON
0086  * @param occ occurrence to set in UBF
0087  * @return EXSUCCED/EXFAIL (error loaded if any)
0088  */
0089 exprivate int ndrx_load_object(UBFH *p_ub, char *fldnm, BFLDID fldid, int fldtyp, 
0090         char *bin_buf, size_t bin_buf_len, EXJSON_Object *innerobj, BFLDOCC occ)
0091 {
0092     
0093     int ret = EXSUCCEED;
0094     
0095     if (BFLD_UBF==fldtyp)
0096     {
0097         UBFH *p_ub_tmp = (UBFH *)bin_buf;
0098 
0099         if (EXFAIL==Binit(p_ub_tmp, bin_buf_len))
0100         {
0101             ndrx_TPset_error_fmt(TPESYSTEM, 
0102                     "Failed to init temporary UBF for [%s]: %s", 
0103                     fldnm, Bstrerror(Berror));
0104             NDRX_LOG(log_error, "Failed to init temporary UBF for [%s]: %s", 
0105                     fldnm, Bstrerror(Berror));
0106             EXFAIL_OUT(ret);
0107         }
0108 
0109         if (EXSUCCEED!=ndrx_tpjsontoubf(p_ub_tmp, NULL, innerobj))
0110         {
0111             NDRX_LOG(log_error, "Failed to parse UBF json at field [%s]", 
0112                     fldnm);
0113             EXFAIL_OUT(ret);
0114         }
0115 
0116         /* Add UBF to buffer */
0117         if (EXSUCCEED!=Bchg(p_ub, fldid, occ, (char *)p_ub_tmp, 0L))
0118         {
0119             ndrx_TPset_error_fmt(TPESYSTEM, 
0120                     "Failed to add to parent UBF inner UBF [%s] (fldid=%d): %s", 
0121                     fldnm, fldid, Bstrerror(Berror));
0122             NDRX_LOG(log_error, "Failed to add to parent UBF inner UBF [%s] (fldid=%d): %s", 
0123                     fldnm, fldid, Bstrerror(Berror));
0124             EXFAIL_OUT(ret);
0125         }
0126 
0127         NDRX_LOG(log_debug, "Added sub-ubf [%s] fldid=%d to UBF buffer %p",
0128                 fldnm, fldid, p_ub);
0129 
0130     }
0131     else if (BFLD_PTR==fldtyp)
0132     {
0133         char *allocptr = NULL;
0134         long len;
0135         
0136         if (EXSUCCEED!=ndrx_tpimportex(NULL, NULL, 0, &allocptr, &len, 0, innerobj))
0137         {
0138             NDRX_LOG(log_error, "Failed to parse PTR object");
0139             EXFAIL_OUT(ret);
0140         }
0141         
0142         NDRX_LOG(log_debug, "Got PTR field: %p", allocptr);
0143         
0144         if (EXSUCCEED!=Bchg(p_ub, fldid, occ, (char *)&allocptr, 0L))
0145         {
0146             ndrx_TPset_error_fmt(TPESYSTEM, 
0147                     "Failed to add to parent UBF inner PTR field [%p] [%s] (fldid=%d): %s", 
0148                     fldnm, allocptr, fldid, Bstrerror(Berror));
0149             NDRX_LOG(log_error, 
0150                     "Failed to add to parent UBF inner PTR field [%p] [%s] (fldid=%d): %s", 
0151                     fldnm, allocptr, fldid, Bstrerror(Berror));
0152             EXFAIL_OUT(ret);
0153         }
0154     }
0155     else if (BFLD_VIEW==fldtyp)
0156     {
0157         BVIEWFLD vdata;
0158         int null_view=EXFALSE;
0159         vdata.vflags=0;
0160         
0161         if (NULL==(vdata.data=ndrx_tpjsontoview(vdata.vname, NULL, innerobj, 
0162                 &null_view)) && !null_view)
0163         {
0164             NDRX_LOG(log_error, "Failed to parse UBF json at field [%s]", 
0165                     fldnm);
0166             EXFAIL_OUT(ret);
0167         }
0168 
0169         /* Add UBF to buffer */
0170         if (EXSUCCEED!=Bchg(p_ub, fldid, occ, (char *)&vdata, 0L))
0171         {
0172             ndrx_TPset_error_fmt(TPESYSTEM, 
0173                     "Failed to add to parent UBF inner VIEW[%s] [%s] (fldid=%d): %s", 
0174                     vdata.vname, fldnm, fldid, Bstrerror(Berror));
0175             NDRX_LOG(log_error, "Failed to add to parent UBF inner VIEW[%s] [%s] (fldid=%d): %s", 
0176                     vdata.vname, fldnm, fldid, Bstrerror(Berror));
0177 
0178             NDRX_FREE(vdata.data);
0179             EXFAIL_OUT(ret);
0180         }
0181 
0182         /* avoid object leak! */
0183         tpfree(vdata.data);
0184 
0185         NDRX_LOG(log_debug, "Added sub-view[%s] [%s] fldid=%d to UBF buffer %p",
0186                 vdata.vname, fldnm, fldid, p_ub);
0187     }
0188     else
0189     {
0190         ndrx_TPset_error_fmt(TPEINVAL, "Field [%s] type is %s but object received",
0191                 fldnm, (Btype(fldtyp)?Btype(fldtyp):"(null)"));
0192         NDRX_LOG(log_error, "Field [%s] type is %s but object received",
0193                 fldnm, (Btype(fldtyp)?Btype(fldtyp):"(null)"));
0194         EXFAIL_OUT(ret);
0195     }
0196     
0197 out:
0198     return ret;
0199 }
0200 
0201 /**
0202  * Common parser for string data, allows to use escape sequences if API is
0203  * configured so
0204  * @param p_ub parent UBF into which load the data
0205  * @param fldnm field name in json (UBF field name)
0206  * @param fldid resolved filed id
0207  * @param fldtyp UBF field type
0208  * @param bin_buf temporary working space
0209  * @param bin_buf_len working space length
0210  * @param str_val string data
0211  * @param occ occurrence to set in UBF
0212  * @return EXSUCCEED/EXFAIL
0213  */
0214 exprivate int ndrx_load_string(UBFH *p_ub, char *fldnm, BFLDID fldid, int fldtyp, 
0215         char *bin_buf, size_t bin_buf_len, char* str_val, BFLDOCC occ)
0216 {
0217     int ret = EXSUCCEED;
0218     char    *s_ptr;
0219     BFLDLEN     str_len;
0220     
0221     /* If it is carray - parse hex... */
0222     if (IS_BIN(fldtyp))
0223     {
0224         size_t st_len = bin_buf_len;
0225         NDRX_LOG(log_debug, "Field is binary..."
0226                 " convert from b64...");
0227 
0228         if (NULL==ndrx_base64_decode(str_val,
0229                 strlen(str_val),
0230                 &st_len,
0231                 bin_buf))
0232         {
0233             NDRX_LOG(log_debug, "Failed to "
0234                     "decode base64!");
0235 
0236             ndrx_TPset_error_fmt(TPEINVAL, "Failed to "
0237                     "decode base64: %s", fldnm);
0238 
0239             EXFAIL_OUT(ret);
0240         }
0241         str_len = st_len;
0242         s_ptr = bin_buf;
0243         NDRX_LOG(log_debug, "got binary len [%d]", str_len);
0244     }
0245     else if (ndrx_G_apiflags & NDRX_APIFLAGS_JSONESCAPE)
0246     {
0247         /* convert string from C escape... */
0248         if (EXSUCCEED!=ndrx_normalize_string(str_val, &str_len))
0249         {
0250             NDRX_LOG(log_error, "Invalid C escape used in field [%s] data: [%s]",
0251                     fldnm, str_val);
0252             EXFAIL_OUT(ret);
0253         }
0254         s_ptr = str_val;
0255     }
0256     else
0257     {
0258         s_ptr = str_val;
0259         str_len = strlen(str_val);
0260     }
0261 
0262     if (EXSUCCEED!=CBchg(p_ub, fldid, occ, s_ptr, str_len, BFLD_CARRAY))
0263     {
0264         NDRX_LOG(log_error, "Failed to set UBF field (%s) %d: %s",
0265                 fldnm, fldid, Bstrerror(Berror));
0266         ndrx_TPset_error_fmt(TPESYSTEM, "Failed to set UBF field (%s) %d: %s",
0267                 fldnm, fldid, Bstrerror(Berror));
0268         EXFAIL_OUT(ret);
0269     }
0270     
0271 out:
0272     return ret;
0273 }
0274 
0275 /**
0276  * Convert JSON text buffer to UBF
0277  * TODO: Add support for embedded ubf/view
0278  * TODO: Reset the UBF buffer at the start, so that we do not conflict
0279  * with existing fields
0280  * @param p_ub - UBF buffer to fill data in
0281  * @param buffer - json text to parse
0282  * @data_object - already parsed json in object
0283  * @return SUCCEED/FAIL
0284  */
0285 expublic int ndrx_tpjsontoubf(UBFH *p_ub, char *buffer, EXJSON_Object *data_object)
0286 {
0287     int ret = EXSUCCEED;
0288     EXJSON_Value *root_value=NULL;
0289     EXJSON_Object *root_object=data_object;
0290     EXJSON_Object *innerobj;
0291     EXJSON_Array *array;
0292     size_t i, cnt, j, arr_cnt;
0293     int type;
0294     char *name;
0295     char    *str_val;
0296     BFLDID  fid;
0297     double d_val;
0298     int f_type;
0299     short   bool_val;
0300     char    *bin_buf=NULL;
0301     size_t bin_buf_len;
0302     char    *s_ptr;
0303     int fldtyp;
0304 
0305     /* allocate dynamically... */
0306     bin_buf_len=CARR_BUFFSIZE+1;
0307     NDRX_MALLOC_OUT(bin_buf, bin_buf_len, char);
0308 
0309     if ( NULL != buffer )
0310     {
0311         NDRX_LOG(log_debug, "Parsing buffer: [%s]", buffer);
0312 
0313         root_value = exjson_parse_string_with_comments(buffer);
0314         type = exjson_value_get_type(root_value);
0315         NDRX_LOG(log_debug, "Type is %d", type);
0316 
0317         if (exjson_value_get_type(root_value) != EXJSONObject)
0318         {
0319             NDRX_LOG(log_error, "Failed to parse root element");
0320             ndrx_TPset_error_fmt(TPEINVAL, "exjson: Failed to parse root element");
0321             EXFAIL_OUT(ret);
0322         }
0323         root_object = exjson_value_get_object(root_value);
0324     }
0325     else
0326     {
0327         NDRX_LOG(log_debug, "Parsing from data_object");
0328     }
0329 
0330     cnt = exjson_object_get_count(root_object);
0331     NDRX_LOG(log_debug, "cnt = %d", cnt);
0332 
0333     for (i =0; i< cnt; i++)
0334     {
0335         name = (char *)exjson_object_get_name(root_object, i);
0336 
0337         NDRX_LOG(log_debug, "Name: [%s]", name);
0338         fid = Bfldid(name);
0339 
0340         if (BBADFLDID==fid)
0341         {
0342             NDRX_LOG(log_warn, "Name: [%s] - not known in UBFTAB - ignore", name);
0343             continue;
0344         }
0345         
0346         fldtyp=Bfldtype(fid);
0347 
0348         switch ((f_type=exjson_value_get_type(exjson_object_get_value_at(root_object, i))))
0349         {
0350             case EXJSONString:
0351             {
0352                 str_val = (char *)exjson_object_get_string(root_object, name);
0353                 NDRX_LOG(log_debug, "Str Value: [%s]", str_val);
0354                 
0355                 if (EXSUCCEED!=ndrx_load_string(p_ub, name, fid, fldtyp, 
0356                         bin_buf, bin_buf_len, str_val, 0))
0357                 {
0358                     NDRX_LOG(log_error, "Failed to set array string value for [%s]", 
0359                             name);
0360                     EXFAIL_OUT(ret);
0361                 }
0362                 break;
0363             }
0364             case EXJSONNumber:
0365             {
0366                 if (IS_INT(fldtyp))
0367                 {
0368                     long l = exjson_object_get_intnumber(root_object, name);
0369                     NDRX_LOG(log_debug, "Long value: [%ld]", l);
0370 
0371                     if (EXSUCCEED!=CBchg(p_ub, fid, 0, 
0372                             (char *)&l, 0L, BFLD_LONG))
0373                     {
0374                         NDRX_LOG(log_error, "Failed to set [%s] to [%ld]!", 
0375                             name, l);
0376                         
0377                         ndrx_TPset_error_fmt(TPESYSTEM, "Failed to set [%s] to [%ld]!", 
0378                             name, l);
0379                         
0380                         EXFAIL_OUT(ret);
0381                     }
0382                 }
0383                 else 
0384                 {
0385 
0386                     d_val = exjson_object_get_number(root_object, name);
0387                     NDRX_LOG(log_debug, "Double value: [%lf]", d_val);
0388 
0389                     if (EXSUCCEED!=CBchg(p_ub, fid, 0, (char *)&d_val, 0L, BFLD_DOUBLE))
0390                     {
0391                         NDRX_LOG(log_error, "Failed to set [%s] to [%lf]: %s", 
0392                                 name, d_val, Bstrerror(Berror));
0393                         
0394                         ndrx_TPset_error_fmt(TPESYSTEM, "Failed to set [%s] to [%lf]: %s", 
0395                                 name, d_val, Bstrerror(Berror));
0396                         
0397                         EXFAIL_OUT(ret);
0398                     }
0399                 }
0400             }
0401                     break;
0402             case EXJSONBoolean:
0403             {
0404                 bool_val = (short)exjson_object_get_boolean(root_object, name);
0405                 NDRX_LOG(log_debug, "Bool Value: [%hd]", bool_val);
0406                 if (EXSUCCEED!=CBchg(p_ub, fid, 0, (char *)&bool_val, 0L, BFLD_SHORT))
0407                 {
0408                     NDRX_LOG(log_error, "Failed to set [%s] to [%hd]: %s", 
0409                             name, bool_val, Bstrerror(Berror));
0410                     
0411                     ndrx_TPset_error_fmt(TPESYSTEM, "Failed to set [%s] to [%hd]: %s", 
0412                             name, bool_val, Bstrerror(Berror));
0413                     
0414                     EXFAIL_OUT(ret);
0415                 }
0416             }
0417             break;
0418             
0419             /* parse embedded object */
0420             case EXJSONObject:
0421                 
0422                 innerobj = exjson_object_get_object(root_object, name);
0423 
0424                 if (NULL==innerobj)
0425                 {
0426                     ndrx_TPset_error_fmt(TPEINVAL, 
0427                             "Null object received for field [%s]", name);
0428                     NDRX_LOG(log_error, "Null object received for field [%s]", 
0429                             name);
0430                     EXFAIL_OUT(ret);
0431                 }
0432 
0433                 if (EXSUCCEED!=ndrx_load_object(p_ub, name, fid, fldtyp, 
0434                         bin_buf, bin_buf_len, innerobj, 0))
0435                 {
0436                     NDRX_LOG(log_error, "Failed to parse inner object of [%s]", 
0437                             name);
0438                     EXFAIL_OUT(ret);
0439                 }
0440                 
0441                 break;
0442                 
0443             /* Fielded buffer fields with more than one occurrance will go to array: 
0444              * Stuff here is almost identicial to above!
0445              */
0446             case EXJSONArray:
0447             {
0448                 if (NULL==(array = exjson_object_get_array(root_object, name)))
0449                 {
0450                     NDRX_LOG(log_error, "Failed to get array object!");
0451                     ndrx_TPset_error_fmt(TPESYSTEM, "Failed to get array object!");
0452                     EXFAIL_OUT(ret);
0453                 }
0454                 arr_cnt = exjson_array_get_count(array);
0455 
0456                 for (j = 0; j<arr_cnt; j++ )
0457                 {
0458                     switch (f_type = exjson_value_get_type(
0459                             exjson_array_get_value(array, j)))
0460                     {
0461                         case EXJSONString:
0462                         {
0463                             str_val = (char *)exjson_array_get_string(array, j);
0464                             NDRX_LOG(log_debug, 
0465                                         "Array j=%d, Str Value: [%s]", j, str_val);
0466                             
0467                             if (EXSUCCEED!=ndrx_load_string(p_ub, name, fid, fldtyp, 
0468                                     bin_buf, bin_buf_len, str_val, j))
0469                             {
0470                                 NDRX_LOG(log_error, "Failed to set array string value for [%s]", 
0471                                         name);
0472                                 EXFAIL_OUT(ret);
0473                             }
0474                         }
0475                         break;
0476                         case EXJSONNumber:
0477                         {
0478                             long l;
0479 
0480                             if (IS_INT(fldtyp))
0481                             {
0482                                 l = exjson_array_get_intnumber(array, j);
0483                                 NDRX_LOG(log_debug, "Array j=%d, Integer Value: [%ld]", j, l);
0484                                 if (EXSUCCEED!=CBchg(p_ub, fid, j, 
0485                                         (char *)&l, 0L, BFLD_LONG))
0486                                 {
0487                                         NDRX_LOG(log_error, "Failed to set [%s] to [%ld]: %s", 
0488                                                 name, l, Bstrerror(Berror));
0489                                         
0490                                         ndrx_TPset_error_fmt(TPESYSTEM, 
0491                                                 "Failed to set [%s] to [%ld]: %s", 
0492                                                 name, l, Bstrerror(Berror));
0493                                         
0494                                         EXFAIL_OUT(ret);
0495                                 }
0496                             }
0497                             else 
0498                             {
0499 
0500                                 d_val = exjson_array_get_number(array, j);
0501                                 NDRX_LOG(log_debug, "Array j=%d, Double Value: [%lf]", j, d_val);
0502 
0503                                 if (EXSUCCEED!=CBchg(p_ub, fid, j, 
0504                                     (char *)&d_val, 0L, BFLD_DOUBLE))
0505                                 {
0506                                     NDRX_LOG(log_error, "Failed to set [%s] to [%lf]: %s", 
0507                                             name, d_val, Bstrerror(Berror));
0508                                     
0509                                     ndrx_TPset_error_fmt(TPESYSTEM,"Failed to set "
0510                                             "[%s] to [%lf]: %s", 
0511                                             name, d_val, Bstrerror(Berror));
0512                                     
0513                                     EXFAIL_OUT(ret);
0514                                 }
0515                             }
0516                         }
0517                         break;
0518                         case EXJSONBoolean:
0519                         {
0520                             bool_val = (short)exjson_array_get_boolean(array, j);
0521                             NDRX_LOG(log_debug, "Array j=%d, Bool Value: [%hd]", j, bool_val);
0522                             if (EXSUCCEED!=CBchg(p_ub, fid, j, (char *)&bool_val, 0L, BFLD_SHORT))
0523                             {
0524                                 NDRX_LOG(log_error, "Failed to set [%s] to [%hd]: %s", 
0525                                         name, bool_val, Bstrerror(Berror));
0526                                 
0527                                 ndrx_TPset_error_fmt(TPESYSTEM,"Failed to set "
0528                                         "[%s] to [%hd]: %s", 
0529                                         name, bool_val, Bstrerror(Berror));
0530                                 
0531                                 EXFAIL_OUT(ret);
0532                             }
0533                         }
0534                         
0535                         case EXJSONObject:
0536                             
0537                             innerobj = exjson_array_get_object(array, j);
0538 
0539                             if (NULL==innerobj)
0540                             {
0541                                 ndrx_TPset_error_fmt(TPEINVAL, 
0542                                         "Null object received for array field [%s]", name);
0543                                 NDRX_LOG(log_error, "Null object received for array field [%s]", 
0544                                         name);
0545                                 EXFAIL_OUT(ret);
0546                             }
0547 
0548                             if (EXSUCCEED!=ndrx_load_object(p_ub, name, fid, fldtyp, 
0549                                     bin_buf, bin_buf_len, innerobj, j))
0550                             {
0551                                 NDRX_LOG(log_error, "Failed to parse inner array object of [%s]", 
0552                                         name);
0553                                 EXFAIL_OUT(ret);
0554                             }
0555                              
0556                         break;
0557                         default:
0558                             NDRX_LOG(log_error, 
0559                                         "Unsupported array elem "
0560                                         "type: %d", f_type);                            
0561                         break;
0562                     }
0563                 }
0564             }
0565             break;
0566             default:
0567             {
0568                 NDRX_LOG(log_error, "Unsupported type: %d", f_type);
0569             }
0570             break;
0571 
0572         }
0573     }
0574     
0575 out:
0576     /* cleanup code */
0577     if (NULL != root_value)
0578     {
0579         exjson_value_free(root_value);
0580     }
0581 
0582     if (NULL!=bin_buf)
0583     {
0584         NDRX_FREE(bin_buf);
0585     }
0586 
0587     return ret;
0588 }
0589 
0590 /**
0591  * Build json text from UBF buffer
0592  * @param p_ub  JSON buffer
0593  * @param buffer output json buffer
0594  * @param bufsize       output buffer size
0595  * @return SUCCEED/FAIL 
0596  */
0597 expublic int ndrx_tpubftojson(UBFH *p_ub, char *buffer, int bufsize, EXJSON_Object *data_object)
0598 {
0599     int ret = EXSUCCEED;
0600     BFLDID fldid;
0601     int occs;
0602     int is_array;
0603     double d_val;
0604     long l_val;
0605     size_t strval_len = CARR_BUFFSIZE+1;
0606     char *strval=NULL; 
0607     size_t b64_buf_len =CARR_BUFFSIZE_B64+1;
0608     char *b64_buf=NULL;
0609     int is_num, is_int;
0610     char *s_ptr;
0611     char *d_ptr;
0612     BFLDLEN flen;
0613     /* use if there is no root */
0614     EXJSON_Value *root_value=NULL;
0615     EXJSON_Object *root_object=NULL;
0616     char *serialized_string = NULL;
0617     BFLDOCC oc;
0618     BFLDLEN fldlen;
0619     int fldtyp;
0620     EXJSON_Value *emb_value = NULL;
0621     EXJSON_Object *emb_object = NULL;
0622     Bnext_state_t state;
0623     char *nm;
0624     EXJSON_Array *jarr=NULL;
0625     
0626     NDRX_MALLOC_OUT(strval, strval_len, char);
0627     NDRX_MALLOC_OUT(b64_buf, b64_buf_len, char);
0628     
0629     if ( NULL == data_object )
0630     {
0631         root_value = exjson_value_init_object();
0632         
0633         if (NULL==root_value)
0634         {
0635             ndrx_TPset_error_fmt(TPESYSTEM, "Failed to init json object value - mem issue?");
0636             EXFAIL_OUT(ret);
0637         }
0638         
0639         root_object = exjson_value_get_object(root_value);
0640     }
0641     else
0642     {
0643         root_object = data_object;
0644     }
0645     
0646     memset(&state, 0, sizeof(state));
0647     
0648     for (fldid = BFIRSTFLDID, oc = 0;
0649             1 == (ret = ndrx_Bnext(&state, p_ub, &fldid, &oc, NULL, &fldlen, &d_ptr));)
0650     {
0651         /* Feature #232 return ID if field not found in tables... */
0652         nm = ndrx_Bfname_int(fldid);
0653         NDRX_LOG(log_debug, "Field: [%s] occ %d id: %d", nm, oc, fldid);
0654         if (0==oc)
0655         {
0656             occs = Boccur(p_ub, fldid);
0657             if (occs>1)
0658             {
0659                 /* create array */
0660                 is_array = EXTRUE;
0661                 /* add array to document... */
0662                 if (EXJSONSuccess!=exjson_object_set_value(root_object, 
0663                         nm, exjson_value_init_array()))
0664                 {
0665                     NDRX_LOG(log_error, "Failed to add Array to root object!!");
0666 
0667                     ndrx_TPset_error_msg(TPESYSTEM, "Failed to add Array "
0668                             "to root object!!");
0669                     EXFAIL_OUT(ret);
0670                 }
0671                 if (NULL == (jarr=exjson_object_get_array(root_object, nm)))
0672                 {
0673                     NDRX_LOG(log_error, "Failed to initialize array!!");
0674 
0675                     ndrx_TPset_error_msg(TPESYSTEM, "Failed to initialize array");
0676                     EXFAIL_OUT(ret);
0677                 }
0678             }
0679             else
0680             {
0681                 is_array = EXFALSE;
0682             }
0683         }
0684         else
0685         {
0686             is_array = EXTRUE;
0687         }
0688         
0689         fldtyp=Bfldtype(fldid);
0690 
0691         is_num=EXFALSE;
0692         is_int=EXFALSE;
0693         if (IS_INT(fldtyp))
0694         {
0695             if (EXSUCCEED!=CBget(p_ub, fldid, oc, (char *)&l_val, 0L, BFLD_LONG))
0696             {
0697                 NDRX_LOG(log_error, "Failed to get (long): %ld/%d: %s",
0698                                                 fldid, oc, Bstrerror(Berror));
0699                 
0700                 ndrx_TPset_error_fmt(TPESYSTEM, "Failed to get (long): %ld/%d: %s",
0701                                                 fldid, oc, Bstrerror(Berror));
0702                 EXFAIL_OUT(ret);
0703             }
0704             is_int = EXTRUE;
0705             NDRX_LOG(log_debug, "Numeric value: %ld", l_val);
0706         }
0707         else if (IS_NUM(fldtyp))
0708         {
0709             if (EXSUCCEED!=CBget(p_ub, fldid, oc, (char *)&d_val, 0L, BFLD_DOUBLE))
0710             {
0711                 NDRX_LOG(log_error, "Failed to get (double): %ld/%d: %s",
0712                                                 fldid, oc, Bstrerror(Berror));
0713                 
0714                 ndrx_TPset_error_fmt(TPESYSTEM, "Failed to get (double): %ld/%d: %s",
0715                                                 fldid, oc, Bstrerror(Berror));
0716                 EXFAIL_OUT(ret);
0717             }
0718             is_num = EXTRUE;
0719             NDRX_LOG(log_debug, "Numeric value: %lf", d_val);
0720         }
0721         else if (BFLD_UBF==fldtyp || BFLD_VIEW==fldtyp || BFLD_PTR==fldtyp)
0722         {
0723             if (NULL==(emb_value = exjson_value_init_object()))
0724             {
0725                 NDRX_LOG(log_error, "Failed to init data_value");
0726                 ndrx_TPset_error_fmt(TPESYSTEM, "exparson: failed to init data_value");
0727                 
0728                 EXFAIL_OUT(ret);
0729             }
0730 
0731             if (NULL==(emb_object = exjson_value_get_object(emb_value)))
0732             {
0733                 NDRX_LOG(log_error, "Failed to get object value");
0734                 ndrx_TPset_error_fmt(TPESYSTEM, "exparson: Failed to get object");
0735                 EXFAIL_OUT(ret);
0736             }
0737             
0738              /* process embedded buffer */
0739             if (BFLD_UBF==fldtyp)
0740             {
0741                 if (EXSUCCEED!=ndrx_tpubftojson((UBFH *)d_ptr, NULL, 0, emb_object))
0742                 {
0743                     NDRX_LOG(log_error, "Failed to build embedded data object from UBF!");
0744                     EXFAIL_OUT(ret);
0745                 }
0746             }
0747             else if (BFLD_PTR==fldtyp)
0748             {
0749                 /* export whole buffer... run as new tpexport */
0750                 
0751                 ndrx_longptr_t *ptr =(ndrx_longptr_t *)d_ptr;
0752                 NDRX_LOG(log_debug, "About to export ptr: [%p]", (char *)*ptr);
0753                 
0754                 if (EXSUCCEED!=ndrx_tpexportex(NULL, 
0755                         (char *)*ptr, 0, NULL, NULL, 0, emb_object))
0756                 {
0757                     NDRX_LOG(log_error, "Failed to export PTR (%p)!", *ptr);
0758                     EXFAIL_OUT(ret);
0759                 }
0760                 
0761                 NDRX_LOG(log_debug, "Export ptr returns: [%p]", (char *)*ptr);
0762                 /* set value? */
0763             }
0764             else
0765             {
0766                 /* if this is a view... needs to get view struct data... */
0767                 ndrx_ubf_tls_bufval_t *vf = (ndrx_ubf_tls_bufval_t *)d_ptr;
0768                 
0769                 if (EXSUCCEED!=ndrx_tpviewtojson(vf->vdata.data, 
0770                         vf->vdata.vname, NULL, 0, BVACCESS_NOTNULL, emb_object))
0771                 {
0772                     NDRX_LOG(log_error, "Failed to build embedded data object from VIEW!");
0773                     EXFAIL_OUT(ret);
0774                 }
0775             }
0776         }
0777         else
0778         {
0779             flen = strval_len;
0780             if (EXSUCCEED!=CBget(p_ub, fldid, oc, strval, &flen, BFLD_CARRAY))
0781             {
0782                 NDRX_LOG(log_error, "Failed to get (string): %ld/%d: %s",
0783                                         fldid, oc, Bstrerror(Berror));
0784                 
0785                 ndrx_TPset_error_fmt(TPESYSTEM, "Failed to get (string): %ld/%d: %s",
0786                                         fldid, oc, Bstrerror(Berror));
0787                 
0788                 EXFAIL_OUT(ret);
0789             }
0790 
0791             /* If it is carray, then convert to hex... */
0792             if (IS_BIN(fldtyp))
0793             {
0794                 size_t outlen = b64_buf_len;
0795                 NDRX_LOG(log_debug, "Field is binary... convert to b64");
0796 
0797                 if (NULL==ndrx_base64_encode((unsigned char *)strval, flen, 
0798                             &outlen, b64_buf))
0799                 {
0800                     NDRX_LOG(log_error, "Failed to convert to b64!");
0801                     
0802                     ndrx_TPset_error_fmt(TPESYSTEM, "Failed to convert to b64!");
0803                     
0804                     EXFAIL_OUT(ret);
0805                 }
0806                 /* b64_buf[outlen] = EXEOS; */
0807                 s_ptr = b64_buf;
0808 
0809             }
0810             else if (ndrx_G_apiflags & NDRX_APIFLAGS_JSONESCAPE)
0811             {
0812                 int tmp_len = ndrx_get_nonprintable_char_tmpspace(strval, flen);
0813                 
0814                 if (tmp_len+1 > b64_buf_len)
0815                 {
0816                     NDRX_LOG(log_error, "Field [%s] value too long for json "
0817                             "escape temporary buffer: required %d have: %z - "
0818                             "increase NDRX_MSGSIZEMAX",
0819                             nm, tmp_len+1, b64_buf_len);
0820                     
0821                     ndrx_TPset_error_fmt(TPEINVAL, "Field [%s] value too long for json "
0822                             "escape temporary buffer: required %d have: %z - "
0823                             "increase NDRX_MSGSIZEMAX",
0824                             nm, tmp_len+1, b64_buf_len);
0825                     
0826                     EXFAIL_OUT(ret);
0827                 }
0828                 
0829                 ndrx_build_printable_string(b64_buf, b64_buf_len, strval, flen);
0830                 s_ptr = b64_buf;
0831             }
0832             else
0833             {
0834                 strval[flen] = EXEOS;
0835                 s_ptr = strval;
0836             }
0837 
0838             NDRX_LOG(log_debug, "String value: [%s]", s_ptr);
0839         }
0840 
0841         if (is_array)
0842         {
0843             /* Add array element 
0844             exjson_object_set_value */
0845 
0846             /* Add normal element */
0847             if (is_int)
0848             {
0849                 if (EXJSONSuccess!=exjson_array_append_intnumber(jarr, l_val))
0850                 {
0851                     NDRX_LOG(log_error, "Failed to set array elem to [%ld]!", 
0852                             l_val);
0853 
0854                     ndrx_TPset_error_fmt(TPESYSTEM, "exjson: Failed to set array "
0855                             "elem to [%ld]!", l_val);
0856 
0857                     EXFAIL_OUT(ret);
0858                 }
0859             }
0860             else if (is_num)
0861             {
0862                 if (EXJSONSuccess!=exjson_array_append_number(jarr, d_val))
0863                 {
0864                     NDRX_LOG(log_error, "Failed to set array elem to [%lf]!",
0865                             d_val);
0866 
0867                     ndrx_TPset_error_fmt(TPESYSTEM, "exjson: Failed to set array "
0868                             "elem to [%lf]!", d_val);
0869 
0870                     EXFAIL_OUT(ret);
0871                 }
0872             }
0873             else if (BFLD_UBF==fldtyp || BFLD_VIEW==fldtyp || BFLD_PTR==fldtyp)
0874             {
0875                 /* append  */
0876                 if (EXJSONSuccess!=exjson_array_append_value(jarr, emb_value))
0877                 {
0878                     NDRX_LOG(log_error, "exjson: Failed to set array "
0879                             "elem [%s] to embedded object (view/ubf) occ: %d fldid: %d!", 
0880                             nm, oc, fldid);
0881                     
0882                     ndrx_TPset_error_fmt(TPESYSTEM, "exjson: Failed to set array "
0883                             "elem [%s] to embedded object (view/ubf) occ: %d fldid: %d!", 
0884                             nm, oc, fldid);
0885                     EXFAIL_OUT(ret);
0886                 }
0887                 
0888                 /* set to not to free up... */
0889                 emb_value=NULL;
0890             }
0891             else
0892             {
0893                 if (EXJSONSuccess!=exjson_array_append_string(jarr, s_ptr))
0894                 {
0895                     NDRX_LOG(log_error, "Failed to set array elem to [%s]!", 
0896                             s_ptr);
0897 
0898                     ndrx_TPset_error_fmt(TPESYSTEM, "exjson: Failed to set array "
0899                             "elem to [%s]!", s_ptr);
0900 
0901                     EXFAIL_OUT(ret);
0902                 }
0903             }
0904         }
0905         else
0906         {
0907             /* Add normal element */
0908             if (is_int)
0909             {
0910                 if (EXJSONSuccess!=exjson_object_set_intnumber(root_object, nm, l_val))
0911                 {
0912                     NDRX_LOG(log_error, "Failed to set [%s] value to [%ld]!",
0913                                         nm, l_val);
0914                     
0915                     ndrx_TPset_error_fmt(TPESYSTEM, "exjson: Failed to set [%s] "
0916                             "value to [%ld]!", nm, l_val);
0917                     
0918                     EXFAIL_OUT(ret);
0919                 }
0920             }
0921             else if (is_num)
0922             {
0923                 if (EXJSONSuccess!=exjson_object_set_number(root_object, nm, d_val))
0924                 {
0925                     NDRX_LOG(log_error, "Failed to set [%s] value to [%lf]!",
0926                                         nm, d_val);
0927                     
0928                     ndrx_TPset_error_fmt(TPESYSTEM, "exjson: Failed to set [%s] "
0929                             "value to [%lf]!", nm, d_val);
0930                     
0931                     EXFAIL_OUT(ret);
0932                 }
0933             }
0934             else if (BFLD_UBF==fldtyp || BFLD_VIEW==fldtyp || BFLD_PTR==fldtyp)
0935             {
0936                 if (EXJSONSuccess!=exjson_object_set_value(root_object, nm, emb_value))
0937                 {
0938                     NDRX_LOG(log_error, "Failed to add embedded VIEW/UBF [%s]", nm);
0939                     EXFAIL_OUT(ret);
0940                 }
0941                 /* set to not to free up... */
0942                 emb_value=NULL;
0943             }
0944             else
0945             {
0946                 if (EXJSONSuccess!=exjson_object_set_string(root_object, nm, s_ptr))
0947                 {
0948                     NDRX_LOG(log_error, "Failed to set [%s] value to [%s]!",
0949                                     nm, s_ptr);
0950                     
0951                     ndrx_TPset_error_fmt(TPESYSTEM, "exjson: Failed to set [%s] "
0952                             "value to [%s]!", nm, s_ptr);
0953                     
0954                     EXFAIL_OUT(ret);
0955                 }
0956             }
0957         }
0958     }
0959 
0960     if (NULL != buffer)
0961     {
0962         serialized_string = exjson_serialize_to_string(root_value);
0963 
0964         if (strlen(serialized_string) < bufsize ) /* needs space for EOS */
0965         {
0966             NDRX_STRCPY_SAFE_DST(buffer, serialized_string, bufsize);
0967 
0968             NDRX_LOG(log_debug, "Got JSON: [%s]", buffer);
0969         }
0970         else
0971         {
0972             NDRX_LOG(log_error, "Buffer too short: Got json size: [%d] buffer size: [%d]", 
0973                     strlen(serialized_string)+1, bufsize);
0974 
0975             ndrx_TPset_error_fmt(TPEOS, "Buffer too short: Got json size: "
0976                     "[%d] buffer size: [%d]",  strlen(serialized_string)+1, bufsize);
0977 
0978             EXFAIL_OUT(ret);
0979         }
0980     }
0981 
0982 out:
0983 
0984     if (NULL!=serialized_string)
0985     {
0986         exjson_free_serialized_string(serialized_string);
0987     }
0988 
0989     if (NULL!=emb_value)
0990     {
0991         exjson_value_free(emb_value);
0992     }
0993 
0994     /* kill the root value if any... */
0995     if (NULL==data_object && NULL!=root_value)
0996     {
0997         exjson_value_free(root_value);
0998     }
0999 
1000     if (NULL!=strval)
1001     {
1002         NDRX_FREE(strval);
1003     }
1004     
1005     
1006     if (NULL!=b64_buf)
1007     {
1008         NDRX_FREE(b64_buf);
1009     }
1010     
1011     return ret;
1012 }
1013 
1014 /**
1015  * auto-buffer convert func. json->ubf
1016  * @param buffer
1017  * @return 
1018  */
1019 expublic int typed_xcvt_json2ubf(buffer_obj_t **buffer)
1020 {
1021     int ret = EXSUCCEED;
1022     buffer_obj_t *tmp_b;
1023     /* Allocate the max UBF buffer */
1024     UBFH * tmp = NULL;
1025     UBFH * newbuf_out = NULL; /* real output buffer */
1026 
1027     if (NULL==(tmp = (UBFH *)tpalloc("UBF", NULL, NDRX_MSGSIZEMAX)))
1028     {
1029         NDRX_LOG(log_error, "failed to convert JSON->UBF. UBF buffer alloc fail!");
1030         EXFAIL_OUT(ret);
1031     }
1032 
1033     /* Do the convert */
1034     ndrx_TPunset_error();
1035     if (EXSUCCEED!=ndrx_tpjsontoubf(tmp, (*buffer)->buf, NULL))
1036     {
1037         tpfree((char *)tmp);
1038         NDRX_LOG(log_error, "Failed to convert JSON->UBF: %s", tpstrerror(tperrno));
1039         EXFAIL_OUT(ret);
1040     }
1041 
1042     /* Shrink the buffer (by reallocating) new! 
1043      * we will do the shrink because, msg Q might not have settings set for
1044      * max buffer size...
1045      */
1046     if (NULL==(newbuf_out = (UBFH *)tpalloc("UBF", NULL, Bused(tmp))))
1047     {
1048         tpfree((char *)tmp);
1049         NDRX_LOG(log_error, "Failed to alloc output UBF %ld !", Bused(tmp));
1050         EXFAIL_OUT(ret);
1051     }
1052 
1053     if (EXSUCCEED!=Bcpy(newbuf_out, tmp))
1054     {
1055         tpfree((char *)tmp);
1056         ndrx_tpfree_inner((char *)newbuf_out, NULL, NULL);
1057 
1058         NDRX_LOG(log_error, "Failed to copy tmp UBF to output: %s !", Bstrerror(Berror));
1059         EXFAIL_OUT(ret);
1060 
1061     }
1062 
1063     tmp_b=ndrx_find_buffer((char *)newbuf_out);
1064     tmp_b->autoalloc = (*buffer)->autoalloc;
1065 
1066     /* Kill the buffers */
1067     tpfree((*buffer)->buf);
1068     /* keep any BFLD_PTRs.. as they are copied.. */
1069     ndrx_tpfree_inner((char *)tmp, NULL, NULL);
1070 
1071     /* finally return the buffer */
1072     NDRX_LOG(log_info, "Returning new buffer %p", tmp_b);
1073     *buffer = tmp_b;
1074 out:
1075     return ret;
1076 }
1077 
1078 
1079 /**
1080  * auto-buffer convert func. ubf->json
1081  * @param buffer
1082  * @return 
1083  */
1084 expublic int typed_xcvt_ubf2json(buffer_obj_t **buffer)
1085 {
1086     int ret = EXSUCCEED;
1087     buffer_obj_t *tmp_b;
1088     
1089     char * tmp = NULL;
1090     char * newbuf_out = NULL; /* real output buffer */
1091 
1092     if (NULL==(tmp = tpalloc("JSON", NULL, NDRX_MSGSIZEMAX)))
1093     {
1094         NDRX_LOG(log_error, "failed to convert UBF->JSON. JSON buffer alloc fail!: %s",
1095                 tpstrerror(tperrno));
1096         EXFAIL_OUT(ret);
1097     }
1098 
1099     /* Do the convert */
1100     ndrx_TPunset_error();
1101     if (EXSUCCEED!=ndrx_tpubftojson((UBFH *)(*buffer)->buf, tmp, NDRX_MSGSIZEMAX, NULL))
1102     {
1103         tpfree((char *)tmp);
1104         NDRX_LOG(log_error, "Failed to convert UBF->JSON: %s", 
1105                 tpstrerror(tperrno));
1106         EXFAIL_OUT(ret);
1107     }
1108 
1109     /* Shrink the buffer (by reallocating) new! 
1110      * we will do the shrink because, msg Q might not have settings set for
1111      * max buffer size...
1112      */
1113     if (NULL==(newbuf_out = tpalloc("JSON", NULL, strlen(tmp)+1)))
1114     {
1115         tpfree((char *)tmp);
1116         NDRX_LOG(log_error, "Failed to alloc output JSON %ld: %s", strlen(tmp)+1, 
1117                 tpstrerror(tperrno));
1118         EXFAIL_OUT(ret);
1119     }
1120 
1121     strcpy(newbuf_out, tmp);
1122 
1123     tmp_b=ndrx_find_buffer((char *)newbuf_out);
1124     tmp_b->autoalloc = (*buffer)->autoalloc;
1125 
1126     /* Kill the buffers */
1127     tpfree((*buffer)->buf);
1128     tpfree((char *)tmp);
1129 
1130     /* finally return the buffer */
1131     NDRX_LOG(log_info, "Returning new buffer %p", tmp_b->buf);
1132     *buffer = tmp_b;
1133 out:
1134     return ret;
1135 }
1136 
1137 /* vim: set ts=4 sw=4 et smartindent: */