diff options
Diffstat (limited to 'lib/orber/src/cdr_decode.erl')
-rw-r--r-- | lib/orber/src/cdr_decode.erl | 1487 |
1 files changed, 1487 insertions, 0 deletions
diff --git a/lib/orber/src/cdr_decode.erl b/lib/orber/src/cdr_decode.erl new file mode 100644 index 0000000000..9d30098940 --- /dev/null +++ b/lib/orber/src/cdr_decode.erl @@ -0,0 +1,1487 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: cdr_decode.erl +%% +%% Description: +%% This file contains all decoding functions for the CDR +%% format. +%% +%%----------------------------------------------------------------- +-module(cdr_decode). + +-include_lib("orber/src/orber_iiop.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("orber/include/corba.hrl"). + +-include_lib("orber/src/ifr_objects.hrl"). + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([dec_giop_message_header/1, dec_reply_header/4, + dec_reply_body/6, dec_locate_reply_header/4, + dec_locate_reply_body/5, dec_message_header/3, dec_request_body/6, + dec_octet_sequence_bin/6, dec_message/2, peek_request_id/2]). + +%%----------------------------------------------------------------- +%% Functions which only are exported for the testcases. +%%----------------------------------------------------------------- +-export([dec_type/5, dec_byte_order/1, dec_system_exception/4, dec_user_exception/4, + dec_byte_order_list/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- + +%%----------------------------------------------------------------- +%% Macros +%%----------------------------------------------------------------- +-define(DEBUG_LEVEL, 9). + +-define(ODD(N), (N rem 2) == 1). + +%%----------------------------------------------------------------- +%% Func: dec_message/3 +%% Args: +%% TypeCodes - is the type_codes of the return value and out parameters +%% when one decodes a reply. +%% Bytes - is the the message as a byte sequence. +%% Returns: +%% A tupple which contains the decoded message, +%% {ok, Header, Parameters, TypeCodes}. +%%----------------------------------------------------------------- +dec_message(TypeCodes, Bytes) -> + Message = dec_giop_message_header(Bytes), + case Message#giop_message.message_type of + ?GIOP_MSG_REQUEST -> + {Version, ReqHdr, Rest, Len, ByteOrder} = + dec_request_header(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order, Bytes), + dec_request_body(Version, ReqHdr, Rest, Len, ByteOrder, Bytes); + ?GIOP_MSG_REPLY -> + dec_reply(Message#giop_message.giop_version, + TypeCodes, Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_CANCEL_REQUEST -> + dec_cancel_request(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_LOCATE_REQUEST -> + dec_locate_request(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_LOCATE_REPLY -> + dec_locate_reply(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_CLOSE_CONNECTION -> + 'close_connection'; + ?GIOP_MSG_MESSAGE_ERROR -> + 'message_error'; + ?GIOP_MSG_FRAGMENT -> + dec_fragment_header(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order, Bytes) + end. + +%%----------------------------------------------------------------- +%% Func: dec_giop_message_header/1 +%% Args: +%% Bytes - is the the message as a byte sequence. +%% Returns: +%% A giop_message record. +%%----------------------------------------------------------------- +%% Magic|Version|BO| Type | Size | Body +dec_giop_message_header(<<"GIOP",1:8,0:8,1:8,MessType:8, + MessSize:32/little-unsigned-integer,Message/binary>>) -> + #giop_message{magic = "GIOP", giop_version = {1,0}, + byte_order = little, message_type = MessType, + message_size = MessSize, message = Message}; +dec_giop_message_header(<<"GIOP",1:8,0:8,0:8,MessType:8, + MessSize:32/big-unsigned-integer,Message/binary>>) -> + #giop_message{magic = "GIOP", giop_version = {1,0}, + byte_order = big, message_type = MessType, + message_size = MessSize, message = Message}; +dec_giop_message_header(<<"GIOP",1:8,Minor:8,Flags:8,MessType:8, + MessSize:32/little-unsigned-integer,Message/binary>>) when + ((Flags band 16#01) == 16#01) -> + #giop_message{magic = "GIOP", giop_version = {1,Minor}, + byte_order = little, fragments = ((Flags band 16#02) == 16#02), + message_type = MessType, message_size = MessSize, message = Message}; +dec_giop_message_header(<<"GIOP",1:8,Minor:8,Flags:8,MessType:8, + MessSize:32/big-unsigned-integer,Message/binary>>) -> + #giop_message{magic = "GIOP", giop_version = {1,Minor}, + byte_order = big, fragments = ((Flags band 16#02) == 16#02), + message_type = MessType, message_size = MessSize, message = Message}; +dec_giop_message_header(<<Hdr:?GIOP_HEADER_SIZE/binary, _Body/binary>>) -> + orber:dbg("[~p] cdr_decode:dec_giop_message_header(~p);~n" + "Orber cannot decode the GIOP-header.", [?LINE, Hdr], ?DEBUG_LEVEL), + exit(message_error); +dec_giop_message_header(Other) -> + orber:dbg("[~p] cdr_decode:dec_giop_message_header(~p);~n" + "Orber cannot decode the GIOP-header.", [?LINE, Other], ?DEBUG_LEVEL), + exit(message_error). + + +peek_request_id(big, <<ReqId:32/big-unsigned-integer,_/binary>>) -> + ReqId; +peek_request_id(little, <<ReqId:32/little-unsigned-integer,_/binary>>) -> + ReqId. + +%%----------------------------------------------------------------- +%% Func: dec_message_header/2 +%% Args: +%% Header - #giop_message{} +%% Bytes - is the the message body as a byte sequence. +%% Returns: +%%----------------------------------------------------------------- +dec_message_header(TypeCodes, Message, Bytes) -> + case Message#giop_message.message_type of + ?GIOP_MSG_REQUEST -> + dec_request_header(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order, Bytes); + ?GIOP_MSG_REPLY -> + dec_reply(Message#giop_message.giop_version, + TypeCodes, Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_CANCEL_REQUEST -> + dec_cancel_request(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_LOCATE_REQUEST -> + dec_locate_request(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_LOCATE_REPLY -> + dec_locate_reply(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order); + ?GIOP_MSG_CLOSE_CONNECTION -> + 'close_connection'; + ?GIOP_MSG_MESSAGE_ERROR -> + 'message_error'; + ?GIOP_MSG_FRAGMENT -> + dec_fragment_header(Message#giop_message.giop_version, + Message#giop_message.message, ?GIOP_HEADER_SIZE, + Message#giop_message.byte_order, Bytes) + end. + + +%%----------------------------------------------------------------- +%% Func: dec_byte_order/1 +%% Args: +%% The message as a byte sequence. +%% Returns: +%% A tuple {Endianess, Rest} where Endianess is big or little. +%% Rest is the remaining message byte sequence. +%%----------------------------------------------------------------- +dec_byte_order(<<0:8,T/binary>>) -> + {big, T}; +dec_byte_order(<<1:8,T/binary>>) -> + {little, T}. + +%%----------------------------------------------------------------- +%% Func: dec_byte_order_list/1 +%% Args: +%% The message as a byte sequence. +%% Returns: +%% A tuple {Endianess, Rest} where Endianess is big or little. +%% Rest is the remaining message byte sequence. +%%----------------------------------------------------------------- +dec_byte_order_list([0|T]) -> + {big, T}; +dec_byte_order_list([1|T]) -> + {little, T}. + +%%----------------------------------------------------------------- +%% Func : dec_response_flags +%% Args : +%% Returns : boolean +%%----------------------------------------------------------------- +%% FIX ME!! Not correct flag handling. +dec_response_flags(_Version, <<0:8, Rest/binary>>, Len) -> + {false, Rest, Len+1}; +dec_response_flags(_Version, <<1:8, Rest/binary>>, Len) -> + {true_oneway, Rest, Len+1}; +dec_response_flags(_Version, <<3:8, Rest/binary>>, Len) -> + {true, Rest, Len+1}; +dec_response_flags(_Version, <<X:8, Rest/binary>>, Len) -> + %% Not only the Response flag is set, test which. + if + %% Since the 6 most significant bits are unused we'll accept this for now. + ((X band 16#03) == 16#03) -> + {true, Rest, Len+1}; + ((X band 16#01) == 16#01) -> + {true_oneway, Rest, Len+1}; + true -> + {false, Rest, Len+1} + end. + +%%----------------------------------------------------------------- +%% Func : dec_target_addr +%% Args : Octet +%% Returns : boolean +%%----------------------------------------------------------------- +dec_target_addr(Version, Message, Len, ByteOrder, RequestId, Type) -> + case dec_type(?TARGETADDRESS, Version, Message, Len, ByteOrder, [], 0) of + {#'GIOP_TargetAddress'{label = ?GIOP_KeyAddr, value = KeyAddr}, Rest3, Len3, C} -> + {dec_target_key(KeyAddr, RequestId, Version, Type), Rest3, Len3, C}; + {#'GIOP_TargetAddress'{label = ?GIOP_ProfileAddr, + value = #'IOP_TaggedProfile'{tag=?TAG_INTERNET_IOP, + profile_data=PA}}, + Rest3, Len3, C} -> + {dec_target_key(PA, RequestId, Version, Type), Rest3, Len3, C}; + {#'GIOP_TargetAddress'{label = ?GIOP_ReferenceAddr, + value = #'GIOP_IORAddressingInfo'{ + selected_profile_index = _PI, + ior = IOR}}, Rest3, Len3, C} -> + {dec_target_key(iop_ior:get_objkey(IOR), RequestId, Version, Type), + Rest3, Len3, C}; + Other -> + orber:dbg("[~p] cdr_decode:dec_target_addr(~p);~n" + "Unsupported TargetAddress.", [?LINE, Other], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 12), completion_status=?COMPLETED_MAYBE}) + end. + +%%----------------------------------------------------------------- +%% Func : dec_target_key +%% Args : Octet +%% Returns : boolean +%%----------------------------------------------------------------- +dec_target_key(Key, RequestId, Version, Type) -> + %% The Type argument is used as an identifier of which operation it is. + %% We need it to be able to tell the difference if it's, for example, + %% a request or locate-request. + case corba:string_to_objkey_local(Key) of + {location_forward, Object} -> + throw({Type, Object, RequestId, Version, Key}); + ObjRef -> + ObjRef + end. + +%%----------------------------------------------------------------- +%% Func: dec_request_header/3 +%% Args: +%% Message - The message +%% Len0 - Number of bytes already read. +%% ByteOrder - little or big +%% Returns: +%%----------------------------------------------------------------- +dec_request_header(Version, Message, Len0, ByteOrder, _Buffer) when Version == {1,2} -> + {Request_id, Rest1, Len1, _} = dec_type('tk_ulong', Version, Message, Len0, + ByteOrder, [], 0), + {ResponseFlags, Rest2, Len2} = dec_response_flags(Version, Rest1, Len1), + {_, Rest2b, Len2b, _} = dec_type({'tk_array', 'tk_octet', 3}, Version, Rest2, Len2, ByteOrder, [], 0), + {Object_key, Rest3, Len3, _} = dec_target_addr(Version, Rest2b, Len2b, ByteOrder, Request_id, + 'location_forward'), + {Operation, Rest4, Len4, _} = dec_type({'tk_string', 0}, Version, Rest3, Len3, ByteOrder, [], 0), + {Context, Rest5, Len5} = dec_service_context(Version, Rest4, Len4, ByteOrder), + {Version, #request_header{service_context=Context, + request_id=Request_id, + response_expected=ResponseFlags, + object_key=Object_key, + operation=list_to_atom(Operation), + requesting_principal=""}, Rest5, Len5, ByteOrder}; +dec_request_header(Version, Message, Len0, ByteOrder, _Buffer) -> + {Context, Rest1, Len1} = dec_service_context(Version, Message, Len0, ByteOrder), + {Request_id, Rest2, Len2, _} = dec_type('tk_ulong', Version, Rest1, Len1, ByteOrder, [], 0), + {Response_expected, Rest3, Len3, _} = dec_type('tk_boolean', Version, Rest2, Len2, + ByteOrder, [], 0), + {ObjKey, Rest4, Len4, _} = dec_type({'tk_sequence', 'tk_octet', 0}, Version, Rest3, + Len3, ByteOrder, [], 0), + Object_key = dec_target_key(ObjKey, Request_id, Version, 'location_forward'), + {Operation, Rest5, Len5, _} = dec_type({'tk_string', 0}, Version, Rest4, Len4, ByteOrder, [], 0), + {Principal, Rest, Len, _} = dec_type({'tk_string', 0}, Version, Rest5,Len5, ByteOrder, [], 0), + {Version, #request_header{service_context=Context, + request_id=Request_id, + response_expected=Response_expected, + object_key=Object_key, + operation=list_to_atom(Operation), + requesting_principal=Principal}, Rest, Len, ByteOrder}. + + +%%----------------------------------------------------------------- +%% Func: dec_service_context/4 +%% Args: Version - e.g. 1.2 +%% Message - The message +%% Len - Number of bytes already read. +%% ByteOrder - little or big +%% Returns: +%%----------------------------------------------------------------- +dec_service_context(Version, Message, Len, ByteOrder) -> + {Context, Rest, Len1} = dec_type(?IOP_SERVICECONTEXT, Version, Message, + Len, ByteOrder), + {dec_used_contexts(Version, Context, []), Rest, Len1}. + +dec_used_contexts(_Version, [], Ctxs) -> + Ctxs; +dec_used_contexts({1,0}, [#'IOP_ServiceContext'{context_id=?IOP_CodeSets}|T], Ctxs) -> + %% Not supported by 1.0, drop it. + dec_used_contexts({1,0}, T, Ctxs); +dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_CodeSets, + context_data = Bytes}|T], Ctxs) -> + {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)), + {CodeCtx, _, _} = dec_type(?CONV_FRAME_CODESETCONTEXT, Version, + Rest, 1, ByteOrder), + dec_used_contexts(Version, T, + [#'IOP_ServiceContext'{context_id=?IOP_CodeSets, + context_data = CodeCtx}|Ctxs]); +dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_BI_DIR_IIOP, + context_data = Bytes}|T], Ctxs) -> + {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)), + {BiDirCtx, _, _} = dec_type(?IIOP_BIDIRIIOPSERVICECONTEXT, Version, + Rest, 1, ByteOrder), + dec_used_contexts(Version, T, + [#'IOP_ServiceContext'{context_id=?IOP_BI_DIR_IIOP, + context_data = BiDirCtx}|Ctxs]); +dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_FT_REQUEST, + context_data = Bytes}|T], Ctxs) -> + {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)), + {Ctx, _, _} = dec_type(?FT_FTRequestServiceContext, Version, + Rest, 1, ByteOrder), + dec_used_contexts(Version, T, + [#'IOP_ServiceContext'{context_id=?IOP_FT_REQUEST, + context_data = Ctx}|Ctxs]); +dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_FT_GROUP_VERSION, + context_data = Bytes}|T], Ctxs) -> + {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)), + {Ctx, _, _} = dec_type(?FT_FTGroupVersionServiceContext, Version, + Rest, 1, ByteOrder), + dec_used_contexts(Version, T, + [#'IOP_ServiceContext'{context_id=?IOP_FT_GROUP_VERSION, + context_data = Ctx}|Ctxs]); +dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService, + context_data = Bytes}|T], Ctxs) -> + {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)), + {Ctx, _, _} = dec_type(?CSI_SASContextBody, Version, + Rest, 1, ByteOrder), + dec_used_contexts(Version, T, + [#'IOP_ServiceContext'{context_id=?IOP_SecurityAttributeService, + context_data = Ctx}|Ctxs]); +dec_used_contexts(Version, [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID, + context_data = Bytes}|T], Ctxs) -> + {ByteOrder, Rest} = dec_byte_order(list_to_binary(Bytes)), + {Ctx, _, _} = dec_type(?ORBER_GENERIC_CTX, Version, + Rest, 1, ByteOrder), + dec_used_contexts(Version, T, + [#'IOP_ServiceContext'{context_id=?ORBER_GENERIC_CTX_ID, + context_data = binary_to_term(list_to_binary(Ctx))}|Ctxs]); +dec_used_contexts(Version, [H|T], Ctxs) -> + dec_used_contexts(Version, T, [H|Ctxs]). + +%%----------------------------------------------------------------- +%% Func: dec_request_body +%% Args: Version - e.g. 1.2 +%% Returns: +%%----------------------------------------------------------------- +dec_request_body(Version, ReqHdr, Rest, Len, ByteOrder, Buffer) -> + {Parameters, TypeCodes, _} = + dec_request_body(Version, ReqHdr#request_header.object_key, + ReqHdr#request_header.operation, + Rest, Len, ByteOrder, Buffer, Len), + {Version, ReqHdr, Parameters, TypeCodes}. + +dec_request_body(Version, Object_key, Operation, Body, Len, ByteOrder, Buffer, Counter) + when Version == {1,2} -> + case orber_typedefs:get_op_def(Object_key, Operation) of + {RetType, [], OutParameters} -> + {[], {RetType, [], OutParameters}, Len}; + {RetType, InParameters, OutParameters} -> + {Rest, Len1, NewC} = dec_align(Body, Len, 8, Counter), + {Parameters, Len2} = dec_parameters(Version, InParameters, Rest, Len1, + ByteOrder, Buffer, NewC), + {Parameters, {RetType, InParameters, OutParameters}, Len2} + end; +dec_request_body(Version, Object_key, Operation, Body, Len, ByteOrder, Buffer, Counter) -> + {RetType, InParameters, OutParameters} = + orber_typedefs:get_op_def(Object_key, Operation), + {Parameters, Len1} = dec_parameters(Version, InParameters, Body, Len, ByteOrder, Buffer, Counter), + {Parameters, {RetType, InParameters, OutParameters}, Len1}. + +dec_parameters(_, [], _, Len, _, _, _) -> + {[], Len}; +dec_parameters(Version, [P1 |InParList], Body, Len, ByteOrder, Buffer, Counter) -> + {Object, Rest, Len1, NewCounter} = dec_type(P1, Version, Body, Len, ByteOrder, Buffer, Counter), + {List, Len2} = dec_parameters(Version, InParList, Rest, Len1, ByteOrder, Buffer, NewCounter), + {[Object | List], Len2}. + +%%----------------------------------------------------------------- +%% Func: dec_reply/5 +%% Args: +%% Message - The message +%% Len0 - Number of bytes already read. +%% ByteOrder - little or big +%% Returns: +%% A tuple {ReplyHeader, Result} where ReplyHeader is a +%% reply_header record and Result the decode result. +%%----------------------------------------------------------------- +dec_reply(Version, TypeCodes, Message, Len0, ByteOrder) -> + {ReplyHeader, Rest, Len} = dec_reply_header(Version, Message, Len0, ByteOrder), + {Result, Par} = + case ReplyHeader#reply_header.reply_status of + 'no_exception' -> + {R, P, _} = dec_reply_body(Version, TypeCodes, Rest, Len, ByteOrder, Message), + {R, P}; + 'system_exception' -> + {R, _} = dec_system_exception(Version, Rest, Len, ByteOrder), + {R, []}; + 'user_exception' -> + {R, _} = dec_user_exception(Version, Rest, Len, ByteOrder), + {R, []}; + 'location_forward' -> + {R, _, _} = dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]}, + Rest, Len, ByteOrder, Message), + {R, []}; + %% This is deprecated in later version than CORBA-2.3.1. We'll leave it for + %% now. + 'location_forward_perm' -> + {R, _, _} = dec_reply_body(Version, {{'tk_objref', "", ""}, [],[]}, + Rest, Len, ByteOrder, Message), + {R, []}; + 'needs_addressing_mode' -> + {R, _, _} = dec_reply_body(Version, {'tk_short', [],[]}, + Rest, Len, ByteOrder, Message), + {R, []} + end, + {ReplyHeader, Result, Par}. + + +%% ## NEW IIOP 1.2 ## +dec_reply_header(Version, Message, Len0, ByteOrder) when Version == {1,2} -> + {Request_id, Rest1, Len1} = dec_type('tk_ulong', Version, Message, Len0, ByteOrder), + {ReplyStatus, Rest2, Len2} = dec_reply_status(Version, Rest1, Len1, ByteOrder), + {Context, Rest, Len3} = dec_service_context(Version, Rest2, Len2, ByteOrder), + {#reply_header{service_context=Context, request_id=Request_id, reply_status=ReplyStatus}, + Rest, Len3}; + +dec_reply_header(Version, Message, Len0, ByteOrder) -> + {Context, Rest1, Len1} = dec_service_context(Version, Message, Len0, ByteOrder), + {Request_id, Rest2, Len2} = dec_type('tk_ulong', Version, Rest1, Len1, ByteOrder), + {ReplyStatus, Rest, Len3} = dec_reply_status(Version, Rest2, Len2, ByteOrder), + {#reply_header{service_context=Context, request_id=Request_id, reply_status=ReplyStatus}, + Rest, Len3}. + +dec_reply_status(Version, Status, Len, ByteOrder) -> + {L, Rest, Len1}= dec_type('tk_ulong', Version, Status, Len, ByteOrder), + {dec_giop_reply_status_type(L), Rest, Len1}. + +dec_reply_body(_, {'tk_void', _, []}, <<>>, Len, _, _) -> + %% This case is mainly to be able to avoid removing non-existent alignment for + %% IIOP-1.2 messages if the body should be empty, i.e., void return value and + %% no out parameters. + {ok, [], Len}; +dec_reply_body(Version, {RetType, _InParameters, OutParameters}, Body, Len, + ByteOrder, Bytes) when Version == {1,2} -> + {Rest, Len1, Counter} = dec_align(Body, Len, 8, Len), + {Result, Rest2, Len2, C} = dec_type(RetType, Version, Rest, Len1, ByteOrder, Bytes, Counter), + {Par, Len3} = dec_parameters(Version, OutParameters, Rest2, Len2, ByteOrder, Bytes, C), + {Result, Par, Len3}; +dec_reply_body(Version, {RetType, _InParameters, OutParameters}, Body, Len, ByteOrder, Bytes) -> + {Result, Rest, Len1, C} = dec_type(RetType, Version, Body, Len, ByteOrder, Bytes, Len), + {Par, Len2} = dec_parameters(Version, OutParameters, Rest, Len1, ByteOrder, Bytes, C), + {Result, Par, Len2}. + + +%%----------------------------------------------------------------- +%% Func: dec_cancel_request/3 +%% Args: +%% Message - The message +%% Len - Number of bytes already read. +%% ByteOrder - little or big +%% Returns: +%% A cancel_request_header record. +%%----------------------------------------------------------------- +dec_cancel_request(Version, Message, Len, ByteOrder) -> + {Request_id, _, _} = dec_type('tk_ulong', Version, Message, Len, ByteOrder), + #cancel_request_header{request_id=Request_id}. + +%%----------------------------------------------------------------- +%% Func: dec_locate_request/3 +%% Args: +%% Message - The message +%% Len - Number of bytes already read. +%% ByteOrder - little or big +%% Returns: +%% A locate_request_header record. +%%----------------------------------------------------------------- +%% ## NEW IIOP 1.2 ## +dec_locate_request(Version, Message, Len, ByteOrder) when Version == {1,2} -> + {Request_id, Rest, Len1} = dec_type('tk_ulong', Version, Message, Len, ByteOrder), + {Object_key, _, _, _} = dec_target_addr(Version, Rest, Len1, ByteOrder, Request_id, + 'object_forward'), + {Version, #locate_request_header{request_id=Request_id, object_key=Object_key}}; +dec_locate_request(Version, Message, Len, ByteOrder) -> + {Request_id, Rest, Len1} = dec_type('tk_ulong', Version, Message, Len, ByteOrder), + {ObjKey, _, _} = dec_type({'tk_sequence', 'tk_octet', 0}, Version, Rest, + Len1, ByteOrder), + Object_key = dec_target_key(ObjKey, Request_id, Version, 'object_forward'), + {Version, #locate_request_header{request_id=Request_id, object_key=Object_key}}. + + +%%----------------------------------------------------------------- +%% Func: dec_locate_reply/3 +%% Args: +%% Message - The message +%% Len - Number of bytes already read. +%% ByteOrder - little or big +%% Returns: +%% A locate_reply_header record. +%%----------------------------------------------------------------- +dec_locate_reply(Version, Message, Len, ByteOrder) -> + {ReplyHeader, Rest1, Len1} = dec_locate_reply_header(Version, Message, Len, ByteOrder), + {ReplyHeader, dec_locate_reply_body(Version, ReplyHeader#locate_reply_header.locate_status, Rest1, + Len1, ByteOrder)}. + +dec_locate_reply_header(Version, Message, Len, ByteOrder) -> + {Request_id, Rest1, Len1} = dec_type('tk_ulong', Version, Message, Len, ByteOrder), + {Locate_status, Rest2, Len2} = dec_locate_status(Version, Rest1, Len1, ByteOrder), + {#locate_reply_header{request_id=Request_id, locate_status=Locate_status}, Rest2, Len2}. + +dec_locate_reply_body(Version, LocateStatus, Rest, Len, ByteOrder) when Version == {1,2} -> + %% In CORBA-2.3.1 the LocateReply body didn't align the body (8-octet + %% boundry) for IIOP-1.2. This have been changed in CORBA-2.4 and + %% changed back in CORBA-2.6. Hence, we should not change this. + case LocateStatus of + 'object_forward' -> + {ObjRef, _, _, _} = dec_objref(Version, Rest, Len, ByteOrder), + ObjRef; + 'object_forward_perm' -> + %% This is deprecated in later version than CORBA-2.3.1. We'll leave it for + %% now. + {ObjRef, _, _, _} = dec_objref(Version, Rest, Len, ByteOrder), + ObjRef; + 'loc_system_exception' -> + %% This should be updated but since 'dec_system_exception' removes + %% alignment, which the LocateReplyBody don't have, for 1.2 we + %% pretend it's 1.1 for now. + {SysExc, _} = dec_system_exception({1,1}, Rest, Len, ByteOrder), + corba:raise(SysExc); + 'loc_needs_addressing_mode' -> + %% Not supported. + []; + _ -> + [] + end; +dec_locate_reply_body(Version, LocateStatus, Rest, Len, ByteOrder) -> + case LocateStatus of + 'object_forward' -> + {ObjRef, _, _, _} = dec_objref(Version, Rest, Len, ByteOrder), + ObjRef; + _ -> + [] + end. + +dec_locate_status(Version, Bytes, Len, ByteOrder) -> + {L, Rest, Len1} = dec_type('tk_ulong', Version, Bytes, Len, ByteOrder), + {dec_giop_locate_status_type(L), Rest, Len1}. + + +%%----------------------------------------------------------------- +%% Func: dec_fragment_header/5 +%% Args: +%% Message - The message +%% Len0 - Number of bytes already read. +%% ByteOrder - little or big +%% Returns: +%%----------------------------------------------------------------- +dec_fragment_header(Version, Message, Len0, ByteOrder, _Buffer) when Version == {1,2} -> + {RequestId, Rest1, Len1, _} = dec_type('tk_ulong', Version, Message, Len0, + ByteOrder, [], 0), + {Version, #fragment_header{request_id=RequestId}, Rest1, Len1, ByteOrder}; +dec_fragment_header(Version, _Message, _Len0, _ByteOrder, _Buffer) -> + %% The FragmentHeader is IIOP-1.2 specific. Hence, do nothing here. + orber:dbg("[~p] cdr_decode:dec_fragment_header(~p)~n" + "Orber only supports fragmented messages for IIOP-1.2.", + [?LINE, Version], ?DEBUG_LEVEL), + exit(message_error). +% {Version, #fragment_header{}, Message, Len0, ByteOrder}. + +%%----------------------------------------------------------------- +%% Func: dec_giop_reply_status_type +%% Args: +%% An integer status code +%% Returns: +%% An atom which is the reply status +%%----------------------------------------------------------------- +dec_giop_reply_status_type(0) -> + 'no_exception'; +dec_giop_reply_status_type(1) -> + 'user_exception'; +dec_giop_reply_status_type(2) -> + 'system_exception'; +dec_giop_reply_status_type(3) -> + 'location_forward'; +%% ## IIOP-1.2 ## +dec_giop_reply_status_type(4) -> + 'location_forward_perm'; +dec_giop_reply_status_type(5) -> + 'needs_addressing_mode'. + +%%----------------------------------------------------------------- +%% Func: dec_giop_locate_status_type +%% Args: +%% An integer status code +%% Returns: +%% An atom which is the reply status +%%----------------------------------------------------------------- +dec_giop_locate_status_type(0) -> + 'unknown_object'; +dec_giop_locate_status_type(1) -> + 'object_here'; +dec_giop_locate_status_type(2) -> + 'object_forward'; +%% ## IIOP-1.2 ## +dec_giop_locate_status_type(3) -> + 'object_forward_perm'; +dec_giop_locate_status_type(4) -> + 'loc_system_exception'; +dec_giop_locate_status_type(5) -> + 'loc_needs_addressing_mode'. + + +%%----------------------------------------------------------------- +%% Func: dec_type/5 +%%----------------------------------------------------------------- +dec_type(Type, Version, Bytes, Len, ByteOrder) -> + {Val, Rest, Len2, _} = + dec_type(Type, Version, Bytes, Len, ByteOrder, [], 0), + {Val, Rest, Len2}. + +dec_type('tk_null', _Version, Bytes, Len, _, _, C) -> + {'null', Bytes, Len, C}; +dec_type('tk_void', _Version, Bytes, Len, _, _, C) -> + {'ok', Bytes, Len, C}; +dec_type('tk_short', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 2, C), + {Short, Rest1} = cdrlib:dec_short(ByteOrder, Rest), + {Short, Rest1, Len1 + 2, NewC+2}; +dec_type('tk_long', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C), + {Long, Rest1} = cdrlib:dec_long(ByteOrder, Rest), + {Long, Rest1, Len1 + 4, NewC+4}; +dec_type('tk_longlong', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 8, C), + {Long, Rest1} = cdrlib:dec_longlong(ByteOrder, Rest), + {Long, Rest1, Len1 + 8, NewC+8}; +dec_type('tk_ushort', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 2, C), + {Short, Rest1} = cdrlib:dec_unsigned_short(ByteOrder, Rest), + {Short, Rest1, Len1 + 2, NewC+2}; +dec_type('tk_ulong', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C), + {Long, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + {Long, Rest1, Len1 + 4, NewC+4}; +dec_type('tk_ulonglong', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 8, C), + {Long, Rest1} = cdrlib:dec_unsigned_longlong(ByteOrder, Rest), + {Long, Rest1, Len1 + 8, NewC+8}; +dec_type('tk_float', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C), + {Float, Rest1} = cdrlib:dec_float(ByteOrder, Rest), + {Float, Rest1, Len1 + 4, NewC+4}; +dec_type('tk_double', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 8, C), + {Double, Rest1} = cdrlib:dec_double(ByteOrder, Rest), + {Double, Rest1, Len1 + 8, NewC+8}; +dec_type('tk_boolean', _Version, Bytes, Len, _, _, C) -> + {Bool, Rest} = cdrlib:dec_bool(Bytes), + {Bool, Rest, Len + 1, C+1}; +dec_type('tk_char', _Version, Bytes, Len, _, _, C) -> + {Char, Rest} = cdrlib:dec_char(Bytes), + {Char, Rest, Len + 1, C+1}; +dec_type('tk_wchar', {1,2}, Bytes, Len, _ByteOrder, _, C) -> + %% For IIOP-1.2 a wchar is almost encoded the same way as an octet-sequence. + %% The only difference is that the length-value is an octet as well. + case cdrlib:dec_octet(Bytes) of + {2, Rest1} -> + %% Currently we only allow 2-bytes wchar. + {WChar, Rest2} = cdrlib:dec_unsigned_short(big, Rest1), + {WChar, Rest2, Len+3, C+3}; + {What, _} -> + orber:dbg("[~p] cdr_decode:dec_type(~p); unsupported wchar", + [?LINE, What], ?DEBUG_LEVEL), + corba:raise(#'DATA_CONVERSION'{completion_status=?COMPLETED_NO}) + end; +%% For 1.1 the wchar is limited to the use of two-octet fixed-length encoding. +dec_type('tk_wchar', _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 2, C), + {WChar, Rest2} = cdrlib:dec_unsigned_short(ByteOrder, Rest), + {WChar, Rest2, Len1 + 2, NewC+2}; +dec_type('tk_octet', _Version, Bytes, Len, _, _, C) -> + {Octet, Rest} = cdrlib:dec_octet(Bytes), + {Octet, Rest, Len + 1, C+1}; +dec_type('tk_any', Version, Bytes, Len, ByteOrder, Buff, C) -> + {TypeCode, Rest1, Len1, NewC} = dec_type('tk_TypeCode', Version, Bytes, Len, ByteOrder, Buff, C), + {Value, Rest2, Len2, NewC2} = dec_type(TypeCode, Version, Rest1, Len1, ByteOrder, Buff, NewC), + {#any{typecode=TypeCode, value=Value}, Rest2, Len2, NewC2}; +dec_type('tk_TypeCode', Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_type_code(Version, Bytes, Len, ByteOrder, Buff, C); +dec_type('tk_Principal', Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_sequence(Version, Bytes, 'tk_octet', Len, ByteOrder, Buff, C); +dec_type({'tk_objref', _IFRId, _Name}, Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_objref(Version, Bytes, Len, ByteOrder, Buff, C); +dec_type({'tk_struct', IFRId, Name, ElementList}, Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_struct(Version, IFRId, Name, ElementList, Bytes, Len, ByteOrder, Buff, C); +dec_type({'tk_union', IFRId, Name, DiscrTC, Default, ElementList}, + Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_union(Version, IFRId, Name, DiscrTC, Default, ElementList, Bytes, Len, ByteOrder, Buff, C); +dec_type({'tk_enum', _IFRId, _Name, ElementList}, _Version, Bytes, Len, ByteOrder, _, C) -> + {Rest, Len1, NewC} = dec_align(Bytes, Len, 4, C), + {Enum, Rest1} = cdrlib:dec_enum(ByteOrder, ElementList, Rest), + {Enum, Rest1, Len1 + 4, NewC+4}; +dec_type({'tk_string', _MaxLength}, Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_string(Version, Bytes, Len, ByteOrder, Buff, C); +dec_type({'tk_wstring', _MaxLength}, Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_wstring(Version, Bytes, Len, ByteOrder, Buff, C); +dec_type({'tk_sequence', ElemTC, _MaxLength}, Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_sequence(Version, Bytes, ElemTC, Len, ByteOrder, Buff, C); +dec_type({'tk_array', ElemTC, Size}, Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_array(Version, Bytes, Size, ElemTC, Len, ByteOrder, Buff, C); +dec_type({'tk_alias', _IFRId, _Name, TC}, Version, Bytes, Len, ByteOrder, Buff, C) -> + dec_type(TC, Version, Bytes, Len, ByteOrder, Buff, C); +%dec_type({'tk_except', IFRId, Name, ElementList}, Version, Bytes, Len, ByteOrder) -> +dec_type({'tk_fixed', Digits, Scale}, _Version, Bytes, Len, _ByteOrder, _Buff, C) -> + dec_fixed(Digits, Scale, Bytes, Len, C); +dec_type(Type, _, _, _, _, _, _) -> + orber:dbg("[~p] cdr_decode:dec_type(~p)~n" + "Incorrect TypeCode or unsupported type.", + [?LINE, Type], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 13), completion_status=?COMPLETED_MAYBE}). + +stringify_enum({tk_enum,_,_,_}, Label) -> + atom_to_list(Label); +stringify_enum(_, Label) -> + Label. + +%%----------------------------------------------------------------- +%% Func: dec_fixed +%%----------------------------------------------------------------- +%% Digits eq. total number of digits. +%% Scale eq. position of the decimal point. +%% E.g. fixed<5,2> - "123.45" +%% E.g. fixed<4,2> - "12.34" +%% These are encoded as: +%% ## <5,2> ## ## <4,2> ## +%% 1,2 0,1 eq. 1 octet +%% 3,4 2,3 +%% 5,0xC 4,0xC +%% +%% Each number is encoded as a half-octet. Note, for <4,2> a zero is +%% added first to to be able to create "even" octets. +dec_fixed(0, 0, Bytes, Len, C) -> + {#fixed{digits = 0, scale = 0, value = ""}, Bytes, Len, C}; +dec_fixed(Digits, Scale, Bytes, Len, C) -> + case ?ODD(Digits) of + true -> + {Fixed, Bytes2, Len2, C2, Sign} = dec_fixed_2(Digits, Scale, Bytes, Len, C), + case Sign of + ?FIXED_POSITIVE -> + {#fixed{digits = Digits, scale = Scale, + value = list_to_integer(Fixed)}, Bytes2, Len2, C2}; + ?FIXED_NEGATIVE -> + {#fixed{digits = Digits, scale = Scale, + value = -list_to_integer(Fixed)}, Bytes2, Len2, C2} + end; + false -> + %% If the length (of fixed) is even a zero is added first. + %% Subtract that we've read 1 digit. + <<0:4,D2:4,T/binary>> = Bytes, + {Fixed, Bytes2, Len2, C2, Sign} = dec_fixed_2(Digits-1, Scale, T, Len+1, C+1), + case Sign of + ?FIXED_POSITIVE -> + {#fixed{digits = Digits, scale = Scale, + value = list_to_integer([D2+48|Fixed])}, Bytes2, Len2, C2}; + ?FIXED_NEGATIVE -> + {#fixed{digits = Digits, scale = Scale, + value = -list_to_integer([D2+48|Fixed])}, Bytes2, Len2, C2} + end + end. + +dec_fixed_2(1, _Scale, <<D1:4,?FIXED_POSITIVE:4,T/binary>>, Len, C) -> + {[D1+48], T, Len+1, C+1, ?FIXED_POSITIVE}; +dec_fixed_2(1, _Scale, <<D1:4,?FIXED_NEGATIVE:4,T/binary>>, Len, C) -> + {[D1+48], T, Len+1, C+1, ?FIXED_NEGATIVE}; +dec_fixed_2(Digits, Scale, _Bytes, _Len, _C) when Digits =< 0 -> + orber:dbg("[~p] cdr_decode:dec_fixed_2(~p, ~p)~n" + "Malformed fixed type.", [?LINE, Digits, Scale], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 14), completion_status=?COMPLETED_MAYBE}); +dec_fixed_2(Digits, Scale, <<>>, _Len, _C) -> + orber:dbg("[~p] cdr_decode:dec_fixed_2(~p, ~p)~n" + "The fixed type received was to short.", + [?LINE, Digits, Scale], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 14), completion_status=?COMPLETED_MAYBE}); +dec_fixed_2(Digits, Scale, <<D1:4,D2:4,T/binary>>, Len, C) -> + {Seq, Rest2, Len2, NewC2, Sign} = dec_fixed_2(Digits-2, Scale, T, Len+1, C+1), + {[D1+48, D2+48 | Seq], Rest2, Len2, NewC2, Sign}. + +%%----------------------------------------------------------------- +%% Func: dec_sequence/7 and dec_sequence/8 +%%----------------------------------------------------------------- +dec_sequence(_Version, Message, 'tk_octet', Len, ByteOrder, _Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + <<OctetSeq:Size/binary, Rest2/binary>> = Rest1, + {binary_to_list(OctetSeq), Rest2, Len1+4+Size, NewC+4+Size}; +dec_sequence(_Version, Message, 'tk_char', Len, ByteOrder, _Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + <<OctetSeq:Size/binary, Rest2/binary>> = Rest1, + {binary_to_list(OctetSeq), Rest2, Len1+4+Size, NewC+4+Size}; +%% We test if it's a sequence of struct's or unions. By doing this we only +%% have to look up the IFR-ID once instead of N times (N eq length of sequence). +dec_sequence(Version, Message, {'tk_struct', IFRId, ShortName, ElementList}, + Len, ByteOrder, Buff, C) when IFRId /= "", ShortName /= "" -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + case IFRId of + ?SYSTEM_TYPE -> + dec_sequence_struct(Version, Rest1, Size, ElementList, Len1 + 4, + ByteOrder, Buff, NewC+4, ShortName); + _ -> + Name = ifrid_to_name(IFRId, ?IFR_StructDef), + dec_sequence_struct(Version, Rest1, Size, ElementList, Len1 + 4, + ByteOrder, Buff, NewC+4, Name) + end; +dec_sequence(Version, Message, + {'tk_union', ?SYSTEM_TYPE, TCName, DiscrTC, Default, ElementList}, + Len, ByteOrder, Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + dec_sequence_union(Version, Rest1, Size, DiscrTC, Default, ElementList, Len1 + 4, + ByteOrder, Buff, NewC+4, TCName); +dec_sequence(Version, Message, + {'tk_union', IFRId, _TCName, DiscrTC, Default, ElementList}, + Len, ByteOrder, Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + Name = ifrid_to_name(IFRId, ?IFR_UnionDef), + dec_sequence_union(Version, Rest1, Size, DiscrTC, Default, ElementList, Len1 + 4, + ByteOrder, Buff, NewC+4, Name); +dec_sequence(Version, Message, TypeCode, Len, ByteOrder, Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + dec_sequence(Version, Rest1, Size, TypeCode, Len1 + 4, ByteOrder, Buff, NewC+4). + + +dec_sequence(_, Message, 0, _Type, Len, _ByteOrder, _Buff, C) -> + {[], Message, Len, C}; +dec_sequence(Version, Message, N, Type, Len, ByteOrder, Buff, C) -> + {Object, Rest1, Len1, NewC} = dec_type(Type, Version, Message, Len, ByteOrder, Buff, C), + {Seq, Rest2, Len2, NewC2} = dec_sequence(Version, Rest1, N - 1, Type, Len1, ByteOrder, Buff, NewC), + {[Object | Seq], Rest2, Len2, NewC2}. + +dec_sequence_struct(_, Message, 0, _Type, Len, _ByteOrder, _Buff, C, _Name) -> + {[], Message, Len, C}; +dec_sequence_struct(Version, Message, N, TypeCodeList, Len, ByteOrder, Buff, C, Name) -> + {Struct, Rest1, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C), + {Seq, Rest2, Len2, NewC2} = dec_sequence_struct(Version, Rest1, N - 1, TypeCodeList, Len1, ByteOrder, + Buff, NewC, Name), + {[list_to_tuple([Name |Struct]) | Seq], Rest2, Len2, NewC2}. +dec_sequence_union(_, Message, 0, _DiscrTC, _Default, _ElementList, Len, _ByteOrder, _Buff, C, _Name) -> + {[], Message, Len, C}; +dec_sequence_union(Version, Message, N, DiscrTC, Default, ElementList, Len, ByteOrder, Buff, C, Name) -> + + {Label, Rest1, Len1, NewC} = dec_type(DiscrTC, Version, Message, Len, ByteOrder, Buff, C), + Result = dec_union(Version, stringify_enum(DiscrTC, Label), ElementList, Default, + Rest1, Len1, ByteOrder, Buff, NewC), + {Value, Rest2, Len2, NewC3} = case Result of + {default, R, L, NewC2} -> + dec_union(Version, default, ElementList, Default, + R, L, ByteOrder, Buff, NewC2); + X -> + X + end, + {Seq, Rest3, Len3, NewC4} = dec_sequence_union(Version, Rest2, N - 1, + DiscrTC, Default, ElementList, + Len2, ByteOrder, + Buff, NewC3, Name), + {[{Name, Label, Value} | Seq], Rest3, Len3, NewC4}. + +%% A special case; when something is encapsulated (i.e. sent as octet-sequence) +%% we sometimes don not want the result to be converted to a list. +dec_octet_sequence_bin(_Version, Message, Len, ByteOrder, _Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + <<OctetSeq:Size/binary, Rest2/binary>> = Rest1, + {OctetSeq, Rest2, Len1+4+Size, NewC+4+Size}. + +%%----------------------------------------------------------------- +%% Func: dec_array/5 +%%----------------------------------------------------------------- +dec_array(Version, Message, Size, TypeCode, Len, ByteOrder, Buff, C) -> + {Seq, Rest1, Len1, NewC} = dec_sequence(Version, Message, Size, TypeCode, Len, + ByteOrder, Buff, C), + {list_to_tuple(Seq), Rest1, Len1, NewC}. + + +%%----------------------------------------------------------------- +%% Func: dec_string/4 +%%----------------------------------------------------------------- +dec_string(_Version, Message, Len, ByteOrder, _Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + if + Size > 0 -> + DataSize = Size-1, + <<String:DataSize/binary, _Null:1/binary, Rest2/binary>> = Rest1, + {binary_to_list(String), Rest2, Len1+4+Size, NewC+4+Size}; + true -> + {"", Rest1, Len1 + 4, NewC+4} + end. + +%%----------------------------------------------------------------- +%% Func: dec_string/4 +%%----------------------------------------------------------------- +dec_wstring({1,2}, Message, Len, ByteOrder, Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Octets, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + if + Octets == 0 -> + {"", Rest1, Len1 + 4, NewC+4}; + Octets > 0 -> + Size = round(Octets/2), + {String, Rest2, Len2, NewC2} = + dec_sequence({1,2}, Rest1, Size, 'tk_ushort', + Len1 + 4, big, Buff, NewC+4), + {String, Rest2, Len2, NewC2}; + true -> + orber:dbg("[~p] cdr_decode:dec_wstring(~p);", + [?LINE, Rest1], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO}) + end; +dec_wstring(Version, Message, Len, ByteOrder, Buff, C) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, C), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + if + Size > 0 -> + {String, Rest2, Len2, NewC2} = dec_sequence(Version, Rest1, Size - 1, 'tk_wchar', + Len1 + 4, ByteOrder, Buff, NewC+4), + %% Remove the NULL character. + {_, Rest3} = cdrlib:dec_unsigned_short(ByteOrder, Rest2), + {String, Rest3, Len2 + 2, NewC2+2}; + Size == 0 -> + {"", Rest1, Len1 + 4, NewC+4}; + true -> + orber:dbg("[~p] cdr_decode:dec_wstring(~p);", + [?LINE, Rest1], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{completion_status=?COMPLETED_NO}) + end. + + +%%----------------------------------------------------------------- +%% Func: dec_union/9 +%%----------------------------------------------------------------- +%% ## NEW IIOP 1.2 ## +dec_union(Version, ?SYSTEM_TYPE, Name, DiscrTC, Default, ElementList, Bytes, Len, ByteOrder, Buff, C) -> + {Label, Rest1, Len1, NewC} = dec_type(DiscrTC, Version, Bytes, Len, ByteOrder, Buff, C), + {Value, Rest2, Len2, NewC3} = dec_union(Version, Label, ElementList, Default, + Rest1, Len1, ByteOrder, Buff, NewC), + {{Name, Label, Value}, Rest2, Len2, NewC3}; + + +dec_union(Version, IFRId, _, DiscrTC, Default, ElementList, Bytes, Len, ByteOrder, Buff, C) -> + {Label, Rest1, Len1, NewC} = dec_type(DiscrTC, Version, Bytes, Len, ByteOrder, Buff, C), + Result = dec_union(Version, stringify_enum(DiscrTC, Label), ElementList, Default, + Rest1, Len1, ByteOrder, Buff, NewC), + {Value, Rest2, Len2, NewC3} = case Result of + {default, R, L, NewC2} -> + dec_union(Version, default, ElementList, Default, + R, L, ByteOrder, Buff, NewC2); + X -> + X + end, + Name = ifrid_to_name(IFRId, ?IFR_UnionDef), + {{Name, Label, Value}, Rest2, Len2, NewC3}. + +dec_union(_, _, [], Default, Message, Len, _, _Buff, C) when Default < 0 -> + {undefined, Message, Len, C}; +dec_union(_, _, [], _Default, Message, Len, _, _Buff, C) -> + {default, Message, Len, C}; +dec_union(Version, Label, [{Label, _Name, Type}|_List], _Default, Message, Len, ByteOrder, Buff, C) -> + dec_type(Type, Version, Message, Len, ByteOrder, Buff, C); +dec_union(Version, Label, [_H|List], Default, Message, Len, ByteOrder, Buff, C) -> + dec_union(Version, Label, List, Default, Message, Len, ByteOrder, Buff, C). + +%%----------------------------------------------------------------- +%% Func: dec_struct/7 +%%----------------------------------------------------------------- +dec_struct(Version, "", "", TypeCodeList, Message, Len, ByteOrder, Buff, C) -> + {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C), + {list_to_tuple(Struct), Rest, Len1, NewC}; +dec_struct(Version, [], Name, TypeCodeList, Message, Len, ByteOrder, Buff, C) -> + %% This case is used when communicating with ORB:s which don't supply the IFRId + %% field in struct type codes (used in any) + {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C), + {list_to_tuple([list_to_atom(Name) |Struct]), Rest, Len1, NewC}; +dec_struct(Version, ?SYSTEM_TYPE, ShortName, TypeCodeList, Message, Len, ByteOrder, Buff, C) -> + {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C), + {list_to_tuple([ShortName |Struct]), Rest, Len1, NewC}; +dec_struct(Version, IFRId, _ShortName, TypeCodeList, Message, Len, ByteOrder, Buff, C) -> + Name = ifrid_to_name(IFRId, ?IFR_StructDef), + {Struct, Rest, Len1, NewC} = dec_struct1(Version, TypeCodeList, Message, Len, ByteOrder, Buff, C), + {list_to_tuple([Name |Struct]), Rest, Len1, NewC}. + +dec_struct1(_, [], Message, Len, _ByteOrder, _, C) -> + {[], Message, Len, C}; +dec_struct1(Version, [{_ElemName, ElemType} | TypeCodeList], Message, Len, ByteOrder, Buff, C) -> + {Element, Rest, Len1, NewC} = dec_type(ElemType, Version, Message, Len, ByteOrder, Buff, C), + {Struct, Rest1, Len2, NewC2} = dec_struct1(Version, TypeCodeList, Rest, Len1, ByteOrder, Buff, NewC), + {[Element |Struct], Rest1, Len2, NewC2}. + +ifrid_to_name([], Type) -> + orber:dbg("[~p] ~p:ifrid_to_name([], ~p). No Id supplied.", + [?LINE, ?MODULE, Type], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?CORBA_OMGVMCID bor 11), + completion_status=?COMPLETED_MAYBE}); +ifrid_to_name(Id, Type) -> + case orber:light_ifr() of + true -> + orber_ifr:get_module(Id, Type); + false -> + case catch ifrid_to_name_helper(Id, Type) of + {'EXCEPTION', E} -> + corba:raise(E); + {'EXIT',{aborted,{no_exists,_}}} -> + case orber:get_lightweight_nodes() of + false -> + orber:dbg("[~p] cdr_decode:ifrid_to_name(~p, ~p). IFRid not found.", + [?LINE, Id, Type], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}); + Nodes -> + {A,B,C} = now(), + random:seed(A,B,C), + L = length(Nodes), + IFR = get_ifr_node(Nodes, random:uniform(L), L), + list_to_atom('OrberApp_IFR':get_absolute_name(IFR, Id)) + end; + {'EXIT', Other} -> + orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). Unknown: ~p", + [?LINE, Id, Other], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}); + Name -> + list_to_atom(Name) + end + end. + +ifrid_to_name_helper(Id, ?IFR_UnionDef) -> + case mnesia:dirty_index_read(ir_UnionDef, Id, #ir_UnionDef.id) of + [#ir_UnionDef{absolute_name = [$:,$:|N]}] -> + change_colons_to_underscore(N, []); + Other -> + orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). IFR Id not found: ~p", + [?LINE, Id, Other], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 9), + completion_status=?COMPLETED_MAYBE}) + end; +ifrid_to_name_helper(Id, ?IFR_StructDef) -> + case mnesia:dirty_index_read(ir_StructDef, Id, #ir_StructDef.id) of + [#ir_StructDef{absolute_name = [$:,$:|N]}] -> + change_colons_to_underscore(N, []); + Other -> + orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). IFR Id not found: ~p", + [?LINE, Id, Other], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 10), + completion_status=?COMPLETED_MAYBE}) + end; +ifrid_to_name_helper(Id, ?IFR_ExceptionDef) -> + case mnesia:dirty_index_read(ir_ExceptionDef, Id, #ir_ExceptionDef.id) of + [#ir_ExceptionDef{absolute_name = [$:,$:|N]}] -> + change_colons_to_underscore(N, []); + Other -> + orber:dbg("[~p] cdr_decode:ifrid_to_name(~p). IFR Id not found: ~p", + [?LINE, Id, Other], ?DEBUG_LEVEL), + corba:raise(#'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 1), + completion_status=?COMPLETED_MAYBE}) + end. + +change_colons_to_underscore([$:, $: | T], Acc) -> + change_colons_to_underscore(T, [$_ |Acc]); +change_colons_to_underscore([H |T], Acc) -> + change_colons_to_underscore(T, [H |Acc]); +change_colons_to_underscore([], Acc) -> + lists:reverse(Acc). + +get_ifr_node([], _, _) -> + %% Were not able to contact any of the given nodes. + orber:dbg("[~p] cdr_decode:get_ifr_node([]). No Node available.", + [?LINE], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_MAYBE}); +get_ifr_node(Nodes, N, L) -> + Node = lists:nth(N, Nodes), + case catch corba:resolve_initial_references_remote("OrberIFR", [Node]) of + IFR when is_record(IFR, 'IOP_IOR') -> + IFR; + _ -> + %% Not able to commincate with the node. Try next one. + NewL = L-1, + get_ifr_node(lists:delete(Node, Nodes), random:uniform(NewL), NewL) + end. + + +%%----------------------------------------------------------------- +%% Func: dec_objref/4 +%%----------------------------------------------------------------- +dec_objref(Version, Message, Len, ByteOrder) -> + dec_objref(Version, Message, Len, ByteOrder, [], 0). +dec_objref(Version, Message, Len, ByteOrder, _Buff, C) -> + {IOR, Rest, Length} = iop_ior:decode(Version, Message, Len, ByteOrder), + {IOR, Rest, Length, C+Length-Len}. + +%%----------------------------------------------------------------- +%% Func: dec_system_exception/4 and dec_user_exception/4 +%%----------------------------------------------------------------- +dec_system_exception(Version, Message, Len, ByteOrder) when Version == {1,2} -> + {Rest0, Len0, _Counter} = dec_align(Message, Len, 8, Len), + {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Rest0, Len0, ByteOrder), + Name = orber_exceptions:get_name(TypeId, ?SYSTEM_EXCEPTION), + {Struct, _Rest2, Len2} = + dec_exception_1(Version, [{"minor",'tk_ulong'}, + {"completed", + {'tk_enum', "", "completion_status", + ["COMPLETED_YES", "COMPLETED_NO", + "COMPLETED_MAYBE"]}}], + Rest1, Len1, ByteOrder), + {list_to_tuple([Name, "" |Struct]), Len2}; +dec_system_exception(Version, Message, Len, ByteOrder) -> + {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Message, Len, ByteOrder), + Name = orber_exceptions:get_name(TypeId, ?SYSTEM_EXCEPTION), + {Struct, _Rest2, Len2} = + dec_exception_1(Version, [{"minor",'tk_ulong'}, + {"completed", + {'tk_enum', "", "completion_status", + ["COMPLETED_YES", "COMPLETED_NO", + "COMPLETED_MAYBE"]}}], + Rest1, Len1, ByteOrder), + {list_to_tuple([Name, "" |Struct]), Len2}. + +dec_user_exception(Version, Message, Len, ByteOrder) when Version == {1,2} -> + {Rest0, Len0, _Counter} = dec_align(Message, Len, 8, Len), + {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Rest0, Len0, ByteOrder), + Name = ifrid_to_name(TypeId, ?IFR_ExceptionDef), + {'tk_except', _, _, ElementList} = get_user_exception_type(TypeId), + {Struct, _Rest2, Len2} = dec_exception_1(Version, ElementList, Rest1, Len1, + ByteOrder), + {list_to_tuple([Name, TypeId |Struct]), Len2}; +dec_user_exception(Version, Message, Len, ByteOrder) -> + {TypeId, Rest1, Len1} = dec_type({'tk_string', 0}, Version, Message, Len, ByteOrder), + Name = ifrid_to_name(TypeId, ?IFR_ExceptionDef), + {'tk_except', _, _, ElementList} = get_user_exception_type(TypeId), + {Struct, _Rest2, Len2} = dec_exception_1(Version, ElementList, Rest1, Len1, + ByteOrder), + {list_to_tuple([Name, TypeId |Struct]), Len2}. + +dec_exception_1(_, [], Message, Len, _ByteOrder) -> + {[], Message, Len}; +dec_exception_1(Version, [{_ElemName, ElemType} | ElementList], Message, + Len, ByteOrder) -> + {Element, Rest, Len1} = dec_type(ElemType, Version, Message, Len, ByteOrder), + {Struct, Rest1, Len2} = dec_exception_1(Version, ElementList, Rest, Len1, + ByteOrder), + {[Element |Struct], Rest1, Len2}. + + +get_user_exception_type(TypeId) -> + case orber:light_ifr() of + true -> + orber_ifr:get_tc(TypeId, ?IFR_ExceptionDef); + false -> + case orber:get_lightweight_nodes() of + false -> + case mnesia:dirty_index_read(ir_ExceptionDef, TypeId, + #ir_ExceptionDef.id) of + [ExcDef] when is_record(ExcDef, ir_ExceptionDef) -> + ExcDef#ir_ExceptionDef.type; + Other -> + orber:dbg("[~p] cdr_decode:get_user_exception_type(~p). IFR Id not found: ~p", + [?LINE, TypeId, Other], ?DEBUG_LEVEL), + corba:raise(#'UNKNOWN'{minor=(?CORBA_OMGVMCID bor 1), + completion_status=?COMPLETED_MAYBE}) + end; + Nodes -> + {A,B,C} = now(), + random:seed(A,B,C), + L = length(Nodes), + IFR = get_ifr_node(Nodes, random:uniform(L), L), + 'OrberApp_IFR':get_user_exception_type(IFR, TypeId) + end + end. + +%%----------------------------------------------------------------- +%% Func: dec_type_code/4 +%%----------------------------------------------------------------- +dec_type_code(Version, Message, Len, ByteOrder, Buff, C) -> + {TypeNo, Message1, Len1, NewC} = dec_type('tk_ulong', Version, Message, Len, ByteOrder, Buff, C), + dec_type_code(TypeNo, Version, Message1, Len1, ByteOrder, Buff, NewC). + +%%----------------------------------------------------------------- +%% Func: dec_type_code/5 +%%----------------------------------------------------------------- +dec_type_code(0, _, Message, Len, _, _, C) -> + {'tk_null', Message, Len, C}; +dec_type_code(1, _, Message, Len, _, _, C) -> + {'tk_void', Message, Len, C}; +dec_type_code(2, _, Message, Len, _, _, C) -> + {'tk_short', Message, Len, C}; +dec_type_code(3, _, Message, Len, _, _, C) -> + {'tk_long', Message, Len, C}; +dec_type_code(23, _, Message, Len, _, _, C) -> + {'tk_longlong', Message, Len, C}; +dec_type_code(25, _, Message, Len, _, _, C) -> + {'tk_longdouble', Message, Len, C}; +dec_type_code(4, _, Message, Len, _, _, C) -> + {'tk_ushort', Message, Len, C}; +dec_type_code(5, _, Message, Len, _, _, C) -> + {'tk_ulong', Message, Len, C}; +dec_type_code(24, _, Message, Len, _, _, C) -> + {'tk_ulonglong', Message, Len, C}; +dec_type_code(6, _, Message, Len, _, _, C) -> + {'tk_float', Message, Len, C}; +dec_type_code(7, _, Message, Len, _, _, C) -> + {'tk_double', Message, Len, C}; +dec_type_code(8, _, Message, Len, _, _, C) -> + {'tk_boolean', Message, Len, C}; +dec_type_code(9, _, Message, Len, _, _, C) -> + {'tk_char', Message, Len, C}; +dec_type_code(26, _, Message, Len, _, _, C) -> + {'tk_wchar', Message, Len, C}; +dec_type_code(10, _, Message, Len, _, _, C) -> + {'tk_octet', Message, Len, C}; +dec_type_code(11, _, Message, Len, _, _, C) -> + {'tk_any', Message, Len, C}; +dec_type_code(12, _, Message, Len, _, _, C) -> + {'tk_TypeCode', Message, Len, C}; +dec_type_code(13, _, Message, Len, _, _, C) -> + {'tk_Principal', Message, Len, C}; +dec_type_code(14, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg get the byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_objref', RepId, Name}, Message1, Len1, NewC}; +dec_type_code(15, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg get the byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name, ElementList}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", + [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}, + {"element list", + {'tk_sequence', {'tk_struct', "","", + [{"member name", {'tk_string', 0}}, + {"member type", 'tk_TypeCode'}]}, + 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_struct', RepId, Name, ElementList}, Message1, Len1, NewC}; +dec_type_code(16, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg get the byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name, DiscrTC, Default}, Rest2, RestLen2, NewC} = + dec_type({'tk_struct', "", "", + [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}, + {"discriminant type", 'tk_TypeCode'}, + {"default used", 'tk_long'}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {ElementList, <<>>, _RestLen3, NewC2} = + dec_type({'tk_sequence', {'tk_struct', "","", + [{"label value", DiscrTC}, + {"member name", {'tk_string', 0}}, + {"member type", 'tk_TypeCode'}]}, 0}, + Version, Rest2, RestLen2, ByteOrder1, Buff, NewC), + NewElementList = + case check_enum(DiscrTC) of + true -> + lists:map(fun({L,N,T}) -> {atom_to_list(L),N,T} end, ElementList); + false -> + ElementList + end, + {{'tk_union', RepId, Name, DiscrTC, Default, NewElementList}, Message1, Len1, NewC2}; +dec_type_code(17, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg get the byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name, ElementList}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", + [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}, + {"element list", + {'tk_sequence', {'tk_string', 0}, 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_enum', RepId, Name, ElementList}, Message1, Len1, NewC}; +dec_type_code(18, Version, Message, Len, ByteOrder, Buff, C) -> + {MaxLength, Message1, Len1, NewC} = + dec_type('tk_ulong', Version, Message, Len, ByteOrder, Buff, C), + {{'tk_string', MaxLength}, Message1, Len1, NewC}; +dec_type_code(19, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg get the byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{ElemTC, MaxLength}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"element type", 'tk_TypeCode'}, + {"max length", 'tk_ulong'}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_sequence', ElemTC, MaxLength}, Message1, Len1, NewC}; +dec_type_code(20, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg get the byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{ElemTC, Length}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"element type", 'tk_TypeCode'}, + {"length", 'tk_ulong'}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_array', ElemTC, Length}, Message1, Len1, NewC}; +dec_type_code(21, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg ge a byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name, TC}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}, + {"TypeCode", 'tk_TypeCode'}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_alias', RepId, Name, TC}, Message1, Len1, NewC}; +dec_type_code(22, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + %% Decode marshalled parameters, eg get the byteorder first + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name, ElementList}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", + [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}, + {"element list", + {'tk_sequence', {'tk_struct', "","", + [{"member name", {'tk_string', 0}}, + {"member type", 'tk_TypeCode'}]}, + 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_except', RepId, Name, ElementList}, Message1, Len1, NewC}; +dec_type_code(27, Version, Message, Len, ByteOrder, Buff, C) -> + {MaxLength, Message1, Len1, NewC} = + dec_type('tk_ulong', Version, Message, Len, ByteOrder, Buff, C), + {{'tk_wstring', MaxLength}, Message1, Len1, NewC}; +dec_type_code(28, Version, Message, Len, ByteOrder, Buff, C) -> + {Digits, Message1, Len1, C1} = + dec_type('tk_ushort', Version, Message, Len, ByteOrder, Buff, C), + {Scale, Message2, Len2, C2} = + dec_type('tk_short', Version, Message1, Len1, ByteOrder, Buff, C1), + {{'tk_fixed', Digits, Scale}, Message2, Len2, C2}; +dec_type_code(29, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name, ValueModifier, TC, ElementList}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}, + {"ValueModifier", 'tk_short'}, + {"TypeCode", 'tk_TypeCode'}, + {"element list", + {'tk_sequence', + {'tk_struct', "","", + [{"member name", {'tk_string', 0}}, + {"member type", 'tk_TypeCode'}, + {"Visibility", 'tk_short'}]}, + 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_value', RepId, Name, ValueModifier, TC, ElementList}, Message1, Len1, NewC}; +dec_type_code(30, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name, TC}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}, + {"TypeCode", 'tk_TypeCode'}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_value_box', RepId, Name, TC}, Message1, Len1, NewC}; +dec_type_code(31, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"repository ID", {'tk_string', 0}}, + {"name", {'tk_string', 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_native', RepId, Name}, Message1, Len1, NewC}; +dec_type_code(32, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"RepositoryId", {'tk_string', 0}}, + {"name", {'tk_string', 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_abstract_interface', RepId, Name}, Message1, Len1, NewC}; +dec_type_code(33, Version, Message, Len, ByteOrder, Buff, C) -> + {ComplexParams, Message1, Len1, Ex} = decode_complex_tc_parameters(Version, Message, Len, ByteOrder), + {ByteOrder1, Rest1} = dec_byte_order(ComplexParams), + {{RepId, Name}, <<>>, _Len2, NewC} = + dec_type({'tk_struct', "", "", [{"RepositoryId", {'tk_string', 0}}, + {"name", {'tk_string', 0}}]}, + Version, Rest1, 1, ByteOrder1, Buff, C+1+Ex), + {{'tk_local_interface', RepId, Name}, Message1, Len1, NewC}; +dec_type_code(16#ffffffff, Version, Message, Len, ByteOrder, Buff, C) -> %% placeholder + {Indirection, Message1, Len1, NewC} = + dec_type('tk_long', Version, Message, Len, ByteOrder, Buff, C), + Position = C+Indirection, + <<_:Position/binary, SubBuff/binary>> = Buff, + {TC, _, _, _} = dec_type_code(Version, SubBuff, Position, ByteOrder, Buff, Position), + {TC, Message1, Len1, NewC}; +dec_type_code(Type, _, _, _, _, _, _) -> + orber:dbg("[~p] cdr_decode:dec_type_code(~p); No match.", + [?LINE, Type], ?DEBUG_LEVEL), + corba:raise(#'MARSHAL'{minor=(?ORBER_VMCID bor 8), completion_status=?COMPLETED_MAYBE}). + +check_enum({'tk_enum', _, _, _}) -> + true; +check_enum(_) -> + false. + + +decode_complex_tc_parameters(_Version, Message, Len, ByteOrder) -> + {Rest, Len1, NewC} = dec_align(Message, Len, 4, 0), + {Size, Rest1} = cdrlib:dec_unsigned_long(ByteOrder, Rest), + <<OctetSeq:Size/binary, Rest2/binary>> = Rest1, + {OctetSeq, Rest2, Len1+4+Size, NewC+4}. + +%%----------------------------------------------------------------- +%% Func: dec_align/3 +%% Args: +%% R - The byte sequence that shall be aligned. +%% Len - The number of bytes read so far. +%% Alignment - The alignment as an integer (for example: 2,4,8). +%% Returns: +%% An aligned byte sequence. +%%----------------------------------------------------------------- +dec_align(R, Len, Alignment, C) -> + Rem = Len rem Alignment, + if Rem == 0 -> + {R, Len, C}; + true -> + Diff = Alignment - Rem, + <<_:Diff/binary,Rest/binary>> = R, + {Rest, Len + Diff, C + Diff} + end. + +%%---------------- EOF MODULE ---------------------------------------- |