コード例 #1
0
static void parseOptionInto(
	const std::string& id, XMLRPC_VALUE option, LLUserAuth::options_t& options)
{
	std::string key;
	std::string val;
	XMLRPC_VALUE_TYPE_EASY type;
	XMLRPC_VALUE row = XMLRPC_VectorRewind(option);
	while(row)
	{
		XMLRPC_VALUE opt  = XMLRPC_VectorRewind(row);
		LLUserAuth::response_t responses;
		while(opt)
		{
			key.assign(XMLRPC_GetValueID(opt));
			//llinfos << "option key: " << key << llendl;
			type = XMLRPC_GetValueTypeEasy(opt);
			if(xmlrpc_type_string == type)
			{
				val.assign(XMLRPC_GetValueString(opt));
				//llinfos << "string val: " << val << llendl;
			}
			else if(xmlrpc_type_int == type)
			{
				val = llformat("%d", XMLRPC_GetValueInt(opt));
				//llinfos << "int val: " << val << llendl;
			}
			else if(xmlrpc_type_double == type)
			{
				val = llformat("%g", XMLRPC_GetValueDouble(opt));
				//llinfos << "double val: " << val << llendl;
			}
			else
			{	// Can't understand the type
				val = "???";
				//llinfos << "unknown value type: " << type << llendl;
			}

			responses.insert(LLUserAuth::response_t::value_type(key, val));
			opt = XMLRPC_VectorNext(row);
		}
		options.push_back(responses);
		row = XMLRPC_VectorNext(option);
	}
}
コード例 #2
0
// this is a c function here since it's really an implementation
// detail that requires a header file just get the definition of the
// parameters.
LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value)
{
	XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value);
	LLIOPipe::EStatus status = LLIOPipe::STATUS_OK;
	switch(type)
	{
	case xmlrpc_type_base64:
	{
		S32 len = XMLRPC_GetValueStringLen(value);
		const char* buf = XMLRPC_GetValueBase64(value);
		ostr << " b(";
		if((len > 0) && buf)
		{
			ostr << len << ")\"";
			ostr.write(buf, len);
			ostr << "\"";
		}
		else
		{
			ostr << "0)\"\"";
		}
		break;
	}
	case xmlrpc_type_boolean:
		//lldebugs << "stream_out() bool" << llendl;
		ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false");
		break;
	case xmlrpc_type_datetime:
		ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\"";
		break;
	case xmlrpc_type_double:
		ostr << " r" << XMLRPC_GetValueDouble(value);
		//lldebugs << "stream_out() double" << XMLRPC_GetValueDouble(value)
		//		 << llendl;
		break;
	case xmlrpc_type_int:
		ostr << " i" << XMLRPC_GetValueInt(value);
		//lldebugs << "stream_out() integer:" << XMLRPC_GetValueInt(value)
		//		 << llendl;
		break;
	case xmlrpc_type_string:
		//lldebugs << "stream_out() string: " << str << llendl;
		ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'"
			<< XMLRPC_GetValueString(value) << "'";
		break;
	case xmlrpc_type_array: // vector
	case xmlrpc_type_mixed: // vector
	{
		//lldebugs << "stream_out() array" << llendl;
		ostr << " [";
		U32 needs_comma = 0;
		XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
		while(current && (LLIOPipe::STATUS_OK == status))
		{
			if(needs_comma++) ostr << ",";
			status = stream_out(ostr, current);
			current = XMLRPC_VectorNext(value);
		}
		ostr << "]";
		break;
	}
	case xmlrpc_type_struct: // still vector
	{
		//lldebugs << "stream_out() struct" << llendl;
		ostr << " {";
		std::string name;
		U32 needs_comma = 0;
		XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
		while(current && (LLIOPipe::STATUS_OK == status))
		{
			if(needs_comma++) ostr << ",";
			name.assign(XMLRPC_GetValueID(current));
			ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':";
			status = stream_out(ostr, current);
			current = XMLRPC_VectorNext(value);
		}
		ostr << "}";
		break;
	}
	case xmlrpc_type_empty:
	case xmlrpc_type_none:
	default:
		status = LLIOPipe::STATUS_ERROR;
		llwarns << "Found an empty xmlrpc type.." << llendl;
		// not much we can do here...
		break;
	};
	return status;
}
コード例 #3
0
ファイル: lluserauth.cpp プロジェクト: nebadon2025/replex
LLSD LLUserAuth::parseValues(UserAuthcode &auth_code, const std::string& key_pfx, XMLRPC_VALUE param)
{
	auth_code = E_OK;
	LLSD responses;
	for(XMLRPC_VALUE current = XMLRPC_VectorRewind(param); current;
		current = XMLRPC_VectorNext(param))
	{
		std::string key(XMLRPC_GetValueID(current));
		lldebugs << "key: " << key_pfx << key << llendl;
		XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(current);
		if(xmlrpc_type_string == type)
		{
			LLSD::String val(XMLRPC_GetValueString(current));
			lldebugs << "val: " << val << llendl;
			responses.insert(key,val);
		}
		else if(xmlrpc_type_int == type)
		{
			LLSD::Integer val(XMLRPC_GetValueInt(current));
			lldebugs << "val: " << val << llendl;
			responses.insert(key,val);
		}
		else if (xmlrpc_type_double == type)
        {
			LLSD::Real val(XMLRPC_GetValueDouble(current));
            lldebugs << "val: " << val << llendl;
			responses.insert(key,val);
		}
		else if(xmlrpc_type_array == type)
		{
			// We expect this to be an array of submaps. Walk the array,
			// recursively parsing each submap and collecting them.
			LLSD array;
			int i = 0;          // for descriptive purposes
			for (XMLRPC_VALUE row = XMLRPC_VectorRewind(current); row;
				row = XMLRPC_VectorNext(current), ++i)
			{
				// Recursive call. For the lower-level key_pfx, if 'key'
				// is "foo", pass "foo[0]:", then "foo[1]:", etc. In the
				// nested call, a subkey "bar" will then be logged as
				// "foo[0]:bar", and so forth.
				// Parse the scalar subkey/value pairs from this array
				// entry into a temp submap. Collect such submaps in 'array'.
				std::string key_prefix = key_pfx;
				array.append(parseValues(auth_code,
									STRINGIZE(key_pfx << key << '[' << i << "]:"),
									row));
			}
			// Having collected an 'array' of 'submap's, insert that whole
			// 'array' as the value of this 'key'.
			responses.insert(key, array);
		}
		else if (xmlrpc_type_struct == type)
    	{
    		LLSD submap = parseValues(auth_code,
            						STRINGIZE(key_pfx << key << ':'),
            						current);
            responses.insert(key, submap);
        }
        else
        {
        	// whoops - unrecognized type
            llwarns << "Unhandled xmlrpc type " << type << " for key "
                                        << key_pfx << key << LL_ENDL;
            responses.insert(key, STRINGIZE("<bad XMLRPC type " << type << '>'));
            auth_code = E_UNHANDLED_ERROR;
        }
    }
    return responses;
}
コード例 #4
0
ファイル: xml_to_xmlrpc.c プロジェクト: AzerTyQsdF/osx
xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VALUE node, 
                                          XMLRPC_REQUEST_TYPE request_type, int depth) {
#define BUF_SIZE 512
   xml_element* root = NULL;
   if (node) {
      char buf[BUF_SIZE];
      XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
      XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(node);
      xml_element* elem_val = xml_elem_new();

      /* special case for when root element is not an array */
      if (depth == 0 && 
          !(type == xmlrpc_vector && 
            vtype == xmlrpc_vector_array && 
            request_type == xmlrpc_request_call) ) {
         int bIsFault = (vtype == xmlrpc_vector_struct && XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE));

         xml_element* next_el = XMLRPC_to_xml_element_worker(NULL, node, request_type, depth + 1);
         if (next_el) {
            Q_PushTail(&elem_val->children, next_el);
         }
         elem_val->name = strdup(bIsFault ? ELEM_FAULT : ELEM_PARAMS);
		}
		else {
         switch (type) {
			case xmlrpc_empty: /*  treat null value as empty string in xmlrpc. */
         case xmlrpc_string:
            elem_val->name = strdup(ELEM_STRING);
            simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
            break;
         case xmlrpc_int:
            elem_val->name = strdup(ELEM_INT);
            snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
            simplestring_add(&elem_val->text, buf);
            break;
         case xmlrpc_boolean:
            elem_val->name = strdup(ELEM_BOOLEAN);
            snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
            simplestring_add(&elem_val->text, buf);
            break;
         case xmlrpc_double:
            elem_val->name = strdup(ELEM_DOUBLE);
            snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
            simplestring_add(&elem_val->text, buf);
            break;
         case xmlrpc_datetime:
            elem_val->name = strdup(ELEM_DATETIME);
            simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
            break;
         case xmlrpc_base64:
            {
               struct buffer_st buf;
               elem_val->name = strdup(ELEM_BASE64);
               base64_encode(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
               simplestring_addn(&elem_val->text, buf.data, buf.offset );
               buffer_delete(&buf);
            }
            break;
         case xmlrpc_vector:
            {
               XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
               XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
               xml_element* root_vector_elem = elem_val;

               switch (my_type) {
               case xmlrpc_vector_array:
                  {
                      if(depth == 0) {
                         elem_val->name = strdup(ELEM_PARAMS);
                      }
                      else {
                         /* Hi my name is Dave and I like to make things as confusing
                          * as possible, thus I will throw in this 'data' element
                          * where it absolutely does not belong just so that people
                          * cannot code arrays and structs in a similar and straight
                          * forward manner. Have a good day.
                          *
                          * GRRRRRRRRR!
                          */
                         xml_element* data = xml_elem_new();
                         data->name = strdup(ELEM_DATA);
    
                         elem_val->name = strdup(ELEM_ARRAY);
                         Q_PushTail(&elem_val->children, data);
                         root_vector_elem = data;
                      }
                  }
                  break;
               case xmlrpc_vector_mixed:       /* not officially supported */
               case xmlrpc_vector_struct:
                  elem_val->name = strdup(ELEM_STRUCT);
                  break;
               default:
                  break;
               }

               /* recurse through sub-elements */
               while ( xIter ) {
                  xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1);
                  if (next_el) {
                     Q_PushTail(&root_vector_elem->children, next_el);
                  }
                  xIter = XMLRPC_VectorNext(node);
               }
            }
            break;
         default:
            break;
         }
      }

      {
         XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector);

         if (depth == 1) {
            xml_element* value = xml_elem_new();
            value->name = strdup(ELEM_VALUE);

            /* yet another hack for the "fault" crap */
            if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) {
               root = value;
				}
				else {
               xml_element* param = xml_elem_new();
               param->name = strdup(ELEM_PARAM);

               Q_PushTail(&param->children, value);

               root = param;
            }
            Q_PushTail(&value->children, elem_val);
			}
			else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) {
            xml_element* member = xml_elem_new();
            xml_element* name = xml_elem_new();
            xml_element* value = xml_elem_new();

            member->name = strdup(ELEM_MEMBER);
            name->name = strdup(ELEM_NAME);
            value->name = strdup(ELEM_VALUE);

            simplestring_add(&name->text, XMLRPC_GetValueID(node));

            Q_PushTail(&member->children, name);
            Q_PushTail(&member->children, value);
            Q_PushTail(&value->children, elem_val);

            root = member;
			}
			else if (vtype == xmlrpc_vector_array) {
            xml_element* value = xml_elem_new();

            value->name = strdup(ELEM_VALUE);

            Q_PushTail(&value->children, elem_val);

            root = value;
			}
			else if (vtype == xmlrpc_vector_none) {
            /* no parent.  non-op */
            root = elem_val;
			}
			else {
            xml_element* value = xml_elem_new();

            value->name = strdup(ELEM_VALUE);

            Q_PushTail(&value->children, elem_val);

            root = value;
         }
      }
   }
   return root;
}
コード例 #5
0
LLUserAuth::UserAuthcode LLUserAuth::parseResponse()
{
	// The job of this function is to parse sCurlDownloadArea and
	// extract every member into either the mResponses or
	// mOptions. For now, we will only be looking at mResponses, which
	// will all be string => string pairs.
	UserAuthcode rv = E_UNHANDLED_ERROR;
	XMLRPC_REQUEST response = mTransaction->response();
	if(!response) return rv;

	// clear out any old parsing
	mResponses.clear();
	mOptions.clear();

	// Now, parse everything
	std::string key;
	std::string val;
	XMLRPC_VALUE param = NULL;
	XMLRPC_VALUE current = NULL;
	XMLRPC_VALUE_TYPE_EASY type;
	param = XMLRPC_RequestGetData(response);
	if(!param) goto exit;
	current = XMLRPC_VectorRewind(param);
	while(current)
	{
		key.assign(XMLRPC_GetValueID(current));
		lldebugs << "key: " << key << llendl;
		type = XMLRPC_GetValueTypeEasy(current);
		if(xmlrpc_type_string == type)
		{
			val.assign(XMLRPC_GetValueString(current));
			lldebugs << "val: " << val << llendl;
			mResponses.insert(response_t::value_type(key, val));
		}
		else if(xmlrpc_type_int == type)
		{
			val = llformat( "%d", XMLRPC_GetValueInt(current));
			lldebugs << "val: " << val << llendl;
			mResponses.insert(response_t::value_type(key, val));
		}
		else if(xmlrpc_type_array == type)
		{
			options_t options;
			parseOptionInto(key, current, options);
			mOptions.insert(all_options_t::value_type(key, options));
		}
		else
		{
			// whoops - bad response
			llwarns << "Unhandled xmlrpc type, key, value: " << type << " "
					<< key << " " << val << "." << llendl;
			rv = E_UNHANDLED_ERROR;
			break;
		}
		current = XMLRPC_VectorNext(param);
		rv = E_OK;
	}

 exit:
	return rv;
}
コード例 #6
0
ファイル: xml_to_dandarpc.c プロジェクト: AllenJB/php-src
xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
#define BUF_SIZE 512
   xml_element* root = NULL;
   if(node) {
      char buf[BUF_SIZE];
      const char* id = XMLRPC_GetValueID(node);
      XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
      XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request);
      int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space);
      xml_element* elem_val = xml_elem_new();
      const char* pAttrType = NULL;

      xml_element_attr* attr_type = bNoAddType ? NULL : emalloc(sizeof(xml_element_attr));

      if(attr_type) {
         attr_type->key = estrdup(ATTR_TYPE);
         attr_type->val = 0;
         Q_PushTail(&elem_val->attrs, attr_type);
      }

      elem_val->name = (type == xmlrpc_vector) ? estrdup(ATTR_VECTOR) : estrdup(ATTR_SCALAR);

      if(id && *id) {
         xml_element_attr* attr_id = emalloc(sizeof(xml_element_attr));
         if(attr_id) {
            attr_id->key = estrdup(ATTR_ID);
            attr_id->val = estrdup(id);
            Q_PushTail(&elem_val->attrs, attr_id);
         }
      }

      switch(type) {
         case xmlrpc_string:
            pAttrType = ATTR_STRING;
            simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
            break;
         case xmlrpc_int:
            pAttrType = ATTR_INT;
            snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
            simplestring_add(&elem_val->text, buf);
            break;
         case xmlrpc_boolean:
            pAttrType = ATTR_BOOLEAN;
            snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
            simplestring_add(&elem_val->text, buf);
            break;
         case xmlrpc_double:
            pAttrType = ATTR_DOUBLE;
            snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
            simplestring_add(&elem_val->text, buf);
            break;
         case xmlrpc_datetime:
            pAttrType = ATTR_DATETIME;
            simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
            break;
         case xmlrpc_base64:
            {
               struct buffer_st buf;
               pAttrType = ATTR_BASE64;
               base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
               simplestring_addn(&elem_val->text, buf.data, buf.offset );
               buffer_delete(&buf);
            }
            break;
         case xmlrpc_vector:
            {
               XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
               XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);

               switch(my_type) {
                  case xmlrpc_vector_array:
                     pAttrType = ATTR_ARRAY;
                     break;
                  case xmlrpc_vector_mixed:
                     pAttrType = ATTR_MIXED;
                     break;
                  case xmlrpc_vector_struct:
                     pAttrType = ATTR_STRUCT;
                     break;
                  default:
                     break;
               }

               /* recurse through sub-elements */
               while( xIter ) {
                  xml_element* next_el = DANDARPC_to_xml_element_worker(request, xIter);
                  if(next_el) {
                     Q_PushTail(&elem_val->children, next_el);
                  }
                  xIter = XMLRPC_VectorNext(node);
               }
            }
            break;
         default:
            break;
      }
      if(pAttrType && attr_type && !bNoAddType) {
         attr_type->val = estrdup(pAttrType);
      }
      root = elem_val;
   }
   return root;
}
コード例 #7
0
ファイル: xml_to_soap.c プロジェクト: browniebraun/php-src
/* translates data structures to soap/xml. recursive */
xml_element* SOAP_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
#define BUF_SIZE 128
	xml_element* elem_val = NULL;
	if (node) {
		int bFreeNode = 0;  /* sometimes we may need to free 'node' variable */
		char buf[BUF_SIZE];
		XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(node);
		char* pName = NULL, *pAttrType = NULL;

		/* create our return value element */
		elem_val = xml_elem_new();

		switch (type) {
		case xmlrpc_type_struct:
		case xmlrpc_type_mixed:
		case xmlrpc_type_array:
			if (type == xmlrpc_type_array) {
				/* array's are _very_ special in soap.
				   TODO: Should handle sparse/partial arrays here. */

				/* determine soap array type. */
				const char* type = get_array_soap_type(node);
				xml_element_attr* attr_array_type = NULL;

				/* specify array kids type and array size. */
				snprintf(buf, sizeof(buf), "%s[%i]", type, XMLRPC_VectorSize(node));
				attr_array_type = new_attr(TOKEN_ARRAY_TYPE, buf);

				Q_PushTail(&elem_val->attrs, attr_array_type);

				pAttrType = TOKEN_ARRAY;
			}
			/* check for fault, which is a rather special case. 
			   (can't these people design anything consistent/simple/elegant?) */
			else if (type == xmlrpc_type_struct) {
				int fault_type = get_fault_type(node);
				if (fault_type) {
					if (fault_type == 1) {
						/* gen fault from xmlrpc style fault codes              
						    notice that we get a new node, which must be freed herein. */
						node = gen_fault_xmlrpc(node, elem_val);
						bFreeNode = 1;
					}
					pName = TOKEN_FAULT;
				}
			}

			{
				/* recurse through sub-elements */
				XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
				while ( xIter ) {
					xml_element* next_el = SOAP_to_xml_element_worker(request, xIter);
					if (next_el) {
						Q_PushTail(&elem_val->children, next_el);
					}
					xIter = XMLRPC_VectorNext(node);
				}
			}

			break;

			/* handle scalar types */
		case xmlrpc_type_empty:
			pAttrType = TOKEN_NULL;
			break;
		case xmlrpc_type_string:
			pAttrType = TOKEN_STRING;
			simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
			break;
		case xmlrpc_type_int:
			pAttrType = TOKEN_INT;
			snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
			simplestring_add(&elem_val->text, buf);
			break;
		case xmlrpc_type_boolean:
			pAttrType = TOKEN_BOOLEAN;
			snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
			simplestring_add(&elem_val->text, buf);
			break;
		case xmlrpc_type_double:
			pAttrType = TOKEN_DOUBLE;
			snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
			simplestring_add(&elem_val->text, buf);
			break;
		case xmlrpc_type_datetime:
			{
				time_t tt = XMLRPC_GetValueDateTime(node);
				struct tm *tm = localtime (&tt);
				pAttrType = TOKEN_DATETIME;
				if(strftime (buf, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm)) {
					simplestring_add(&elem_val->text, buf);
				}
			}
			break;
		case xmlrpc_type_base64:
			{
				struct buffer_st buf;
				pAttrType = TOKEN_BASE64;
				base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
				simplestring_addn(&elem_val->text, buf.data, buf.offset );
				buffer_delete(&buf);
			}
			break;
			break;
		default:
			break;
		}

		/* determining element's name is a bit tricky, due to soap semantics. */
		if (!pName) {
			/* if the value's type is known... */
			if (pAttrType) {
				/* see if it has an id (key). If so, use that as name, and type as an attribute. */
				pName = (char*)XMLRPC_GetValueID(node);
				if (pName) {
					Q_PushTail(&elem_val->attrs, new_attr(TOKEN_TYPE, pAttrType));
				}

				/* otherwise, use the type as the name. */
				else {
					pName = pAttrType;
				}
			}
			/* if the value's type is not known... (a rare case?) */
			else {
				/* see if it has an id (key). otherwise, default to generic "item" */
				pName = (char*)XMLRPC_GetValueID(node);
				if (!pName) {
					pName = "item";
				}
			}
		}
		elem_val->name = strdup(pName);

		/* cleanup */
		if (bFreeNode) {
			XMLRPC_CleanupValue(node);
		}
	}
	return elem_val;
}