From 606f37be8dbd1dff3d135e3bdafd245c84d67860 Mon Sep 17 00:00:00 2001 From: aebersol Date: Mon, 20 Dec 2021 22:17:25 +0100 Subject: [PATCH] Initial Import from SVN --- CMakeLists.txt | 180 + TODO.txt | 184 + adt/CMakeLists.txt | 24 + adt/asn1_constraint.cpp | 293 ++ adt/asn1_constraint.h | 226 ++ adt/asn1_constraint.inc | 39 + adt/asn1_meta.h | 46 + adt/asn1_meta.inc | 14 + adt/asn1_module.cpp | 159 + adt/asn1_module.h | 113 + adt/asn1_node.cpp | 742 ++++ adt/asn1_node.h | 397 ++ adt/asn1_node_alternative_choice.h | 16 + adt/asn1_node_assignment.cpp | 69 + adt/asn1_node_assignment.h | 54 + adt/asn1_node_choice.cpp | 129 + adt/asn1_node_choice.h | 40 + adt/asn1_node_classdef.cpp | 452 +++ adt/asn1_node_classdef.h | 364 ++ adt/asn1_node_constructed.cpp | 84 + adt/asn1_node_constructed.h | 66 + adt/asn1_node_exports.h | 25 + adt/asn1_node_field.cpp | 153 + adt/asn1_node_field.h | 120 + adt/asn1_node_imports.cpp | 59 + adt/asn1_node_imports.h | 47 + adt/asn1_node_object.cpp | 66 + adt/asn1_node_object.h | 37 + adt/asn1_node_parameters.cpp | 133 + adt/asn1_node_parameters.h | 102 + adt/asn1_node_primitive.cpp | 218 ++ adt/asn1_node_primitive.h | 106 + adt/asn1_node_selection.h | 33 + adt/asn1_node_sequence.cpp | 59 + adt/asn1_node_sequence.h | 37 + adt/asn1_node_sequence_of.h | 21 + adt/asn1_node_set.h | 17 + adt/asn1_node_set_of.h | 18 + adt/asn1_node_typenode.cpp | 77 + adt/asn1_node_typenode.h | 63 + adt/asn1_node_typeref.cpp | 301 ++ adt/asn1_node_typeref.h | 87 + adt/asn1_node_valuetype.cpp | 97 + adt/asn1_node_valuetype.h | 87 + adt/asn1_recursive_visitor.h | 640 ++++ adt/asn1_reference.cpp | 199 + adt/asn1_reference.h | 197 + adt/asn1_resolver.cpp | 494 +++ adt/asn1_resolver.h | 68 + adt/asn1_type.h | 113 + adt/asn1_type.inc | 97 + adt/asn1_value.cpp | 111 + adt/asn1_value.h | 61 + adt/asn1_visitor.h | 164 + cmip/CMIPActionListener.h | 7 + cmip/CMIPAgent.cpp | 151 + cmip/CMIPAgent.h | 35 + cmip/CMIPEventReportListener.h | 24 + cmip/CMIPListener.h | 36 + cmip/CMIPStack.cpp | 374 ++ cmip/CMIPStack.h | 94 + cmip/CMakeLists.txt | 164 + cmip/main.cpp | 210 ++ cmip/modules.txt | 4 + csta/CMakeLists.txt | 100 + csta/main.cpp | 83 + csta/modules.txt | 266 ++ cstav1/AtraceCurlReader.cpp | 13 + cstav1/AtraceDecoder.h | 43 + cstav1/AtraceListener.h | 50 + cstav1/AtraceMsgs.h | 60 + cstav1/AtraceReader.h | 39 + cstav1/CExpatImpl.h | 862 +++++ cstav1/CMakeLists.txt | 541 +++ cstav1/Call.h | 29 + cstav1/Controler.cpp | 1127 ++++++ cstav1/Controler.h | 43 + cstav1/CstaInsightLog.cpp | 2 + cstav1/CstaInsightLog.h | 102 + cstav1/HeaderView.cpp | 127 + cstav1/HeaderView.h | 61 + cstav1/IconFactory.cpp | 45 + cstav1/IconFactory.h | 21 + cstav1/Model.cpp | 182 + cstav1/Model.h | 111 + cstav1/Observer.h | 17 + cstav1/Packet.cpp | 264 ++ cstav1/Packet.h | 61 + cstav1/Pcap.cpp | 73 + cstav1/Pcap.h | 33 + cstav1/PrivateEla.cpp | 12 + cstav1/PrivateEla.h | 40 + cstav1/SequenceView.cpp | 731 ++++ cstav1/SequenceView.h | 93 + cstav1/SniffHeader.h | 68 + cstav1/TLMsg.cpp | 52 + cstav1/TLMsg.h | 70 + cstav1/TLMsgCsta.h | 17 + cstav1/TLMsgSip.h | 13 + cstav1/TLMsgXml.h | 13 + cstav1/Timeline.cpp | 119 + cstav1/Timeline.h | 36 + cstav1/XMLMessage.h | 72 + cstav1/cstaspyui.fl | 688 ++++ cstav1/data/double_appel_csta.pcap | Bin 0 -> 8272 bytes cstav1/data/listen_vm_vhe_csta.pcap | Bin 0 -> 10433 bytes .../ma_change_filtering_level_3_csta.pcap | Bin 0 -> 5261 bytes ...ing_level_filtering_to_screening_csta.pcap | Bin 0 -> 1248 bytes ...iltering_level_none_to_filtering_csta.pcap | Bin 0 -> 34393 bytes cstav1/data/make_call_csta.pcap | Bin 0 -> 11366 bytes cstav1/data/make_call_redirect_vm_csta.pcap | Bin 0 -> 12225 bytes ...ip_transfer_call_withoutsip_releasing.pcap | Bin 0 -> 122429 bytes .../data/myicoffice_msip130_make_call_ua.pcap | Bin 0 -> 70092 bytes cstav1/data/ots_start_csta.pcap | Bin 0 -> 54185 bytes cstav1/data/sip130_make_call_ua.pcap | Bin 0 -> 36628 bytes cstav1/images/Funnel_16.png | Bin 0 -> 604 bytes cstav1/images/Lighting_16.png | Bin 0 -> 576 bytes cstav1/images/RequestSoap_16.png | Bin 0 -> 813 bytes cstav1/images/Request_16.png | Bin 0 -> 500 bytes cstav1/images/ResponseError_16.png | Bin 0 -> 621 bytes cstav1/images/ResponseReject_16.png | Bin 0 -> 731 bytes cstav1/images/ResponseSoap_16.png | Bin 0 -> 830 bytes cstav1/images/Response_16.png | Bin 0 -> 505 bytes cstav1/images/Server_24.png | Bin 0 -> 622 bytes cstav1/images/Server_48.png | Bin 0 -> 1163 bytes cstav1/images/Sip_16.png | Bin 0 -> 754 bytes cstav1/images/VTSip_24.png | Bin 0 -> 965 bytes cstav1/images/VTSip_48.png | Bin 0 -> 2194 bytes cstav1/images/VT_24.png | Bin 0 -> 766 bytes cstav1/images/VT_48.png | Bin 0 -> 1536 bytes cstav1/main.cpp | 158 + cstav1/modules.txt | 14 + cstav1/sigslot.h | 2521 +++++++++++++ gsm/CMakeLists.txt | 99 + gsm/modules.txt | 5 + gsmmap/CMakeLists.txt | 50 + gsmmap/module.txt | 4 + h248/CMakeLists.txt | 156 + h248/main.cpp | 41 + h248/modules.txt | 1 + h323/CMakeLists.txt | 95 + h323/modules.txt | 3 + ledger/CMakeLists.txt | 150 + ledger/main.cpp | 60 + ledger/modules.txt | 6 + libgen/CMakeLists.txt | 69 + libgen/asn1_gen_auto_tag.cpp | 393 ++ libgen/asn1_gen_auto_tag.h | 46 + libgen/asn1_gen_codec_cpp.cpp | 1517 ++++++++ libgen/asn1_gen_codec_cpp.h | 158 + libgen/asn1_gen_config.h.in | 9 + libgen/asn1_gen_constraints.cpp | 57 + libgen/asn1_gen_constraints.h | 75 + libgen/asn1_gen_cpp.cpp | 572 +++ libgen/asn1_gen_cpp.h | 131 + libgen/asn1_gen_hpp.cpp | 1691 +++++++++ libgen/asn1_gen_hpp.h | 119 + libgen/asn1_gen_optimizer.cpp | 918 +++++ libgen/asn1_gen_optimizer.h | 40 + libgen/asn1_generator.cpp | 472 +++ libgen/asn1_generator.h | 263 ++ libgen/asn1_generator_helper.h | 42 + libgen/cpp/cgcpp_helper.cpp | 64 + libgen/cpp/cgcpp_helper.h | 53 + libgen/cpp/cgcpph_bitstring.cpp | 239 ++ libgen/cpp/cgcpph_bitstring.h | 38 + libgen/cpp/cgcpph_boolean.cpp | 242 ++ libgen/cpp/cgcpph_boolean.h | 42 + libgen/cpp/cgcpph_choice.cpp | 1159 ++++++ libgen/cpp/cgcpph_choice.h | 101 + libgen/cpp/cgcpph_enumerated.cpp | 264 ++ libgen/cpp/cgcpph_enumerated.h | 42 + libgen/cpp/cgcpph_import.cpp | 87 + libgen/cpp/cgcpph_import.h | 45 + libgen/cpp/cgcpph_integer.cpp | 264 ++ libgen/cpp/cgcpph_integer.h | 39 + libgen/cpp/cgcpph_object.cpp | 449 +++ libgen/cpp/cgcpph_object.h | 63 + libgen/cpp/cgcpph_objectset.cpp | 123 + libgen/cpp/cgcpph_objectset.h | 39 + libgen/cpp/cgcpph_octetstring.cpp | 221 ++ libgen/cpp/cgcpph_octetstring.h | 39 + libgen/cpp/cgcpph_oid.cpp | 240 ++ libgen/cpp/cgcpph_oid.h | 42 + libgen/cpp/cgcpph_primitive.cpp | 292 ++ libgen/cpp/cgcpph_primitive.h | 56 + libgen/cpp/cgcpph_real.cpp | 123 + libgen/cpp/cgcpph_real.h | 41 + libgen/cpp/cgcpph_sequence.cpp | 598 +++ libgen/cpp/cgcpph_sequence.h | 71 + libgen/cpp/cgcpph_sequenceof.cpp | 311 ++ libgen/cpp/cgcpph_sequenceof.h | 43 + libgen/cpp/cgcpph_set.cpp | 254 ++ libgen/cpp/cgcpph_set.h | 45 + libgen/cpp/cgcpph_setof.cpp | 218 ++ libgen/cpp/cgcpph_setof.h | 43 + libgen/cpp/cgcpph_string.cpp | 297 ++ libgen/cpp/cgcpph_string.h | 40 + libgen/cpp/cgcpph_typeref.cpp | 443 +++ libgen/cpp/cgcpph_typeref.h | 49 + libgen/cpp/cgh_construct.cpp | 1097 ++++++ libgen/cpp/cgh_construct.h | 68 + libgen/cpp/cgh_hconstruct.cpp | 65 + libgen/cpp/cgh_hconstruct.h | 75 + libgen/cpp/cgh_object.cpp | 220 ++ libgen/cpp/cgh_object.h | 53 + libgen/cpp/cgh_value.cpp | 77 + libgen/cpp/cgh_value.h | 40 + libgen/cpp/cghpp_helper.cpp | 77 + libgen/cpp/cghpp_helper.h | 80 + libgen/cpp/cghpph_bitstring.cpp | 122 + libgen/cpp/cghpph_bitstring.h | 42 + libgen/cpp/cghpph_boolean.cpp | 105 + libgen/cpp/cghpph_boolean.h | 42 + libgen/cpp/cghpph_choice.cpp | 417 +++ libgen/cpp/cghpph_choice.h | 55 + libgen/cpp/cghpph_classdef.cpp | 608 +++ libgen/cpp/cghpph_classdef.h | 56 + libgen/cpp/cghpph_enumerated.cpp | 124 + libgen/cpp/cghpph_enumerated.h | 41 + libgen/cpp/cghpph_import.cpp | 234 ++ libgen/cpp/cghpph_import.h | 43 + libgen/cpp/cghpph_integer.cpp | 145 + libgen/cpp/cghpph_integer.h | 41 + libgen/cpp/cghpph_object.cpp | 229 ++ libgen/cpp/cghpph_object.h | 53 + libgen/cpp/cghpph_octetstring.cpp | 126 + libgen/cpp/cghpph_octetstring.h | 38 + libgen/cpp/cghpph_oid.cpp | 140 + libgen/cpp/cghpph_oid.h | 44 + libgen/cpp/cghpph_primitive.cpp | 155 + libgen/cpp/cghpph_primitive.h | 41 + libgen/cpp/cghpph_real.cpp | 118 + libgen/cpp/cghpph_real.h | 41 + libgen/cpp/cghpph_sequence.cpp | 337 ++ libgen/cpp/cghpph_sequence.h | 46 + libgen/cpp/cghpph_sequenceof.cpp | 163 + libgen/cpp/cghpph_sequenceof.h | 41 + libgen/cpp/cghpph_set.cpp | 134 + libgen/cpp/cghpph_set.h | 40 + libgen/cpp/cghpph_setof.cpp | 165 + libgen/cpp/cghpph_setof.h | 41 + libgen/cpp/cghpph_string.cpp | 143 + libgen/cpp/cghpph_string.h | 37 + libgen/cpp/cghpph_typeref.cpp | 332 ++ libgen/cpp/cghpph_typeref.h | 49 + libgen/cpp/cghpph_value.cpp | 77 + libgen/cpp/cghpph_value.h | 40 + libgen/js/asn1_gen_js.cpp | 1049 ++++++ libgen/js/asn1_gen_js.h | 93 + libgen/lds/asn1_gen_lds.cpp | 347 ++ libgen/lds/asn1_gen_lds.h | 76 + libgen/uml/asn1_gen_uml.cpp | 1274 +++++++ libgen/uml/asn1_gen_uml.h | 97 + libparser/CMakeLists.txt | 60 + libparser/asn1.l | 393 ++ libparser/asn1.y | 3330 +++++++++++++++++ libparser/asn1_parser.cpp | 274 ++ libparser/asn1_parser.h | 107 + libparser/asn1_parser_listener.h | 27 + main.cpp | 375 ++ megaco/CMakeLists.txt | 129 + megaco/main.cpp | 100 + megaco/modules.txt | 1 + optionparser.h | 2829 ++++++++++++++ pasn1/parser.i | 47 + pkix/CMakeLists.txt | 35 + pkix/main_pkix.cpp | 62 + pkix/result.txt | 226 ++ pkix/sample-Certificate-1.der | Bin 0 -> 1128 bytes rtasn1/CMakeLists.txt | 71 + rtasn1/asn1.h | 86 + rtasn1/asn1_codec.h | 40 + rtasn1/asn1_codec_ber.cpp | 1126 ++++++ rtasn1/asn1_codec_ber.h | 239 ++ rtasn1/asn1_codec_jer.cpp | 1259 +++++++ rtasn1/asn1_codec_jer.h | 275 ++ rtasn1/asn1_codec_oer.cpp | 456 +++ rtasn1/asn1_codec_oer.h | 127 + rtasn1/asn1_codec_per.cpp | 469 +++ rtasn1/asn1_codec_per.h | 126 + rtasn1/asn1_config.h.in | 20 + rtasn1/asn1_context.cpp | 125 + rtasn1/asn1_context.h | 199 + rtasn1/asn1_debug.h | 89 + rtasn1/asn1_errors.h | 23 + rtasn1/asn1_rose.h | 239 ++ rtasn1/asn1_tag.h | 58 + rtasn1/asn1_types.cpp | 1164 ++++++ rtasn1/asn1_types.h | 1098 ++++++ rtasn1/asn1_types.hpp | 148 + rtasn1/asn1_types.inc | 39 + rtasn1/cjson/LICENSE | 20 + rtasn1/cjson/README | 247 ++ rtasn1/cjson/cJSON.c | 596 +++ rtasn1/cjson/cJSON.h | 143 + rtasn1/cjson/test.c | 156 + rtasn1/cjson/tests/test1 | 22 + rtasn1/cjson/tests/test2 | 11 + rtasn1/cjson/tests/test3 | 26 + rtasn1/cjson/tests/test4 | 88 + rtasn1/cjson/tests/test5 | 27 + rtasn1/cpp/CMakeLists.txt | 21 + rtasn1/cpp/prim_GeneralizedTime.h | 26 + rtasn1/cpp/prim_UTCTime.h | 27 + rtasn1/cpp/prim_oid.cpp | 215 ++ rtasn1/cpp/prim_oid.h | 57 + rtasn1/json_token.h.inc | 19 + rtasn1/prim_types.cpp | 135 + rtasn1/prim_types.h | 449 +++ tests/CMakeLists.txt | 136 + tests/UNIT-TEST-basic-types-choice.cpp | 324 ++ tests/UNIT-TEST-basic-types-choice.h | 70 + tests/UNIT-TEST-basic-types-enum.cpp | 65 + tests/UNIT-TEST-basic-types-enum.h | 33 + tests/UNIT-TEST-basic-types-explicit.cpp | 126 + tests/UNIT-TEST-basic-types-explicit.h | 43 + tests/UNIT-TEST-basic-types-implicit.cpp | 80 + tests/UNIT-TEST-basic-types-implicit.h | 35 + tests/UNIT-TEST-basic-types-optional.cpp | 432 +++ tests/UNIT-TEST-basic-types-optional.h | 63 + tests/UNIT-TEST-basic-types-sequence.cpp | 88 + tests/UNIT-TEST-basic-types-sequence.h | 39 + tests/UNIT-TEST-basic-types-set.cpp | 89 + tests/UNIT-TEST-basic-types-set.h | 39 + tests/UNIT-TEST-basic-types-tagged.cpp | 291 ++ tests/UNIT-TEST-basic-types-tagged.h | 75 + tests/UNIT-TEST-basic-types.cpp | 280 ++ tests/UNIT-TEST-basic-types.h | 68 + tests/UNIT-TEST-ber-primary-types.cpp | 575 +++ tests/UNIT-TEST-ber-primary-types.h | 139 + tests/UNIT-TEST-private-types-choice.cpp | 175 + tests/UNIT-TEST-private-types-choice.h | 45 + tests/UNIT-TEST-type-parameter.h | 29 + tests/main_asn1_type_sizes.cpp | 62 + tests/main_test.cpp | 50 + tests/modules.txt | 11 + tests/poc-codec.h | 22 + tests/poc-codec.hpp | 4 + tests/source.asn1 | 872 +++++ 340 files changed, 63639 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 TODO.txt create mode 100644 adt/CMakeLists.txt create mode 100644 adt/asn1_constraint.cpp create mode 100644 adt/asn1_constraint.h create mode 100644 adt/asn1_constraint.inc create mode 100644 adt/asn1_meta.h create mode 100644 adt/asn1_meta.inc create mode 100644 adt/asn1_module.cpp create mode 100644 adt/asn1_module.h create mode 100644 adt/asn1_node.cpp create mode 100644 adt/asn1_node.h create mode 100644 adt/asn1_node_alternative_choice.h create mode 100644 adt/asn1_node_assignment.cpp create mode 100644 adt/asn1_node_assignment.h create mode 100644 adt/asn1_node_choice.cpp create mode 100644 adt/asn1_node_choice.h create mode 100644 adt/asn1_node_classdef.cpp create mode 100644 adt/asn1_node_classdef.h create mode 100644 adt/asn1_node_constructed.cpp create mode 100644 adt/asn1_node_constructed.h create mode 100644 adt/asn1_node_exports.h create mode 100644 adt/asn1_node_field.cpp create mode 100644 adt/asn1_node_field.h create mode 100644 adt/asn1_node_imports.cpp create mode 100644 adt/asn1_node_imports.h create mode 100644 adt/asn1_node_object.cpp create mode 100644 adt/asn1_node_object.h create mode 100644 adt/asn1_node_parameters.cpp create mode 100644 adt/asn1_node_parameters.h create mode 100644 adt/asn1_node_primitive.cpp create mode 100644 adt/asn1_node_primitive.h create mode 100644 adt/asn1_node_selection.h create mode 100644 adt/asn1_node_sequence.cpp create mode 100644 adt/asn1_node_sequence.h create mode 100644 adt/asn1_node_sequence_of.h create mode 100644 adt/asn1_node_set.h create mode 100644 adt/asn1_node_set_of.h create mode 100644 adt/asn1_node_typenode.cpp create mode 100644 adt/asn1_node_typenode.h create mode 100644 adt/asn1_node_typeref.cpp create mode 100644 adt/asn1_node_typeref.h create mode 100644 adt/asn1_node_valuetype.cpp create mode 100644 adt/asn1_node_valuetype.h create mode 100644 adt/asn1_recursive_visitor.h create mode 100644 adt/asn1_reference.cpp create mode 100644 adt/asn1_reference.h create mode 100644 adt/asn1_resolver.cpp create mode 100644 adt/asn1_resolver.h create mode 100644 adt/asn1_type.h create mode 100644 adt/asn1_type.inc create mode 100644 adt/asn1_value.cpp create mode 100644 adt/asn1_value.h create mode 100644 adt/asn1_visitor.h create mode 100644 cmip/CMIPActionListener.h create mode 100644 cmip/CMIPAgent.cpp create mode 100644 cmip/CMIPAgent.h create mode 100644 cmip/CMIPEventReportListener.h create mode 100644 cmip/CMIPListener.h create mode 100644 cmip/CMIPStack.cpp create mode 100644 cmip/CMIPStack.h create mode 100644 cmip/CMakeLists.txt create mode 100644 cmip/main.cpp create mode 100644 cmip/modules.txt create mode 100644 csta/CMakeLists.txt create mode 100644 csta/main.cpp create mode 100644 csta/modules.txt create mode 100644 cstav1/AtraceCurlReader.cpp create mode 100644 cstav1/AtraceDecoder.h create mode 100644 cstav1/AtraceListener.h create mode 100644 cstav1/AtraceMsgs.h create mode 100644 cstav1/AtraceReader.h create mode 100644 cstav1/CExpatImpl.h create mode 100644 cstav1/CMakeLists.txt create mode 100644 cstav1/Call.h create mode 100644 cstav1/Controler.cpp create mode 100644 cstav1/Controler.h create mode 100644 cstav1/CstaInsightLog.cpp create mode 100644 cstav1/CstaInsightLog.h create mode 100644 cstav1/HeaderView.cpp create mode 100644 cstav1/HeaderView.h create mode 100644 cstav1/IconFactory.cpp create mode 100644 cstav1/IconFactory.h create mode 100644 cstav1/Model.cpp create mode 100644 cstav1/Model.h create mode 100644 cstav1/Observer.h create mode 100644 cstav1/Packet.cpp create mode 100644 cstav1/Packet.h create mode 100644 cstav1/Pcap.cpp create mode 100644 cstav1/Pcap.h create mode 100644 cstav1/PrivateEla.cpp create mode 100644 cstav1/PrivateEla.h create mode 100644 cstav1/SequenceView.cpp create mode 100644 cstav1/SequenceView.h create mode 100644 cstav1/SniffHeader.h create mode 100644 cstav1/TLMsg.cpp create mode 100644 cstav1/TLMsg.h create mode 100644 cstav1/TLMsgCsta.h create mode 100644 cstav1/TLMsgSip.h create mode 100644 cstav1/TLMsgXml.h create mode 100644 cstav1/Timeline.cpp create mode 100644 cstav1/Timeline.h create mode 100644 cstav1/XMLMessage.h create mode 100644 cstav1/cstaspyui.fl create mode 100755 cstav1/data/double_appel_csta.pcap create mode 100755 cstav1/data/listen_vm_vhe_csta.pcap create mode 100755 cstav1/data/ma_change_filtering_level_3_csta.pcap create mode 100755 cstav1/data/ma_change_filtering_level_filtering_to_screening_csta.pcap create mode 100755 cstav1/data/ma_change_filtering_level_none_to_filtering_csta.pcap create mode 100755 cstav1/data/make_call_csta.pcap create mode 100755 cstav1/data/make_call_redirect_vm_csta.pcap create mode 100755 cstav1/data/myicoffice_monitor_sip_transfer_call_withoutsip_releasing.pcap create mode 100755 cstav1/data/myicoffice_msip130_make_call_ua.pcap create mode 100755 cstav1/data/ots_start_csta.pcap create mode 100755 cstav1/data/sip130_make_call_ua.pcap create mode 100755 cstav1/images/Funnel_16.png create mode 100755 cstav1/images/Lighting_16.png create mode 100755 cstav1/images/RequestSoap_16.png create mode 100755 cstav1/images/Request_16.png create mode 100755 cstav1/images/ResponseError_16.png create mode 100755 cstav1/images/ResponseReject_16.png create mode 100755 cstav1/images/ResponseSoap_16.png create mode 100755 cstav1/images/Response_16.png create mode 100755 cstav1/images/Server_24.png create mode 100755 cstav1/images/Server_48.png create mode 100755 cstav1/images/Sip_16.png create mode 100755 cstav1/images/VTSip_24.png create mode 100755 cstav1/images/VTSip_48.png create mode 100755 cstav1/images/VT_24.png create mode 100755 cstav1/images/VT_48.png create mode 100644 cstav1/main.cpp create mode 100644 cstav1/modules.txt create mode 100755 cstav1/sigslot.h create mode 100644 gsm/CMakeLists.txt create mode 100644 gsm/modules.txt create mode 100644 gsmmap/CMakeLists.txt create mode 100644 gsmmap/module.txt create mode 100644 h248/CMakeLists.txt create mode 100644 h248/main.cpp create mode 100644 h248/modules.txt create mode 100644 h323/CMakeLists.txt create mode 100644 h323/modules.txt create mode 100644 ledger/CMakeLists.txt create mode 100644 ledger/main.cpp create mode 100644 ledger/modules.txt create mode 100644 libgen/CMakeLists.txt create mode 100644 libgen/asn1_gen_auto_tag.cpp create mode 100644 libgen/asn1_gen_auto_tag.h create mode 100644 libgen/asn1_gen_codec_cpp.cpp create mode 100644 libgen/asn1_gen_codec_cpp.h create mode 100644 libgen/asn1_gen_config.h.in create mode 100644 libgen/asn1_gen_constraints.cpp create mode 100644 libgen/asn1_gen_constraints.h create mode 100644 libgen/asn1_gen_cpp.cpp create mode 100644 libgen/asn1_gen_cpp.h create mode 100644 libgen/asn1_gen_hpp.cpp create mode 100644 libgen/asn1_gen_hpp.h create mode 100644 libgen/asn1_gen_optimizer.cpp create mode 100644 libgen/asn1_gen_optimizer.h create mode 100644 libgen/asn1_generator.cpp create mode 100644 libgen/asn1_generator.h create mode 100644 libgen/asn1_generator_helper.h create mode 100644 libgen/cpp/cgcpp_helper.cpp create mode 100644 libgen/cpp/cgcpp_helper.h create mode 100644 libgen/cpp/cgcpph_bitstring.cpp create mode 100644 libgen/cpp/cgcpph_bitstring.h create mode 100644 libgen/cpp/cgcpph_boolean.cpp create mode 100644 libgen/cpp/cgcpph_boolean.h create mode 100644 libgen/cpp/cgcpph_choice.cpp create mode 100644 libgen/cpp/cgcpph_choice.h create mode 100644 libgen/cpp/cgcpph_enumerated.cpp create mode 100644 libgen/cpp/cgcpph_enumerated.h create mode 100644 libgen/cpp/cgcpph_import.cpp create mode 100644 libgen/cpp/cgcpph_import.h create mode 100644 libgen/cpp/cgcpph_integer.cpp create mode 100644 libgen/cpp/cgcpph_integer.h create mode 100644 libgen/cpp/cgcpph_object.cpp create mode 100644 libgen/cpp/cgcpph_object.h create mode 100644 libgen/cpp/cgcpph_objectset.cpp create mode 100644 libgen/cpp/cgcpph_objectset.h create mode 100644 libgen/cpp/cgcpph_octetstring.cpp create mode 100644 libgen/cpp/cgcpph_octetstring.h create mode 100644 libgen/cpp/cgcpph_oid.cpp create mode 100644 libgen/cpp/cgcpph_oid.h create mode 100644 libgen/cpp/cgcpph_primitive.cpp create mode 100644 libgen/cpp/cgcpph_primitive.h create mode 100644 libgen/cpp/cgcpph_real.cpp create mode 100644 libgen/cpp/cgcpph_real.h create mode 100644 libgen/cpp/cgcpph_sequence.cpp create mode 100644 libgen/cpp/cgcpph_sequence.h create mode 100644 libgen/cpp/cgcpph_sequenceof.cpp create mode 100644 libgen/cpp/cgcpph_sequenceof.h create mode 100644 libgen/cpp/cgcpph_set.cpp create mode 100644 libgen/cpp/cgcpph_set.h create mode 100644 libgen/cpp/cgcpph_setof.cpp create mode 100644 libgen/cpp/cgcpph_setof.h create mode 100644 libgen/cpp/cgcpph_string.cpp create mode 100644 libgen/cpp/cgcpph_string.h create mode 100644 libgen/cpp/cgcpph_typeref.cpp create mode 100644 libgen/cpp/cgcpph_typeref.h create mode 100644 libgen/cpp/cgh_construct.cpp create mode 100644 libgen/cpp/cgh_construct.h create mode 100644 libgen/cpp/cgh_hconstruct.cpp create mode 100644 libgen/cpp/cgh_hconstruct.h create mode 100644 libgen/cpp/cgh_object.cpp create mode 100644 libgen/cpp/cgh_object.h create mode 100644 libgen/cpp/cgh_value.cpp create mode 100644 libgen/cpp/cgh_value.h create mode 100644 libgen/cpp/cghpp_helper.cpp create mode 100644 libgen/cpp/cghpp_helper.h create mode 100644 libgen/cpp/cghpph_bitstring.cpp create mode 100644 libgen/cpp/cghpph_bitstring.h create mode 100644 libgen/cpp/cghpph_boolean.cpp create mode 100644 libgen/cpp/cghpph_boolean.h create mode 100644 libgen/cpp/cghpph_choice.cpp create mode 100644 libgen/cpp/cghpph_choice.h create mode 100644 libgen/cpp/cghpph_classdef.cpp create mode 100644 libgen/cpp/cghpph_classdef.h create mode 100644 libgen/cpp/cghpph_enumerated.cpp create mode 100644 libgen/cpp/cghpph_enumerated.h create mode 100644 libgen/cpp/cghpph_import.cpp create mode 100644 libgen/cpp/cghpph_import.h create mode 100644 libgen/cpp/cghpph_integer.cpp create mode 100644 libgen/cpp/cghpph_integer.h create mode 100644 libgen/cpp/cghpph_object.cpp create mode 100644 libgen/cpp/cghpph_object.h create mode 100644 libgen/cpp/cghpph_octetstring.cpp create mode 100644 libgen/cpp/cghpph_octetstring.h create mode 100644 libgen/cpp/cghpph_oid.cpp create mode 100644 libgen/cpp/cghpph_oid.h create mode 100644 libgen/cpp/cghpph_primitive.cpp create mode 100644 libgen/cpp/cghpph_primitive.h create mode 100644 libgen/cpp/cghpph_real.cpp create mode 100644 libgen/cpp/cghpph_real.h create mode 100644 libgen/cpp/cghpph_sequence.cpp create mode 100644 libgen/cpp/cghpph_sequence.h create mode 100644 libgen/cpp/cghpph_sequenceof.cpp create mode 100644 libgen/cpp/cghpph_sequenceof.h create mode 100644 libgen/cpp/cghpph_set.cpp create mode 100644 libgen/cpp/cghpph_set.h create mode 100644 libgen/cpp/cghpph_setof.cpp create mode 100644 libgen/cpp/cghpph_setof.h create mode 100644 libgen/cpp/cghpph_string.cpp create mode 100644 libgen/cpp/cghpph_string.h create mode 100644 libgen/cpp/cghpph_typeref.cpp create mode 100644 libgen/cpp/cghpph_typeref.h create mode 100644 libgen/cpp/cghpph_value.cpp create mode 100644 libgen/cpp/cghpph_value.h create mode 100644 libgen/js/asn1_gen_js.cpp create mode 100644 libgen/js/asn1_gen_js.h create mode 100644 libgen/lds/asn1_gen_lds.cpp create mode 100644 libgen/lds/asn1_gen_lds.h create mode 100644 libgen/uml/asn1_gen_uml.cpp create mode 100644 libgen/uml/asn1_gen_uml.h create mode 100644 libparser/CMakeLists.txt create mode 100644 libparser/asn1.l create mode 100644 libparser/asn1.y create mode 100644 libparser/asn1_parser.cpp create mode 100644 libparser/asn1_parser.h create mode 100644 libparser/asn1_parser_listener.h create mode 100644 main.cpp create mode 100644 megaco/CMakeLists.txt create mode 100644 megaco/main.cpp create mode 100644 megaco/modules.txt create mode 100755 optionparser.h create mode 100644 pasn1/parser.i create mode 100644 pkix/CMakeLists.txt create mode 100644 pkix/main_pkix.cpp create mode 100644 pkix/result.txt create mode 100644 pkix/sample-Certificate-1.der create mode 100644 rtasn1/CMakeLists.txt create mode 100644 rtasn1/asn1.h create mode 100644 rtasn1/asn1_codec.h create mode 100644 rtasn1/asn1_codec_ber.cpp create mode 100644 rtasn1/asn1_codec_ber.h create mode 100644 rtasn1/asn1_codec_jer.cpp create mode 100644 rtasn1/asn1_codec_jer.h create mode 100644 rtasn1/asn1_codec_oer.cpp create mode 100644 rtasn1/asn1_codec_oer.h create mode 100644 rtasn1/asn1_codec_per.cpp create mode 100644 rtasn1/asn1_codec_per.h create mode 100644 rtasn1/asn1_config.h.in create mode 100644 rtasn1/asn1_context.cpp create mode 100644 rtasn1/asn1_context.h create mode 100644 rtasn1/asn1_debug.h create mode 100644 rtasn1/asn1_errors.h create mode 100644 rtasn1/asn1_rose.h create mode 100644 rtasn1/asn1_tag.h create mode 100644 rtasn1/asn1_types.cpp create mode 100644 rtasn1/asn1_types.h create mode 100644 rtasn1/asn1_types.hpp create mode 100644 rtasn1/asn1_types.inc create mode 100644 rtasn1/cjson/LICENSE create mode 100644 rtasn1/cjson/README create mode 100644 rtasn1/cjson/cJSON.c create mode 100644 rtasn1/cjson/cJSON.h create mode 100644 rtasn1/cjson/test.c create mode 100644 rtasn1/cjson/tests/test1 create mode 100644 rtasn1/cjson/tests/test2 create mode 100644 rtasn1/cjson/tests/test3 create mode 100644 rtasn1/cjson/tests/test4 create mode 100644 rtasn1/cjson/tests/test5 create mode 100644 rtasn1/cpp/CMakeLists.txt create mode 100644 rtasn1/cpp/prim_GeneralizedTime.h create mode 100644 rtasn1/cpp/prim_UTCTime.h create mode 100644 rtasn1/cpp/prim_oid.cpp create mode 100644 rtasn1/cpp/prim_oid.h create mode 100644 rtasn1/json_token.h.inc create mode 100644 rtasn1/prim_types.cpp create mode 100644 rtasn1/prim_types.h create mode 100644 tests/CMakeLists.txt create mode 100644 tests/UNIT-TEST-basic-types-choice.cpp create mode 100644 tests/UNIT-TEST-basic-types-choice.h create mode 100644 tests/UNIT-TEST-basic-types-enum.cpp create mode 100644 tests/UNIT-TEST-basic-types-enum.h create mode 100644 tests/UNIT-TEST-basic-types-explicit.cpp create mode 100644 tests/UNIT-TEST-basic-types-explicit.h create mode 100644 tests/UNIT-TEST-basic-types-implicit.cpp create mode 100644 tests/UNIT-TEST-basic-types-implicit.h create mode 100644 tests/UNIT-TEST-basic-types-optional.cpp create mode 100644 tests/UNIT-TEST-basic-types-optional.h create mode 100644 tests/UNIT-TEST-basic-types-sequence.cpp create mode 100644 tests/UNIT-TEST-basic-types-sequence.h create mode 100644 tests/UNIT-TEST-basic-types-set.cpp create mode 100644 tests/UNIT-TEST-basic-types-set.h create mode 100644 tests/UNIT-TEST-basic-types-tagged.cpp create mode 100644 tests/UNIT-TEST-basic-types-tagged.h create mode 100644 tests/UNIT-TEST-basic-types.cpp create mode 100644 tests/UNIT-TEST-basic-types.h create mode 100644 tests/UNIT-TEST-ber-primary-types.cpp create mode 100644 tests/UNIT-TEST-ber-primary-types.h create mode 100644 tests/UNIT-TEST-private-types-choice.cpp create mode 100644 tests/UNIT-TEST-private-types-choice.h create mode 100644 tests/UNIT-TEST-type-parameter.h create mode 100644 tests/main_asn1_type_sizes.cpp create mode 100644 tests/main_test.cpp create mode 100644 tests/modules.txt create mode 100644 tests/poc-codec.h create mode 100644 tests/poc-codec.hpp create mode 100644 tests/source.asn1 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..afa8c93 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,180 @@ +PROJECT(asn1) + +SET(ASN1_VERSION_MAJOR 1) +SET(ASN1_VERSION_MINOR 0) +SET(ASN1_VERSION_PATCH 2) +SET(ASN1_VERSION "${ASN1_VERSION_MAJOR}.${ASN1_VERSION_MINOR}.${ASN1_VERSION_PATCH}") + +OPTION(WITH_CMIP "Build Asn1 CMIP test directory" OFF) +OPTION(WITH_CSTA "Build Asn1 CSTA v2 test directory" ON) +OPTION(WITH_CSTAV1 "Build Asn1 CSTA v1 test directory" ON) +OPTION(WITH_GSM "Build Asn1 GSM test directory" ON) +OPTION(WITH_H323 "Build Asn1 H323 test directory" ON) +OPTION(WITH_ASN1_GEN_UML "Build UML Code Generator library" OFF) +OPTION(WITH_ASN1_GEN_JS "Build Javascript Code Generator library" ON) +OPTION(WITH_ASN1_GEN_CPP "Build C++ Code Generator library" ON) +OPTION(WITH_ASN1_GEN_LDS "Build Lds Code Generator library" OFF) + +IF(CMAKE_CROSSCOMPILING) + SET(IMPORT_EXECUTABLES "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point to the + export file from native build") + INCLUDE(${IMPORT_EXECUTABLES}) +ENDIF(CMAKE_CROSSCOMPILING) + +IF (NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE Debug) +ENDIF(NOT CMAKE_BUILD_TYPE) + +ADD_DEFINITIONS(-DBUILD_VERSION=\"${ASN1_VERSION}\") +ADD_DEFINITIONS(-DBUILD_TYPE=\"${CMAKE_BUILD_TYPE}\") +# Only for Linux not MAC +IF(APPLE) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG ") +ELSEIF(WIN32) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG ") +ELSE(APPLE) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -std=c++0x") + SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x") +ENDIF(APPLE) + +# +# Set VARIABLES used by subdirs +# eg: fltk, cppunit, expat, pcap, winpcap + +# +# Libraries first. Process sub dirs +# +IF(NOT CMAKE_CROSSCOMPILING) +SUBDIRS(rtasn1 adt libparser libgen tests pkix cstav1 ledger csta gsm h323 megaco h248 + cmip) +ELSE(NOT CMAKE_CROSSCOMPILING) +SUBDIRS(rtasn1 pkix cstav1 ledger csta gsm h323 megaco h248) +ENDIF(NOT CMAKE_CROSSCOMPILING) + +INCLUDE(${rules_SOURCE_DIR}/flex.cmake) + +IF(NOT WIN32) +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_CURRENT_SOURCE_DIR}/,,$<)\"'") +ENDIF(NOT WIN32) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libgen) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/adt) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${aebutils_SOURCE_DIR}) + +# +# MAC specific addon files for target +# +IF(APPLE) + SET(ASN1PADDONS + ${CMAKE_CURRENT_SOURCE_DIR}/../Resources/squarelogo.jpg + ${CMAKE_CURRENT_SOURCE_DIR}/../Resources/cstainsight.icns + ) +ELSE(APPLE) + SET(ASN1PADDONS "") +ENDIF(APPLE) +# +# EXECUTALBE +# +IF (NOT CMAKE_CROSSCOMPILING) + + ADD_EXECUTABLE(asn1p + main.cpp + ${ASN1PADDONS} + ) + IF (WIN32) + SET_TARGET_PROPERTIES(asn1p PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:console") + SET_TARGET_PROPERTIES(asn1p PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") + SET_TARGET_PROPERTIES(asn1p PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:console") + SET_TARGET_PROPERTIES(asn1p PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") + ENDIF(WIN32) + MESSAGE("Export Executables to ${CMAKE_BINARY_DIR}") + EXPORT(TARGETS asn1p FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake + NAMESPACE native-) + TARGET_LINK_LIBRARIES(asn1p asn1adt libgen libasn1p) +ENDIF(NOT CMAKE_CROSSCOMPILING) + +# +# Cross compiling ... +# +IF(CMAKE_CROSSCOMPILING) + SET(asn1p_EXE native-asn1p) + GET_TARGET_PROPERTY(test ${asn1p_EXE} IMPORTED_LOCATION_DEBUG) + SET(asn1p_EXE ${test}) +ELSE(CMAKE_CROSSCOMPILING) + SET(asn1p_EXE ${CMAKE_CURRENT_BINARY_DIR}/asn1p) +ENDIF(CMAKE_CROSSCOMPILING) + +# +# Install Stuff +# +IF(APPLE) + ADD_EXECUTABLE(Smartasn1 + main.cpp + ${ASN1PADDONS} + ) + TARGET_LINK_LIBRARIES(Smartasn1 asn1adt libgen libasn1p) + + SET(MACOSX_RESOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../Resources/cstainsight.icns + ) + SET_TARGET_PROPERTIES(Smartasn1 PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_STARTUP_COMMAND betfan.sh + MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME} + MACOSX_BUNDLE_BUNDLE_VERSION ${ASN1_VERSION} + MACOSX_BUNDLE_LONG_VERSION_STRING "${ASN1_VERSION}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${ASN1_VERSION}" + MACOSX_BUNDLE_GUI_IDENTIFIER "fr.ebersold.Smartasn1" + # MACOSX_BUNDLE_ICON_FILE "betfan.icns" + MACOSX_BUNDLE_ICON_FILE "cstainsight.icns" + ) + SET_SOURCE_FILES_PROPERTIES( + ${CMAKE_CURRENT_SOURCE_DIR}/../Resources/squarelogo.icns + PROPERTIES MACOSX_PACKAGE_LOCATION Resources + ) + SET_SOURCE_FILES_PROPERTIES( + ${CMAKE_CURRENT_SOURCE_DIR}/../Resources/cstainsight.icns + PROPERTIES MACOSX_PACKAGE_LOCATION Resources + ) + SET(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}) + SET(APPS "\$ENV{DESTDIR}/Smartasn1.app") + SET(DIRS "") +ENDIF(APPLE) +IF(WIN32) + SET_TARGET_PROPERTIES(asn1p PROPERTIES WIN32_EXECUTABLE TRUE) +ENDIF(WIN32) + +IF (NOT CMAKE_CROSSCOMPILING) + IF(APPLE) + INSTALL(TARGETS Smartasn1 + BUNDLE DESTINATION . + COMPONENT Asn1 + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/ + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ + ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ + ) + INSTALL(TARGETS asn1p + COMPONENT Asn1 + DESTINATION Smartasn1.app/Contents/bin/ + RUNTIME DESTINATION Smartasn1.app/Contents/bin/ + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ + ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ + ) + + #INSTALL(CODE " + # include(BundleUtilities) + # fixup_bundle(\"${APP}\" \"\" \"${DIRS}\") + # " COMPONENT Asn1) + ELSE(APPLE) + # + # Unix Install + # + INSTALL(TARGETS asn1p + COMPONENT Asn1 + DESTINATION bin/) + ENDIF(APPLE) +ENDIF(NOT CMAKE_CROSSCOMPILING) + + diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..c1cd967 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,184 @@ +2012/01/27 : Solve the issue with type identifier +2012/01/27 : Solve the issue with parameterized types + +SIGNED{ToBeSigned} ::= SEQUENCE { + tobeSigned ToBeSigned; +} + +2012/07/27 : Codec for Enum is needed specificaly when there is an explicit +tag +2012/07/27 : ANY IDENTIFY BY See If I can replace it by something else. + +2012/07/27 : Choice should have set/get operation as inline. Default +constructors for each choice. !!! might be an issue when several choices have +the same type. + +2012/07/31 : ObjectSet code generation is missing +2012/07/31 : Constraint management, for sized elements +2012/07/31 : Better support for Optional values in codec +2012/07/31 : asn1::error class / codes for error management in codec +2012/07/31 : Log results in file, Logger class + +2012/08/01 : Tags in attributes for sequence +2012/08/01 : Tags in attributes for choice +2012/08/01 : Tags in attributes for set + +2012/08/13 : Decoders have a problem with [0] IMPLICIT BOOLEAN. The issue is +linked to tag checks. + +2014/10/02 : Size of csta_insight has increased 7934911 to 8662504 +8662504 +7934911 +8810664 2017/04/28 +8175720 2017/07/21 +8115936 2017/07/28 + +2014/11/02 : First version of cstav1 with optional and new choice. + - URGENT printf of new choice. + - remove attributes from choice. + - remplace code in choice_codec + - review the way to initialize defaults. New Constructor prototype ? + - review decode of optionnal. Maybe destroy existing value if one. + - Write tests : SEQUENCE OF, SEQUENCE with defaults that are tagged. + - purge traces in parser (generator.cpp) all std::cout should be put under log + - add log traces filter at generation level. (DEBUG_CTOR, DEBUG_CODEC, DEBUG_COMMENT) + * a flag that will remove all comments from source code. + * a flag that will remove debug traces + * a flag that will even remove ERROR traces. + - ENUMRATED, put implementation in cpp file. + - BIT_STRING, if there is a size contraint, I should use it. + + 2014/11/18: ASN1 spec 2008 + -------------------------- + Take into account the news introduced in X.680 2008 there are changes + -> new reserved keywords : DATE / DATE-TIME / DURATION / ENCODING-CONTROL / + INSTRUCTIONS / NOT-A-NUMBER / OID-IRI / RELATIVE-OID-IRI / SETTINGS / TIME / + TIME-OF-DAY + new tags: + TIME tag UNIVERSAL 14 + DATE tag UNIVERSAL 31 + TIME-OF-DAY tag 32 + DATE-TIME tag UNIVERSAL 33 + DURATION tag UNIVERSAL 34 + + add ENCODING-CONTROL part + in definition, rule encoding_instruction_defaults + +2015/08/19: +----------- +Move files abstract datatypes to adt directory and make a library out of it. +create a new version 2 for asn1.l asn1.y to use common project of parser. + +Also solve asn1p issues with gsm and H323 +------------- + +Generaration of CODE SEQUENCE_OF + leads to duplicate codecs + +Generation of CODEC for private CHOICE in sequence + missing codec for private choice + +Issue with CODEC generation with SEQUENCE OF SEQUENCE + +2016/01/20: +----------- + - Finalize helper generator for cpp et hpp + - Finalize flatten option. or unested code generation. + - Add prefix option + - Add namespace option + - Put all asn1 file and definition name in a file to allow the parser to resolve imports. + - OER encoded needs to be added. + - Solve issue with duplicated name types in nested environments specially in h248. + - Issue with BIT_STRING primitive class. should not be an array needs to be rewritten + - Rework handling of reference generation as I got a better understanding + - Add a resolver class in adt. The purpose is to find the type for a given reference. + - Better handling of struct name assignment + - BIT STRING types are not defined in header. compilation of gsm fails + +2016/04/06: +----------- + - Fixed parsing objects and checking against class + - Fixed nested issue + - Fixed SELECTION TYPE + - Fixed COMPONENTS OF for sequence / set. Missing one check + - Fixed Duplicate Types in h248 + - Fixed encoding for object classes + - Fixed resolver added in adt. + - Fixed ROS syntax with parameter generation. Missing Init of object sets + +2017/01/10: +----------- + - remove begin / end for all calls where it is not required + - handling of values to be aligned. valuetype class should be used. Clarify + valuetype and value class !!! seems to have the same purpose + +2017/04/28: +----------- + - Fixed H323 generation. Compiles again ... Was broken during source reworking + - Improved Asn1 Object data types to facilitate parsing and understanding. + - Better distinction in generator between actual parameter and parameter. + - Optimizer, Added processing of SELECTION Type + - Reworked Codec classes .... added dummy per and oer codecs. Seems to be promissing + - Tests have still 5 failures. + - DONE move asn1 folder to rtasn1 meaning : asn1 runtime to avoid confusion with root + directory. + - In choice, add parameter handling for Types like Invoke... + +2017/05/14: +----------- + - make a clear separation between typenodes and assignments + * move m_reference and its API from node to typeref + * move m_type and its API from node to assignment and field + * remove node iterator, and introduce assignement iterator and field iterator + +2017/06/20: +----------- + - TODO For typeref add methods like get_canonical() return the primivite type + - TODO For typeref add get_prev_typeref which will return preview declaration. It's useful + to build tag list chaine. + - TODO For typeref also add method get_prev_typenode() + - TODO Before optimization, I should built the type map and resolve the references. + this would save me a lot of time during processing where is often use lookup + - TODO Attribute-ASN1Module uses class typeref. I do not generate code for this type :-( + +2018/05/19: +----------- + +Generator | BER | BER | JER | OER | PER | XER | ctors | print | equal | copy +cpp/Type | Old | Codec | Codec | Codec | Codec | | | | | + +Typeref | | 30% | 40% | | | | | | | +BOOLEAN | 100% | 50% | 50% | 20% | | | DONE | DONE | DONE | DONE +INTEGER | 70% | 30% | 30% | 20% | 20% | | | | | +ENUMERATED | 70% | 30% | 30% | 20% | 20% | | | | | +NULL | 100% | 20% | 50% | 20% | 20% | | | | | +REAL | 5% | | 20% | | | | | | | +OCTET_STRING | 80% | 30% | 40% | 20% | 20% | | | | | +BIT_STRING | 70% | 20% | 30% | 20% | 20% | | | | | +SEQUENCE | 60% | 20% | 40% | | | | | | | +SET | 50% | | 0% | | | | | | | +CHOICE | 70% | 20% | 30% | | | | | | | +SEQUENCE OF | 60% | 20% | 40% | 20% | 20% | | | | | +SET OF | 60% | 20% | 20% | 20% | | | | | | +CLASSDEF | 60% | | 0% | | | | | | | +OBJECT | 60% | | 0% | | | | | | | +OID | 60% | 20% | 20% | 20% | | | | | | +ROID | 0% | | 0% | | | | | | | +TIME | 0% | | 0% | | | | | | | +TIME-OF-DAY | 0% | | 0% | | | | | | | +GeneralizeUTC | 0% | | 0% | | | | | | | +DATA-TIME | 0% | | 0% | | | | | | | +DURATION | 0% | | 0% | | | | | | | +STRING | 60% | | 20% | | | | | | | +EXTERNAL | 0% | | 0% | | | | | | | +EMBEDDED-PDV | 0% | | 0% | | | | | | | + + - TODO JER start decoding implementation. + - TODO move encode/decode BER to BER codec way. Goal : remove Old BER style. + - TODO update helpers to be more unified. encode/decode into generate_ber + - TODO set/sequence equal + - TODO BIT_STRING or ENUMERATED with constraint in SEQUENCE or SET should lead to a new type! + - TODO disable default ber in generator. + - TODO improve ber generation so that switch --codecs will work. Either codec or embeded enc/dec + - TODO I think there is a constrcutor missing with OID. ASN1 speficitation use a lot of OID value + - TODO Provide allocator class to allocate asn1 objects. Might be easier with codec. diff --git a/adt/CMakeLists.txt b/adt/CMakeLists.txt new file mode 100644 index 0000000..2800e62 --- /dev/null +++ b/adt/CMakeLists.txt @@ -0,0 +1,24 @@ +PROJECT(libasn1adt) + +ADD_LIBRARY(asn1adt + asn1_node.cpp + asn1_node_typenode.cpp + asn1_node_sequence.cpp + asn1_node_choice.cpp + asn1_node_classdef.cpp + asn1_node_object.cpp + asn1_node_parameters.cpp + asn1_node_assignment.cpp + asn1_node_constructed.cpp + asn1_node_field.cpp + asn1_node_typeref.cpp + asn1_node_primitive.cpp + asn1_node_imports.cpp + asn1_constraint.cpp + asn1_value.cpp + asn1_resolver.cpp + asn1_reference.cpp + asn1_node_valuetype.cpp + asn1_module.cpp + ) + diff --git a/adt/asn1_constraint.cpp b/adt/asn1_constraint.cpp new file mode 100644 index 0000000..4f0ce3f --- /dev/null +++ b/adt/asn1_constraint.cpp @@ -0,0 +1,293 @@ +#include +#include +#include +#include +#include + +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "asn1_node.h" + +namespace asn1 { + +std::string +constraint::name() +{ + std::ostringstream os; + switch(type()) + { + case asn1::constraint::EL_TYPE: /* T (contained subtype ) */ + os<<" type("<name(); + os<<")"; + break; + case asn1::constraint::EL_VALUE: /* 123, "X" (elementary value) */ + os<<" value("<name(); + os<<")"; + break; + case asn1::constraint::EL_RANGE: /* 1..5 (basic range) */ + case asn1::constraint::EL_LLRANGE: /* 1<..3 */ + case asn1::constraint::EL_RLRANGE: /* 1..<4 */ + case asn1::constraint:: EL_ULRANGE: /* 1<..<3 (basic range) */ + { + asn1::constraint_range *cr = as_constraint_range(); + os<<" range("; + if (cr && cr->get_min()) + { + os<get_min()->name(); + os<<" .."<get_max()->name(); + } + os<<")"; + } + break; + case asn1::constraint::EL_EXT: /* ... (extensible mark) */ + os<<" extensible "; + break; + + /*Constraint type */ + case asn1::constraint::CT_SIZE: + os<<" !!! size("; + if ((! m_elements.empty()) && m_elements.front() != NULL) + os<<((m_elements.front()))->name(); + os<<")"; + break; + case asn1::constraint::CT_FROM: + default: + os<<" constraint not handled "<name(); + os<<")"; + break; + case asn1::constraint::CT_FROM: + os<<"from "; + if (m_elements.front() != NULL) + os<<((m_elements.front()))->name()<<" "; + break; + case asn1::constraint::CT_WCOMP: + { + os<<"with component "; + iterator it = m_elements.begin(); + os<<(*it)->name(); + } + break; + case asn1::constraint::CT_WCOMPS: + { + os<<"with components "; + for (iterator it = m_elements.begin() + ; it != m_elements.end() + ; ++it) + os<<" "<<(*it)->name()<<" "; + } + break; + case asn1::constraint::CT_CTDBY: + os<<"constrained by "; + if (m_value) + os<name(); + break; + case asn1::constraint::CT_CTNG: + os<<"constaining "; + if (m_value) + os<name(); + break; + default: + os<<" constraint not handled "; + } + return os.str(); +} + +std::string +constraint_array::name() +{ + std::ostringstream os; + switch(type()) + { + case asn1::constraint::CA_SET: + os<<"set "; + for (iterator it = m_elements.begin() + ; it != m_elements.end() + ; ++it) + os<<"("<<(*it)->name()<<")"; + os<<""; + break; + case asn1::constraint::CA_CRC: + { + os<<"crc "; + iterator it = m_elements.begin(); + os<<"{"<<(*it)->name()<<"}"; + ++it; + os<<"{@ ? "<<(*it)->name()<<"}"; + } + break; + case asn1::constraint::CA_CSV: + os<<"csv"; + break; + case asn1::constraint::CA_UNI: + os<<"union"; + break; + case asn1::constraint::CA_INT: + os<<"intersection"; + break; + case asn1::constraint::CA_EXC: + os<<"except"; + break; + case asn1::constraint::CA_AEX: + { + os<<"all except "; + iterator it = m_elements.begin(); + os<<(*it)->name(); + } + break; + + default: + os<<"array constraint"; + } + return os.str(); +} + +asn1::constraint_type * +constraint::as_constraint_type() +{ + return dynamic_cast(this); +} + +asn1::constraint_element * +constraint::as_constraint_element() +{ + return dynamic_cast(this); +} + + +asn1::ctype_size * +constraint::as_constraint_size() +{ + return dynamic_cast(this); +} + + +/** + * constraint_element + */ + +asn1::valuetype * +constraint_element::get_valuetype() const +{ + return (m_value?m_value->as_value_type():NULL); +} + + +/** + * celt_type specificities + */ +celt_type::celt_type(asn1::typeref *t) + : constraint_element(EL_TYPE) +{ + value(t) ; +} + +// +asn1::typeref * +celt_type::get_type() const +{ + return value()->as_typeref(); +} + +/** + * ctype_size object type + * subelement constraint is either value or range. + * range is of type constraint_range + * value is of type constraint_element or + */ +asn1::celt_value * +ctype_size::get_value() const +{ + asn1::constraint_element *subelem = (*m_elements.begin())->as_constraint_element(); + return (subelem?subelem->as_celt_value():NULL); +} + +asn1::constraint_range* +ctype_size::get_range() const +{ + asn1::constraint_element *subelem = (*m_elements.begin())->as_constraint_element(); + return (subelem?subelem->as_constraint_range():NULL); +} + +/** + * + */ +constraint_range * +constraint::as_constraint_range() +{ + return dynamic_cast(this); +} + +#define ELEMENT_CONSTRAINT(elt,cls,parent) \ +cls * \ +constraint::as_##cls() \ +{ \ + return dynamic_cast(this); \ +} + +#include "asn1_constraint.inc" + +/** + * constraint_range code + */ + +constraint_range::constraint_range(types_type t,asn1::node *_min,asn1::node *_max) + : m_min(_min),m_max(_max),constraint_element(t) +{ +} + +constraint_range::~constraint_range() +{ +} + + +void +constraint_range::set_min(asn1::node *s) +{ + m_min = s; + //m_elements.push_back(new constraint("value",s,EL_VALUE)); +} + +void +constraint_range::set_max(asn1::node *s) +{ + m_max = s; + //m_elements.push_back(new constraint("value",s,EL_VALUE)); +} + +void +constraint_range::set_min_max(asn1::node *_min,asn1::node *_max ) +{ + m_min = _min; + m_max = _max; +} + +bool +constraint_range::get_min_max(long &min,long &max) +{ + asn1::valuetype *_min_type = (m_min != NULL)?m_min->as_value_type(): NULL; + asn1::valuetype *_max_type = (m_max != NULL)?m_max->as_value_type(): NULL; + min = (_min_type)?_min_type->value_long():0; + max = (_max_type)?_max_type->value_long():0; + return ( (_min_type != NULL) && ( _max_type != NULL)); +} + + +} diff --git a/adt/asn1_constraint.h b/adt/asn1_constraint.h new file mode 100644 index 0000000..d34e2ea --- /dev/null +++ b/adt/asn1_constraint.h @@ -0,0 +1,226 @@ +#ifndef ASN1_CONSTRAINT_H__ +#define ASN1_CONSTRAINT_H__ + +namespace asn1 { +class node; +class typeref; +class valuetype; +class constraint_element; +class constraint_range; +class constraint_type; +class ctype_size; +class ctype_from; + +#define ELEMENT_CONSTRAINT(elt,cls,parent) \ + class cls ; + +#include "asn1_constraint.inc" + +class constraint +{ + public: + + typedef std::list contraints; + + typedef contraints::iterator iterator; + typedef contraints::const_iterator const_iterator; + + typedef enum { + EL_INVALID, + /* Element type */ + EL_TYPE, /* T (contained subtype ) */ + EL_VALUE, /* 123, "X" (elementary value) */ + EL_RANGE, /* 1..5 (basic range) */ + EL_LLRANGE, /* 1<..3 */ + EL_RLRANGE, /* 1..<4 */ + EL_ULRANGE, /* 1<..<3 (basic range) */ + EL_ENCODEDBY, /* encoded by type */ + EL_EXT, /* ... (extensible mark) */ + + /*Constraint type */ + CT_SIZE, /* SIZE Constraint type */ + CT_FROM, /* */ + CT_WCOMP, /* WITH COMPONENT */ + CT_WCOMPS, /* WITH COMPONENTS*/ + CT_CTDBY, /* CONSTRAINED BY */ + CT_CTNG, /* CONTAINING */ + /* Array Constraints */ + CA_SET, /* A set of constraints: (c1)(c2) */ + CA_CRC, /* Comp. relation c-t: ({a}{@b}) */ + CA_CSV, /* Comma-separated constraints array */ + CA_UNI, /* UNION (|) */ + CA_INT, /* INTERSECTION (^) */ + CA_EXC, /* EXCEPT */ + CA_AEX /* ALL EXCEPT */ + } types_type; + + inline bool is_constraint_array() { return m_type>= CA_SET && m_type <= CA_AEX ; } + inline bool is_constraint_type() { return m_type>= CT_SIZE && m_type <= CT_CTNG ; } + inline bool is_constraint_elem() { return m_type>= EL_TYPE && m_type <= EL_EXT ; } + + typedef enum { + DEFAULT, + PRESENT, + ABSENT, + OPTIONAL_ + } presence_type; + + constraint(const char *name,types_type t = EL_INVALID) :m_type(t),m_value(NULL) {} + constraint(const char *name,asn1::node *n,types_type t = EL_INVALID) :m_type(t),m_value(n) {} + constraint(const constraint &c) : m_type(c.m_type),m_value(c.m_value) {}; + ~constraint() {}; + + virtual std::string name(); + /* Avoid using iterator. Not all constraints use containers */ + iterator begin() {return m_elements.begin();} + const_iterator begin() const {return m_elements.begin();} + iterator end() {return m_elements.end();} + const_iterator end() const {return m_elements.end();} + + void append(constraint *c) {m_elements.push_back(c);}; + + /* Value associated with the constraint */ + inline void value(asn1::node *n) {m_value = n;}; + + inline asn1::node* value() const {return m_value;}; + + inline void presence(presence_type p) {m_presence = p;}; + + inline size_t size() const { return m_elements.size();}; + /* Cast opertors */ + constraint_type *as_constraint_type(); + constraint_element *as_constraint_element(); + constraint_range *as_constraint_range() ; + ctype_size *as_constraint_size() ; + +#define ELEMENT_CONSTRAINT(elt,cls,parent) \ + cls *as_##cls() ; +#include "asn1_constraint.inc" + + // Type of constraint + inline types_type type() const {return m_type;}; + inline void type(types_type t) {m_type = t;}; + protected: + contraints m_elements; + asn1::node *m_value; + types_type m_type; + presence_type m_presence; +}; + + +/** + * + */ +class constraint_element : public constraint +{ + public: + constraint_element(types_type t) :constraint("ELEMENT",t) {} ; + ~constraint_element() {}; + /** + * valuetype is asn1 value some how. + * Here, we leave the constraint syntax + */ + asn1::valuetype *get_valuetype() const ; +}; + +/** + * A range is composed of two values. + * min .. max + */ +class constraint_range : public constraint_element +{ + asn1::node *m_min; + asn1::node *m_max; + public: + constraint_range(types_type t,asn1::node *_min = NULL,asn1::node *_max = NULL); + + ~constraint_range() ; + + void set_min(asn1::node *s); + + void set_max(asn1::node *s); + + asn1::node *get_min() const { return m_min ; } + + asn1::node *get_max() const { return m_max ; } + + void set_min_max(asn1::node *_min,asn1::node *_max ); + + bool get_min_max(long &min,long &max); +}; + +/** + * + */ +class constraint_type : public constraint +{ + public: + constraint_type(types_type t) : constraint("TYPE",t) {}; + ~constraint_type() {}; + std::string name(); +}; + +/** + * + */ +class constraint_array : public constraint +{ + public: + constraint_array(types_type t) : constraint( "ARRAY",t) {} ; + ~constraint_array() {} ; + + std::string name(); +}; +/* Element type */ +#define ELEMENT_CONSTRAINT_EXTEND_celt_type \ + celt_type(asn1::typeref *t); \ + asn1::typeref *get_type() const; +#define ELEMENT_CONSTRAINT_EXTEND_celt_value ; +#define ELEMENT_CONSTRAINT_EXTEND_celt_range ; +#define ELEMENT_CONSTRAINT_EXTEND_celt_llrange ; +#define ELEMENT_CONSTRAINT_EXTEND_celt_rlrange ; +#define ELEMENT_CONSTRAINT_EXTEND_celt_ulrange ; +#define ELEMENT_CONSTRAINT_EXTEND_celt_encodedby ; +#define ELEMENT_CONSTRAINT_EXTEND_celt_ext ; + +/*Constraint type */ +#define ELEMENT_CONSTRAINT_EXTEND_ctype_size \ + asn1::celt_value *get_value() const; \ + asn1::constraint_range *get_range() const; \ + +#define ELEMENT_CONSTRAINT_EXTEND_ctype_from ; +#define ELEMENT_CONSTRAINT_EXTEND_ctype_wcomp ; +#define ELEMENT_CONSTRAINT_EXTEND_ctype_wcomps ; +#define ELEMENT_CONSTRAINT_EXTEND_ctype_ctdby ; +#define ELEMENT_CONSTRAINT_EXTEND_ctype_ctng ; + +/* Array Constraints */ +#define ELEMENT_CONSTRAINT_EXTEND_ca_set ; +#define ELEMENT_CONSTRAINT_EXTEND_ca_crc ; +#define ELEMENT_CONSTRAINT_EXTEND_ca_csv ; +#define ELEMENT_CONSTRAINT_EXTEND_ca_uni ; +#define ELEMENT_CONSTRAINT_EXTEND_ca_int ; +#define ELEMENT_CONSTRAINT_EXTEND_ca_exc ; +#define ELEMENT_CONSTRAINT_EXTEND_ca_aex ; + + +#define ELEMENT_CONSTRAINT_GEN(elt,cls,parent) \ + class cls : public parent \ + {\ + public:\ + cls() : parent(elt) {}; \ + ~cls() {} \ + +// }; + +#define ELEMENT_CONSTRAINT(elt,cls,parent) \ + ELEMENT_CONSTRAINT_GEN(elt,cls,parent) ELEMENT_CONSTRAINT_EXTEND_##cls }; + +#include "asn1_constraint.inc" + +} + +/* +vim:et:sw=2:ts=2 + */ +#endif diff --git a/adt/asn1_constraint.inc b/adt/asn1_constraint.inc new file mode 100644 index 0000000..7801f4f --- /dev/null +++ b/adt/asn1_constraint.inc @@ -0,0 +1,39 @@ +#ifndef ELEMENT_CONSTRAINT +#define ELEMENT_CONSTRAINT(elt,cls,parent) +#endif +/* Element type */ +ELEMENT_CONSTRAINT(EL_TYPE,celt_type,constraint_element) /* t (contained subtype ) */ +ELEMENT_CONSTRAINT(EL_VALUE,celt_value,constraint_element) /* 123, "x" (elementary value) */ +ELEMENT_CONSTRAINT(EL_RANGE,celt_range,constraint_range) /* 1..5 (basic range) */ +ELEMENT_CONSTRAINT(EL_LLRANGE,celt_llrange,constraint_range) /* 1<..3 */ +ELEMENT_CONSTRAINT(EL_RLRANGE,celt_rlrange,constraint_range) /* 1..<4 */ +ELEMENT_CONSTRAINT(EL_ULRANGE,celt_ulrange,constraint_range) /* 1<..<3 (basic range) */ +ELEMENT_CONSTRAINT(EL_ENCODEDBY,celt_encodedby,constraint_range) /* encoded by type */ +ELEMENT_CONSTRAINT(EL_EXT,celt_ext,constraint_element) /* ... (extensible mark) */ + +/*Constraint type */ +#ifndef ELEMENT_CONSTRAINT_TYPE +#define ELEMENT_CONSTRAINT_TYPE(elt,cls,parent) ELEMENT_CONSTRAINT(elt,cls,parent) +#endif +ELEMENT_CONSTRAINT_TYPE(CT_SIZE,ctype_size,constraint_type) /* size constraint type */ +ELEMENT_CONSTRAINT_TYPE(CT_FROM,ctype_from,constraint_type) /* */ +ELEMENT_CONSTRAINT_TYPE(CT_WCOMP,ctype_wcomp,constraint_type) /* with component */ +ELEMENT_CONSTRAINT_TYPE(CT_WCOMPS,ctype_wcomps,constraint_type) /* with components */ +ELEMENT_CONSTRAINT_TYPE(CT_CTDBY,ctype_ctdby,constraint_type) /* constrained by */ +ELEMENT_CONSTRAINT_TYPE(CT_CTNG,ctype_ctng,constraint_type) /* containing */ + +/* Array Constraints */ +#ifndef ELEMENT_CONSTRAINT_ARRAY +#define ELEMENT_CONSTRAINT_ARRAY(elt,cls,parent) ELEMENT_CONSTRAINT(elt,cls,parent) +#endif +ELEMENT_CONSTRAINT_ARRAY(CA_SET,ca_set,constraint_array) /* a set of constraints: (c1)(c2) */ +ELEMENT_CONSTRAINT_ARRAY(CA_CRC,ca_crc,constraint_array) /* comp. relation c-t: ({a}{@b}) */ +ELEMENT_CONSTRAINT_ARRAY(CA_CSV,ca_csv,constraint_array) /* comma-separated constraints array */ +ELEMENT_CONSTRAINT_ARRAY(CA_UNI,ca_uni,constraint_array) /* union (|) */ +ELEMENT_CONSTRAINT_ARRAY(CA_INT,ca_int,constraint_array) /* intersection (^) */ +ELEMENT_CONSTRAINT_ARRAY(CA_EXC,ca_exc,constraint_array) /* except */ +ELEMENT_CONSTRAINT_ARRAY(CA_AEX,ca_aex,constraint_array) /* all except */ + +#undef ELEMENT_CONSTRAINT +#undef ELEMENT_CONSTRAINT_TYPE +#undef ELEMENT_CONSTRAINT_ARRAY diff --git a/adt/asn1_meta.h b/adt/asn1_meta.h new file mode 100644 index 0000000..51e8b11 --- /dev/null +++ b/adt/asn1_meta.h @@ -0,0 +1,46 @@ +#ifndef ASN1_META_H__ +#define ASN1_META_H__ +#include + +namespace asn1 +{ + + class meta + { + public: + typedef enum { + INVALID = 0 , + TYPEREF, /* Type2 := Type1 */ + TYPE, /* Type1 := INTEGER */ + VALUE, /* value Type1 := 1 */ + VALUESET, /* Vset Type1 := {value 1} */ + OBJECT, /* object CLASS := {...} */ + OBJECTCLASS, /* FCT := CLASS {} */ + OBJECTSET, /* objref DefinedObject := {set } */ + OBJECTFIELD, + MAX + } id; + inline meta(meta::id id = INVALID) : m_id(id) {}; + inline meta(const meta &m) : m_id(m.m_id) {}; + inline meta &operator =( const meta &m) {m_id = m.m_id; return *this;}; + inline meta &operator =( const id i) {m_id = i; return *this;}; + inline ~meta() {}; + inline bool operator >(const meta &a) {return m_id > a.m_id; }; + inline bool operator <(const meta &a) {return m_id < a.m_id; }; + inline bool operator ==(const meta &a) {return m_id == a.m_id; }; + inline bool operator ==(const meta::id a) {return m_id == a; }; + + friend std::ostream & operator <<(std::ostream &os, const meta &m) + { + os< +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +/** + * Useful method to resolve references. before + * optimization. + */ +void +module::resolve(asn1::resolver &r) +{ + struct do_resolve { + do_resolve(asn1::resolver &_r) : m_resolver(_r) {}; + + void operator () (std::pair &p) + { + p.second->get_type()->resolve(m_resolver); + } + asn1::resolver &m_resolver; + } ; + + std::cerr<<__FUNCTION__<<" TODO"<second; + return NULL; +} + + + +asn1::assignment * +module::lookup(asn1::node *reference) +{ + asn1::node::iterator nit = std::find_if(begin(), + end(), + asn1::find_node(reference->name())); + if ( nit != end() ) + { + return dynamic_cast(*nit); + } + return NULL; +} + +/** + * All assignments added through this function are + * in m_symbols map. + * -> Those reworked by optimize will not be + * seen in the map. That allows a distinction between + * reparented structures and declared types. + */ +void +module::add_type(asn1::assignment *n) +{ + assert((n != NULL) && "add_type parameter assignment must not be NULL"); + append(n); + if ( n && n->meta_id()() == asn1::meta::OBJECT) + { + m_has_objects = true; + } + symt_iterator it = m_symbols.find(n->name()); + if ( it == m_symbols.end()) + m_symbols[n->name()] = n; +} + +// +void +module::enter_symbol(asn1::node *n,asn1::type::id id) +{ + if (!m_context.empty()) + { + if (n->get_parent() == NULL) + { + n->set_parent(m_context.top()); + } else + { + std::cerr<<"module::enter_symbol the node already has a parent"<append(n); + } else + { + std::cerr<<"module::enter_symbol "<name()<<" can't add on empty context"<(this); + return m_context.top() ; +} +// +asn1::constructed * +module::leave_context() +{ + asn1::constructed *r = m_context.top(); + m_context.pop(); + return r; +} + + + + +asn1::import * +module::get_import(const std::string &imp) const +{ + // pre condition, m_imports != NULL + if ( ! m_imports) + return NULL; + + asn1::node::iterator found = std::find_if( m_imports->begin() + , m_imports->end() + , asn1::find_node(imp)); + if (found != m_imports->end()) + return dynamic_cast(*found); + return NULL; +} + +} +/** + * vim: et sw=2 ts=2 list: + */ diff --git a/adt/asn1_module.h b/adt/asn1_module.h new file mode 100644 index 0000000..a243126 --- /dev/null +++ b/adt/asn1_module.h @@ -0,0 +1,113 @@ +#ifndef ASN1_MODULE_H__ +#define ASN1_MODULE_H__ + +#include +#include +#include + +#include "asn1_node.h" + +namespace asn1 { + + class import_list; + class import; + class module; + class resolver ; + struct find_module + { + find_module(const std::string &s) : m_s(s) {} + bool operator ()(asn1::module *n); + std::string m_s; + }; + +/** + * A module contains all definitions. When we start a new definition, + * the parser shall call enter context and at the end, it shall call + * leave_context + */ +class module : public asn1::constructed +{ + public: + typedef std::map symtable_type; + typedef symtable_type::iterator symt_iterator; + typedef std::vector modules_type; + typedef std::stack context_stack_type; + + public: + + module(const char *name ) : asn1::constructed(name,type::INVALID) + ,m_root(NULL) + ,m_has_objects(false) + ,m_imports(NULL) + ,m_exports(NULL) {}; + + module(const module &m) + : asn1::constructed(m) + , m_has_objects(m.m_has_objects) + { + std::cerr<<"module::module(const module &m)"<name()); + }; + +} + +/** +vim:et:sw=2:ts=2 + */ +#endif diff --git a/adt/asn1_node.cpp b/adt/asn1_node.cpp new file mode 100644 index 0000000..7c297eb --- /dev/null +++ b/adt/asn1_node.cpp @@ -0,0 +1,742 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_reference.h" +#include "asn1_module.h" + +namespace asn1 { +// Counter to help computing an unique identifier for each node. +static long g_counter = 0; + +static +char lop_substitute(char c) +{ + return (c == '&')?'_':c; +} +/** + * + * + */ +node::node(const std::string name, meta m ) : m_is_generated(CL_GREEN) , + m_ref(0),m_name(name),m_meta(m), + m_next(NULL) + , m_constraints("VIDE") + , m_identifier(NULL) + ,m_parameters(NULL) + ,m_value(NULL) + ,m_type(NULL) + ,m_parent(NULL) + ,m_marker(marker_type::FL_NONE) +{ + m_tag.m_mode = tag_type::TM_DEFAULT; + m_tag.m_class = tag_type::TC_NOCLASS; + m_tag.m_value = -1; + m_tag.m_set = false; + std::ostringstream oss; + std::string cppname; + cppname.resize(m_name.size()); + std::transform(m_name.begin(),m_name.end(),cppname.begin(),asn1::lop_substitute); + oss<(this)) + { + return m_name; + } + + if (const asn1::typeref *tref = as_typeref()) + { + + ref_name = "error-ref"; + if ( tref->get_reference() && + (*(tref->get_reference()->begin()) ).m_identifier.compare("TYPE-IDENTIFIER") == 0) + { + ref_name = "error-ref-type-identifier"; + if (m_constraints.begin() != m_constraints.end()) + { + ref_name = "error-ref-type-identifier-has-constraint"; + asn1::constraint::const_iterator cit = m_constraints.begin(); + if ( (*cit)->type() == asn1::constraint::EL_TYPE ) + { + asn1::node *value = (*cit)->value(); + ref_name = value->name();//+"/*CTY*/"; + } + } + } else + { + if (tref->get_reference()) + ref_name = tref->get_reference()->name(); + } + } else + ref_name = m_name; +#if 0 + // Does not work. + if (meta_id() == meta::VALUE + && m_value) + { + ref_name = m_value->cpp_name(); + } +#endif + return ref_name; +} + + +// +// +// +const std::string +node::cpp_name() +{ +std::string lname = name(); +#if 0 +std::string s; +s.resize(name().size()); +std::transform(lname.begin(),lname.end(),s.begin(),op_substitute); +if (lname.compare("private") == 0) { + return std::string("_private"); +} else if (lname.compare("operator") == 0) { + return std::string("_operator"); +} else if (lname.compare("...") == 0) { + return std::string("_treedot"); +} else if (lname.compare("bool") == 0) { + return std::string("_bool"); +} else if (lname.compare("true") == 0) { + return std::string("_true"); +} else if (lname.compare("false") == 0) { + return std::string("_false"); +} else if (lname.compare("auto") == 0) { + return std::string("_auto"); +} else if (lname.compare("explicit") == 0) { + return std::string("_explicit"); +} else if (lname.compare("continue") == 0) { + return std::string("_continue"); +} else if (lname.compare("default") == 0) { + return std::string("_default"); +} else if (lname.compare("NULL") == 0) { + return std::string("Null"); +} else +return s; +#else + return asn1::cpp_name(lname); +#endif +} + +const std::string +cpp_name(const std::string &lname) +{ + std::string s; + s.resize(lname.size()); + std::transform(lname.begin(),lname.end(),s.begin(),op_substitute); + if (lname.compare("private") == 0) { + return std::string("_private"); + } else if (lname.compare("operator") == 0) { + return std::string("_operator"); + } else if (lname.compare("...") == 0) { + return std::string("_treedot"); + } else if (lname.compare("bool") == 0) { + return std::string("_bool"); + } else if (lname.compare("true") == 0) { + return std::string("_true"); + } else if (lname.compare("false") == 0) { + return std::string("_false"); + } else if (lname.compare("auto") == 0) { + return std::string("_auto"); + } else if (lname.compare("explicit") == 0) { + return std::string("_explicit"); + } else if (lname.compare("continue") == 0) { + return std::string("_continue"); + } else if (lname.compare("default") == 0) { + return std::string("_default"); + } else if (lname.compare("NULL") == 0) { + return std::string("Null"); + } else + return s; +} + +// +// +// +const std::string +node::identifier_name() +{ + if (m_identifier !=NULL) { + return m_identifier->name(); + } else { + std::cerr<<"Identifier is NULL"<m_identifier == NULL) { + std::cerr<<"ERROR indentifier == NULL"<name(); +//std::cerr<<"HERE 2 "<0) { + s.resize(name.size()); + std::transform(name.begin(),name.end(),s.begin(),op_substitute); +} +if (name.compare("private") == 0) { + return std::string("_private"); +} else if (name.compare("...") == 0) { + return std::string("_treedot"); +} else if (name.compare("bool") == 0) { + return std::string("_bool"); +} else if (name.compare("true") == 0) { + return std::string("_true"); +} else if (name.compare("false") == 0) { + return std::string("_false"); +} else if (name.compare("default") == 0) { + return std::string("_default"); +} else +return s; +} + + +// Generated stuff +void node::set_generated(bool b) +{ + if (b == false) { + m_is_generated = CL_GREEN; + } else { + if (m_is_generated != CL_RED) + m_is_generated = color(m_is_generated + 1); + } + +} + +// +// +// +bool node::is_generated() +{ + switch(m_type_id()) + { + case asn1::type::ASN1_INTEGER: + case asn1::type::ASN1_OCTET_STRING: + return true; + break; + default: + return m_is_generated == CL_RED; + }; +} + +// +// +// +void +node::path2module(std::list &l) const +{ + long depth = 0; + asn1::node *p = m_parent; + if ( p == NULL) + { + std::cerr<<"node::path2module p (parent ) is NULL for node "<(p)) + { + l.push_front(const_cast(this)); + return; + } + do + { + if ( p == NULL) + { + std::cerr<<"node::path2module p is NULL "<type_id()()) + { + case asn1::type::ASN1_SEQUENCE_OF: + case asn1::type::ASN1_SET_OF: + p = p->get_parent(); + break; + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_CHOICE: + case asn1::type::ASN1_SET: + if ( p->identifier() == NULL) + { + std::cerr<<"node::path2module ASSERT "<name()<( p->get_parent())) + { + std::cerr<<"node::path2module ASSERT return "<name()<name()<get_parent(); + break; + default: + l.push_front(p); + p = p->get_parent(); + depth++; + } + } while( (p != NULL) && (dynamic_cast(p) == NULL) && depth < 20) ; + assert((depth < 20) && (p != NULL)); +} + +/** + * + */ +asn1::module *node::from_module() const +{ + asn1::node *p = m_parent; + node_list nl; + + if (asn1::module *mo = dynamic_cast(p)) + { + return mo; + } + path2module(nl); + + + asn1::module *t_module = dynamic_cast(nl.front()->get_parent()); + return t_module; +} + +// +// +// +bool +node::is_private() const +{ + int depth = 0; + if (dynamic_cast(m_parent) != NULL ) + return false; + asn1::node *p = m_parent; + do + { + if ( p == NULL) + { + std::cerr<<"is_private p is NULL no parent for type "<type_id()()) + { + case asn1::type::ASN1_SEQUENCE_OF: + case asn1::type::ASN1_SET_OF: + p = p->get_parent(); + break; + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_CHOICE: + case asn1::type::ASN1_SET: + if ( p->identifier() == NULL) + { + std::cerr<<"is_private ASSERT "<name()<get_parent(); + depth++; + } + } while( (p != NULL) && (dynamic_cast(p) == NULL) && depth < 20) ; + assert((depth < 20) && (p != NULL)); + return false; +} + + +asn1::valuetype * +node::as_value_type() +{ + return dynamic_cast(this); +} + +asn1::typenode * +node::as_typenode() +{ + return dynamic_cast(this); +} + +asn1::enumerated * +node::as_enumerated() +{ + return dynamic_cast(this); +} + + +asn1::typeref * +node::as_typeref() +{ + return dynamic_cast(this); +} +const asn1::typeref * +node::as_typeref() const +{ + return dynamic_cast(this); +} + +asn1::constructed * +node::as_constructed() +{ + return dynamic_cast(this); +} + +asn1::sequence * +node::as_sequence() +{ + return dynamic_cast(this); +} +asn1::choice * +node::as_choice() +{ + return dynamic_cast(this); +} + +asn1::set * +node::as_set() +{ + return dynamic_cast(this); +} + +asn1::object * +node::as_object() +{ + return dynamic_cast(this); +} + +asn1::integer * +node::as_integer() +{ + return dynamic_cast(this); +} + +asn1::assignment * +node::as_assignment() +{ + return dynamic_cast(this); +} + +asn1::object_identifier * +node::as_object_identifier() +{ + return dynamic_cast(this); +} + +asn1::parameters * +node::as_parameters() +{ + return dynamic_cast(this); +} +asn1::parameter * +node::as_parameter() +{ + return dynamic_cast(this); +} + + +asn1::act_parameters * +node::as_act_parameters() +{ + return dynamic_cast(this); +} + +asn1::parameters *node::parameters() const +{ + return m_parameters->as_parameters() ; +} + +asn1::act_parameters *node::act_parameters() const +{ + return m_parameters->as_act_parameters() ; +} + +const char * +type::name() const +{ + switch (m_id) + { + +#define ASN1_TYPE(cls,parent,id) \ + case ASN1_##id : return #id; + +#define ASN1_STRING_TYPE(cls,parent,id) \ + case ASN1_STRING_##id : return #id; + +#include "adt/asn1_type.inc" + default: + { + std::cerr<<"type::name ERROR unknow : "< +#include +#include +#include +#include +#include +#include // std::shared_ptr +#include // exception +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/sys/log.h" +#include "aeb/pointer/intrusive_ptr.h" + +namespace asn1 +{ + class object_identifier; + class parameters; + class parameter; + class act_parameters; + class typeref; + class integer; + class sequence; + class assignment; + class enumerated; + class choice; + class set; + class object; + + inline char op_substitute(char c) + { + return (c == '-')?'_':c; + } + class node; + class reference; + class simple_reference; + class objectclass_reference; + class module; + class constructed; + class valuetype; + class typenode; + /** + * + */ + struct find_node { + find_node(const std::string &s) : m_s(s){} + bool operator ()(asn1::node *n) ; + std::string m_s; + }; + /** + * + */ + struct find_type { + find_type(const std::string &s) : m_s(s){} + bool operator ()(asn1::node *n) ; + std::string m_s; + }; + /** + * + */ + struct find_value { + find_value(const std::string &s) : m_s(s){} + bool operator ()(asn1::node *n) ; + std::string m_s; + }; + + /** + * This is a generic class for all kind of elements that can + * be found in an ASN1 definition. In terme, this class shall + * become an asbstract class so that it cannot be instantiated. + * + */ + class node + { + INTRUSIVE_DECLARATION(node) + public: + typedef std::list node_list; + typedef std::list::iterator iterator; + typedef std::list::const_iterator const_iterator; + + public: + // Constructor , Destructors + node(const std::string name, meta m = meta::INVALID); + + node(const std::string name, type t = type::INVALID,meta m = meta::INVALID); + + node(const node &n) ; + + node(const char *name) ; + + virtual ~node() {}; + // Deep copy + virtual node *clone() ; + + enum color { + CL_GREEN = 0, + CL_ORANGE = 1, + CL_REENTRANT = 2, + CL_RED = 3 + }; + + // Generated stuff + void set_generated(bool b) ; + + color get_color(void)const + {return m_is_generated;}; + + void set_color(asn1::node::color c) + {m_is_generated = c;}; + + bool is_generated() ; + + // Name stuff + const std::string name() const; + + const void name(const std::string &n) + {m_name = n;}; + + const std::string cpp_name() ; + // Casts + asn1::integer *as_integer(); + asn1::valuetype *as_value_type(); + const asn1::typeref *as_typeref() const; + asn1::typeref *as_typeref() ; + asn1::typenode *as_typenode(); + + asn1::constructed *as_constructed(); + + asn1::choice *as_choice(); + asn1::sequence *as_sequence(); + asn1::enumerated *as_enumerated(); + asn1::set *as_set(); + asn1::object *as_object(); + + asn1::object_identifier *as_object_identifier(); + + asn1::parameters *as_parameters(); + asn1::parameter *as_parameter(); + asn1::act_parameters *as_act_parameters(); + asn1::assignment *as_assignment(); + // Iterators ... +#define NODE_REMOVE_ITERATORS + // + inline bool is_primitive() const + { return m_type_id() >= type::ASN1_BOOLEAN + && m_type_id() <= type::ASN1_STRING_ObjectDescriptor ; + } + inline bool is_constructed() const + { return (m_type_id() >= type::ASN1_SEQUENCE + && m_type_id() <= type::ASN1_SELECTION ) + || m_type_id() == type::ASN1_ENUMERATED; + } + + inline bool is_object_identifier() const + { return m_type_id() == type::ASN1_OBJECT_IDENTIFIER ; }; + + inline bool is_asn1() const + { return is_primitive() || is_constructed() || is_object_identifier(); } + + inline bool is_choice() const + { return m_type_id() == type::ASN1_CHOICE ; }; + + inline bool is_reference() const + { return m_type_id() == type::ASN1_REFERENCE ; }; + + inline bool is_extensible() const + { return m_type_id() == type::ASN1_EXTENSIBLE ; }; + + virtual bool equals(const node &_n ) const { return false; }; + // str Type, type_id + inline void type_node(node *t) { m_type = t; } + + inline node *type_node() const { return m_type; } + + // parameter stuff does not apply to all nodes + // see if this can be moved to another place + asn1::parameters *parameters() const; + + inline void parameters(asn1::constructed *n) + { m_parameters = n; }; + + asn1::act_parameters *act_parameters() const; + + inline void act_parameters(asn1::constructed *n) + { m_parameters = n; }; + + + // str Identifier + inline void identifier(node *t) { m_identifier = t; } + + inline node *identifier() const { return m_identifier; } + + const std::string identifier_name( ) ; + + const std::string identifier_cpp_name( ) ; + + inline std::string uid(void) {return m_uid;}; + + // Type_id stuff + inline void type_id(asn1::type::id t) { m_type_id = t; } + + inline type type_id() const {return m_type_id;}; + + inline asn1::value *value() const { return m_value;}; + + inline void value(asn1::value *v) {m_value =v;}; + // Meta stuff + inline void meta_id(asn1::meta::id m) {m_meta = m;} + + inline meta meta_id() const {return m_meta ;} + + inline bool operator >(const node &n) {return m_meta > n.m_meta;}; + /** + * two nodes are equal if, they are of the same type, + * have the same tagging, + * have the same contraints + * have the same elements + * + */ + bool operator ==(const node &_n) { return equals(_n) ;}; + static bool op_sort(asn1::node *n1,asn1::node *n2) + { +#if 0 + std::cout<<"Compare : "<meta_id()<<" "<meta_id()<meta_id()) > (n2->meta_id()); + } + + /// Tag stuff + struct tag_type { + //inline tag_type() : m_class(TC_NOCLASS),m_mode(TM_DEFAULT) {}; + enum { + TC_NOCLASS , + TC_UNIVERSAL = 0, + TC_APPLICATION = 1, + TC_CONTEXT_SPECIFIC = 2, + TC_PRIVATE = 3 + } m_class; + + enum { + TM_DEFAULT, + TM_IMPLICIT, + TM_EXPLICIT, + TM_AUTOMATIC + } m_mode; + inline long byte() const { return m_class<<6 | m_value; }; + inline long get_tag() const { return m_value<<2 | m_class; }; + long m_value; + bool m_set; + }; + // Do not set -1 tags + inline void tag(tag_type &t) + { if (t.m_value != -1 ) {m_tag = t; m_tag.m_set = true;} }; + + inline tag_type tag() const {return m_tag;}; + inline tag_type &tag() {return m_tag;}; + inline bool tagged() const + { return m_tag.m_set && m_tag.m_value>=0 && m_tag.m_class>= 0; }; + // Marker flags + struct marker_type + { + inline bool is_omitable() const + { return (m_flags & FL_OMITABLE) == FL_OMITABLE; }; + + inline bool is_optional() const + { return (m_flags & FL_OPTIONAL) == FL_OPTIONAL; }; + + inline bool is_default() const + { return m_flags == FL_DEFAULT; }; + + enum eFlag { + FL_NONE = 0, + FL_OMITABLE = 0x02, /* 00010 can be absente in encoding */ + FL_OPTIONAL = 0x07, /* 00111 default value */ + FL_DEFAULT = 0x0F /* 01111*/ + } m_flags; + + marker_type(eFlag t = FL_NONE) : m_flags(t), m_value1(NULL) + {}; + + marker_type(const marker_type &m) + : m_flags(m.m_flags) ,m_value1(m.m_value1) + {}; + marker_type & operator = (const marker_type &m) + { + m_value1 = m.m_value1; + m_flags = m.m_flags; + m_value = m.m_value; return *this; + }; + //TODO Should also check value BUG + bool operator ==(const marker_type &m) const + { + return m_flags == m.m_flags; + }; + int m_value; /* When default value + I would like it to be of type asn1::value::ptr */ + asn1::value::ptr m_value1; + }; + + marker_type flags() const { + // std::cout<<"node::flags() "< &l) const; + asn1::module *from_module() const; + bool is_private() const; + + protected: + node *m_parent; + asn1::meta m_meta; + asn1::type m_type_id; + std::string m_name; + node *m_next; + + node *m_type; // 2011/05/03 must be deprecated + asn1::value *m_value; // Should become part of valuetype + node *m_identifier; + asn1::constructed *m_parameters; + asn1::constraint m_constraints; + tag_type m_tag; + marker_type m_marker; + union { + long long m_value_long; + double m_value_double; + } ; + color m_is_generated; + std::string m_uid; + }; + // Helper function for code generation + const std::string + cpp_name(const std::string &lname); + + inline bool find_node::operator ()(asn1::node *n) + { + if (n == NULL) return false; + //std::cout<<" mds as:"<name()<name()); + }; + inline bool find_type::operator ()(asn1::node *type) + { + if (type == NULL) return false; + //std::cout<<" mds as:"<name()<identifier_name()); + }; + + inline bool find_value::operator ()(asn1::node *type) + { + if (type == NULL) return false; + //std::cout<<" mds as:"<name()<meta_id()() == asn1::meta::VALUE) && !m_s.compare(type->name()); + }; + +/* Add a container class here */ + +/* ALL asn1 Datatypes that can be instantiated */ +#include "asn1_node_typenode.h" +#include "asn1_node_constructed.h" +#include "asn1_node_imports.h" +#include "asn1_node_exports.h" +#include "asn1_node_parameters.h" +#include "asn1_node_typeref.h" +#include "asn1_node_selection.h" +#include "asn1_node_field.h" +#include "asn1_node_alternative_choice.h" +#include "asn1_node_primitive.h" +#include "asn1_node_choice.h" +#include "asn1_node_sequence.h" +#include "asn1_node_sequence_of.h" +#include "asn1_node_set.h" +#include "asn1_node_set_of.h" +#include "asn1_node_classdef.h" +#include "asn1_node_valuetype.h" +#include "asn1_node_object.h" +#include "asn1_node_assignment.h" + +} +#include "asn1_reference.h" +/* + * vim:et:sw=2:ts=2 + */ +#endif diff --git a/adt/asn1_node_alternative_choice.h b/adt/asn1_node_alternative_choice.h new file mode 100644 index 0000000..649f64e --- /dev/null +++ b/adt/asn1_node_alternative_choice.h @@ -0,0 +1,16 @@ +#ifndef ASN1_NODE_ALTERNATIVE_CHOICE_H +#define ASN1_NODE_ALTERNATIVE_CHOICE_H + + +class alternative_choice : public node +{ + public: + + alternative_choice() ; + ~alternative_choice() ; + + protected: +}; + + +#endif diff --git a/adt/asn1_node_assignment.cpp b/adt/asn1_node_assignment.cpp new file mode 100644 index 0000000..7911d2a --- /dev/null +++ b/adt/asn1_node_assignment.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +assignment::assignment(const std::string &s) + : node(s,type::INVALID,meta::INVALID) +{ +} + +assignment::assignment(const std::string &s,asn1::type t,asn1::meta m) + : node(s,t,m) +{ +} + +void assignment::set_type(asn1::node *type) +{ + type_node(type); +} + +typenode * +assignment::get_type() const +{ + return reinterpret_cast(type_node()); +} + +objectset * +assignment::get_objectset() const +{ + return reinterpret_cast(type_node()); +} + +parameter * +assignment::have_parameter(asn1::node *actp,long &idx) +{ + idx = 0; + if (actp && m_parameters) + { + for (asn1::node::iterator pit = parameters()->begin(); + pit != parameters()->end(); + ++pit,++idx) + { + asn1::parameter *p = (*pit)->as_parameter(); + if (p && p->get_typeref()->name() == actp->name()) + return p; + } + + } + return NULL; +} +} + +/** + * vim: et sw=2 ts=2: + */ diff --git a/adt/asn1_node_assignment.h b/adt/asn1_node_assignment.h new file mode 100644 index 0000000..6d07141 --- /dev/null +++ b/adt/asn1_node_assignment.h @@ -0,0 +1,54 @@ +#ifndef ASN1_NODE_ASSIGNMENT_H +#define ASN1_NODE_ASSIGNMENT_H + + +/** + * This class represents an + * asn1 assignment examples : + * Type ::= SEQUENCE ... + * OBJECTSET ::= {} and so on + * + */ +class assignment : public node +{ + public: + assignment(const std::string &s) ; + + assignment(const assignment &a) + : node(a) + {} + + assignment(const std::string &s,asn1::type t,asn1::meta m) ; + + assignment *clone() { return new assignment (*this); } + // Should replace node with typenode + void set_type(asn1::node *n); + + typenode *get_type() const; + objectset *get_objectset() const; + /** + * node is an act_parameter ... + */ + parameter *have_parameter(asn1::node *,long &idx); + protected: +}; + +#define ASSIGNMENT(tp,cls,parent) \ + class cls ## _assignment : public parent \ + {\ + public:\ + cls ## _assignment (const std::string &s) \ + : parent( s,asn1::type::INVALID,asn1::meta::tp) {} ; \ + cls ## _assignment (const cls ## _assignment &a) \ + : parent(a) \ + {}; \ + ~cls ## _assignment () {}; \ + cls ## _assignment *clone() { return new cls ## _assignment(*this);}; \ + }; + +#include "asn1_meta.inc" + +#endif /*ASN1_NODE_ASSIGNMENT_H*/ +/** + * vim: et sw=2 ts=2: + */ diff --git a/adt/asn1_node_choice.cpp b/adt/asn1_node_choice.cpp new file mode 100644 index 0000000..ed75c5e --- /dev/null +++ b/adt/asn1_node_choice.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" +#include "asn1_resolver.h" + + +namespace asn1 +{ + +choice::choice() : constructed("CHOICE",type::ASN1_CHOICE) +{ +} + +choice::choice(const choice &c) : constructed(c.name(),type::ASN1_CHOICE) +{ + std::cerr<<"choice::choice copy "<(*it); + std::cerr<<"choice::choice"<name()<clone(); + nn->set_parent(this); + nn->get_type()->set_parent(this); + append(nn); + std::cerr<<"choice::choice end "<name()<get_parent()); + } + std::cerr<<"choice::choice copy end "<(*begin()) -> get_type(); + + // std::cerr<<"choice::"<<__FUNCTION__<<" Begin type "<tagged()) + { + //std::cerr<<"choice::"<<__FUNCTION__<<" tagged type "<name()<<" \n"; + return ftype->tag(); + } + // Untagged reference, + // Check realtype + if (asn1::typeref *ref = ftype->as_typeref()) + { + std::cerr<<"choice::"<<__FUNCTION__<<" type "<name()<get_real_type()) + { + // tagged realtype + if (rtype->tagged()) + { + std::cerr<<"choice::"<<__FUNCTION__<<" tagged type "<name()<<" \n"; + assert(rtype->tag().m_value != -1); + return rtype->tag(); + } + if (asn1::choice *c = dynamic_cast(rtype)) + { + return c->get_tag(r); + } + // Not a tagged type , Not Choice + if (rtype->tag().m_value != -1) + return rtype->tag(); + // Still a reference, dig deeper, + if (rtype->as_typeref()) + { + ftype = rtype; + goto loopref; + } + // tag is -1 assert an error I don't know what to do + std::cerr<<"choice::"<<__FUNCTION__<<" type "<name()<from_module(); + std::cerr<<"choice::"<<__FUNCTION__<<" type "<name()<<"::"<name()<name()<tag().m_value != -1) + return ftype->tag(); + if (asn1::choice *nc = dynamic_cast(ftype)) + { + return nc->get_tag(r); + } + std::cerr<<"choice::"<<__FUNCTION__<<" type "<name()< +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ +namespace internal +{ + +/** + * Abstract state ... + */ +state::state() +{ +} + +void state::visit(visitor *v) const +{ + ; +} +/** + * transition state + */ +transition::transition(transition_type t) : m_type(t),m_next(NULL) +{ +} + +void transition::visit(visitor *v) const +{ + v->visit_transition(dynamic_cast(*this)); +} + +/** + * split state + */ +split::split(state *start,state *end) + : m_first(start),m_second(end) +{ +} + +void split::visit(visitor *v) const +{ + ; + v->visit_split(dynamic_cast(*this)); +} + +/** + * match state + */ +match::match() +{ +} + +void match::visit(visitor *v) const +{ + v->visit_match(dynamic_cast(*this)); +} + +} /* end namespace internal */ + +/** + * CLASS classdef_nfa + */ +classdef_nfa::classdef_nfa(state *start,state *end,std::shared_ptr pool) + : m_start(start),m_end(end), m_pool(pool) +{ +} + + +void +classdef_nfa::visit(visitor *v) const +{ + v->visit(*m_start,*m_end); +} + +/** + * CLASS syntax_parser + */ + +syntax_parser::fragment::fragment(std::shared_ptr pool) + : m_pool(pool),m_start(NULL) +{ +} + +syntax_parser::fragment::fragment( asn1::node *n + , std::shared_ptr pool) + : m_pool(pool) +{ + + transition *trans = NULL; + if (n->type_id()() == asn1::type::INVALID) + { + trans = m_pool->make_transition(transition::eToken); + } else + trans = m_pool->make_transition(transition::eType); + trans->m_node_type = n; + m_out_edges.push_back(&(trans->m_next)); + m_start = trans; +} + +std::string +syntax_parser::fragment::name() const +{ + if (m_start) + { + if (transition *t = dynamic_cast(m_start)) + { + std::string s("m_node_type->name() +">"; + return s; + } + if (dynamic_cast(m_start)) + { + return std::string(""); + } + if (dynamic_cast(m_start)) + { + return std::string(""); + } + } + return std::string(""); +} + +/** + * + * .-------. .-------. + * --->| frag1 |--->| frag2 |---> + * '-------' '-------' + */ +void +syntax_parser::fragment::concat(const fragment &frag) +{ + for (size_t i = 0 ; i < m_out_edges.size() ; i++) + { + *m_out_edges[i] = frag.m_start; + } + m_out_edges = frag.m_out_edges; +} + + +/** + * + * + * .-------. + * .------->| frag2 |---> + * | '-------' + * .-------. + * --->| split | + * '-------' + * | .-------. + * '--------| frag1 |---> + * '-------' + */ +void +syntax_parser::fragment::_split(const fragment &frag) +{ + m_start = m_pool->make_split(m_start,frag.m_start); + // Append outgoing edges from frag + for ( size_t i = 0 ; i < frag.m_out_edges.size() ; i++) + { + m_out_edges.push_back(frag.m_out_edges[i]); + } +} + +/** + * + * + * .------. + * .------->| frag |---> + * | '------' + * .-------. + * --->| split | + * '-------' + * | + * '-------------------> + */ +void +syntax_parser::fragment::zero_or_one() +{ + split *s = m_pool->make_split(m_start,NULL); + // Append outgoing edges from frag + m_out_edges.push_back(&(s->m_second)); + m_start = s; +} + + +/** + * + */ +std::shared_ptr +syntax_parser::fragment::to_nfa() +{ + match *m = m_pool->make_match(); + + for ( size_t i = 0 ; i < m_out_edges.size() ; i++) + { + *m_out_edges[i] = m ; + } + return std::shared_ptr( + new classdef_nfa(m_start,m,m_pool) ); +} + + + + + +/** + * CLASS thomson_algorithm + */ + +thomson_algorithm::thomson_algorithm() + : m_matched(false) + , m_object(NULL) + , m_start(NULL), m_end(NULL) + , m_current() , m_next() +{ +} + + +bool +thomson_algorithm::accept(object *o,const std::shared_ptr nfa) +{ + m_object = o; + m_current_it = o->begin(); + nfa->visit(this); +#if 0 + std::cerr<<"thomson_algorithm::accept( matched "<name()<end()) && (m_current.size() != 0)) + { + m_matched = false; +#if 0 + std::cerr<<"\nSTART NODE "<<" matched: "<visit(this); + } + ++m_current_it; // advance + m_current.swap(m_next); + m_next.clear(); +#if 0 + if (m_current_it == m_object->end()) + { + std::cerr<<"NEXT NODE "<<" previous matched: "<name()<<" previous matched: "<(*(m_current.begin())); + if (_next) + { + _next->visit(this); + } +} + + +void +thomson_algorithm::visit_transition(const transition &trans) +{ + asn1::node *field = *m_current_it; + // Check if there is a match + if (m_current_it != m_object->end()) + { + if ( trans.is_token() + && !field->name().compare(trans.m_node_type->name()) ) + { + // Ok, got expected token + m_next.insert(trans.m_next); + } else if (trans.is_type() ) + { // Check type + //std::cerr<<"visite_transition MATCH "<name(); + //std::cerr<<" nd:"<name()<parsed_field(trans.m_node_type->name(),field); + m_next.insert(trans.m_next); + } else + { + //std::cerr<<"visite_transition no match "<name(); + //std::cerr<<" nd:"<name()<end()) + std::cerr<<"visite_split "<name()<visit(this); + s.m_second->visit(this); +} + + +void +thomson_algorithm::visit_match(const match &trans) +{ + asn1::node *field = *m_current_it; +#if 0 + if (m_current_it != m_object->end()) + std::cerr<<"visite_match "<name()<(); +} + +// +classdef::~classdef() +{ +} + +// +bool +classdef::check_object_syntax(object *_o) +{ + thomson_algorithm algo; + bool result = algo.accept(_o,m_nfa); + return result; +} + +// +classdef::fragment * +classdef::parse_token(asn1::node *t) +{ + fragment *frag = new fragment(t,m_pool); + return frag; +} + +// +classdef::fragment * +classdef::parse_optional(fragment *frag) +{ + assert(frag != NULL); + frag->zero_or_one(); + return frag; +} +// +classdef::fragment * +classdef::parse_append(fragment *f1,fragment *f2) +{ + assert(f1 != NULL && f2!=NULL); + f1->concat(*f2); + return f1; +} +// +classdef::fragment * +classdef::parse_new() +{ + fragment *frag = new fragment(m_pool); + return frag; +} +// +void +classdef::set_nfa(fragment *f) +{ + assert(f != NULL); + m_nfa = f->to_nfa(); +} + +// +void +classdef::add_field(asn1::classfield *c) +{ + append(c); + if (c->type_node() && c->type_node()->flags().is_optional()) + { + m_optionals.push_back(c); + } +} + +asn1::classfield * +classdef::get_classfield(const std::string &name) +{ + asn1::node::iterator found = std::find_if( begin() + , end() + , asn1::find_node(name)); + if (found != end() ) + return dynamic_cast(*found); + + return NULL; +} + +struct fieldcmp +{ + bool operator()(asn1::node *a,asn1::node *b) + { + return a->type_id()() < b->type_id()(); + } +}; +// +void +classdef::sort_fields() +{ + //std::sort(begin(),end(),fieldcmp()); + m_nodes.sort(fieldcmp()); +} + +} /* end namespace asn1 */ diff --git a/adt/asn1_node_classdef.h b/adt/asn1_node_classdef.h new file mode 100644 index 0000000..0106416 --- /dev/null +++ b/adt/asn1_node_classdef.h @@ -0,0 +1,364 @@ +#ifndef ASN1_NODE_CLASSDEF_H +#define ASN1_NODE_CLASSDEF_H +#if defined(_WIN32) +/* MSDN Visual Studion 14 exception handling ... */ +#pragma warning(disable : 4290) +#endif + +class object; +namespace internal { + struct state; + struct transition; + struct split; + struct match; + + class visitor + { + public: + virtual void visit(const state &start,const state &end) = 0; + + virtual void visit_transition(const transition &trans) = 0; + + virtual void visit_split(const split &trans) = 0; + + virtual void visit_match(const match &trans) = 0; + }; + + /** + * + */ + struct state + { + state(); + + virtual void visit(visitor *) const; + }; + + /** + * + */ + struct transition : public state + { + typedef enum { eToken,eType} transition_type; + transition(transition_type); + + inline bool is_token() const { return m_type == eToken; }; + inline bool is_type() const { return m_type == eType; }; + + virtual void visit(visitor *) const; + + transition_type m_type; + node *m_node_type; + state *m_next; + }; + + /** + * + */ + struct split : public state + { + split(state *first,state*second); + + virtual void visit(visitor *) const; + state *m_first; + state *m_second; + }; + /** + * + */ + struct match : public state + { + match(); + + virtual void visit(visitor *) const; + }; + + /** + * StatePool stack + */ +class state_pool { + + //! \brief state_pool memory representation. + //! + //! No data alignement is performed when a Chunk + //! allocates memory, i.e. it can't be used in a + //! general case. + template + struct Chunk { + public: + //! \brief Default constructor. + //! \post The next pointer is NULL + //! \post The data_index is set to 0. + Chunk(): next(NULL), data_index(0) {} + + //! \brief Reserve N bytes in this chunk. + //! \param nbytes Number of bytes to allocate/reserve. + //! \pre The requested number of bytes (nbytes) must be + //! smaller or equal (<=) to the chunk_size. + //! \return A raw pointer to the begining of the reserved + //! memory space. + void* reserve(size_t nbytes) throw(std::logic_error) { + + // Make sure that a Chunk can really + // serve a request of this size. + if (nbytes > chunk_size) + throw std::logic_error("state_pool::Chunk::reserve(): the " + "requested number of bytes is bigger " + "than a chunk_size."); + + // Make sure that we have enough room serve + // the request. If not return NULL. The pool + // will handle this by allocating a new chunk. + if (chunk_size - data_index >= nbytes) { + void* dptr = &data[data_index]; + data_index += nbytes; + return dptr; + } + + return NULL; + } + + Chunk* next; /**< A pointer to the next chunk. */ + unsigned int data_index; /**< Current position in the data array. */ + char data[chunk_size]; /**< Allocation array containing chunk_size bytes. */ + }; + + typedef Chunk<64> MemoryChunk; + +public: + + //! \brief Default constructor. + state_pool() { + root_chunk = last_chunk = new MemoryChunk; + } + + //! \brief Destructor. + //! + //! Free all memory associated to the states allocated from + //! this pool. Beware that it won't call the destructor on + //! those objects. + ~state_pool() { + while (root_chunk) { + MemoryChunk* temp_chunk = root_chunk; + root_chunk = root_chunk->next; + delete temp_chunk; + } + } + + //! \brief Construct a split state from the pool. + //! \param[in] first The first neighbor State. + //! \param[in] second The second neighbor State. + //! \return A pointer to the newly constructed split state. + split* make_split(state* first, state* second) { + void* _split = reserve(sizeof(split)); + new (static_cast(_split)) split(first, second); + return reinterpret_cast(_split); + } + + //! \brief Construct a transition state from the pool. + //! \param label The transition label. + //! \return A pointer to the newly constructed transition state. + transition* make_transition(transition::transition_type label) { + void* trans = reserve(sizeof(transition)); + new (static_cast(trans)) transition(label); + return reinterpret_cast(trans); + } + + //! \brief Construct a match state from the pool. + //! \return A pointer to the newly constructed match state. + match* make_match() { + void* _match = reserve(sizeof(match)); + new (static_cast(_match)) match(); + return reinterpret_cast(_match); + } + +protected: + + //! \brief Reserve N bytes from this pool. + //! \param nbytes Number of bytes to allocate/reserve. + //! \return A raw pointer to the begining of the reserved + //! memory space. + void* reserve(size_t nbytes) { + // Try to reserve N bytes from the last + // allocated memory chunk. + void* data = last_chunk->reserve(nbytes); + + // Check if it's a miss. If so, we'll + // need to allocate a new chunk. + if (!data) { + last_chunk->next = new MemoryChunk; + last_chunk = last_chunk->next; + data = last_chunk->reserve(nbytes); + } + + return data; + } + + state_pool(const state_pool&) {} + void operator=(const state_pool&) {} + + MemoryChunk* root_chunk; /**< First allocated chunk. */ + MemoryChunk* last_chunk; /**< Last allocated chunk. */ +}; + +} /* end namespace internal */ + +class syntax_parser; +class classdef_nfa +{ + protected: + friend class syntax_parser; + typedef internal::state state; + typedef internal::state_pool state_pool; + typedef internal::visitor visitor; + classdef_nfa(state *start,state *end,std::shared_ptr pool); + public: + + void visit(visitor *v) const; + protected: + state *m_start; + state *m_end; + std::shared_ptr m_pool; +}; + +/** + * fragments must be visible to the asn1 parser + * as it is the one the builds the parsing tree + */ +class syntax_parser +{ + public: + typedef internal::state state; + typedef internal::transition transition; + typedef internal::split split; + typedef internal::match match; + typedef internal::state_pool state_pool; + /** + * \brief Class representing a partial fragment of the nfa + */ + class fragment + { + public: + /** + * Build an empty fragment + */ + fragment(std::shared_ptr pool); + /** + * Build an transition framgent + */ + fragment(asn1::node *,std::shared_ptr pool); + + void concat(const fragment &frag); + + void _split(const fragment &frag); + + std::string name() const; + + void zero_or_one(); + + std::shared_ptr to_nfa(); + protected: + state *m_start; + std::vector m_out_edges; + std::shared_ptr m_pool; + }; + + protected: + std::shared_ptr m_pool; + +}; + + +/** + * + */ +class thomson_algorithm : public internal::visitor +{ + typedef internal::state state; + typedef internal::transition transition; + typedef internal::split split; + typedef internal::match match; + protected: + + public: + typedef std::set::const_iterator state_const_iterator; + thomson_algorithm() ; + + bool accept(object *o,const std::shared_ptr nfa); + + void visit(const state &start,const state &end); + + void visit_transition(const transition &trans); + + void visit_split(const split &trans); + + void visit_match(const match &trans); + protected: + bool m_matched; + node::iterator m_current_it; + object *m_object; // token to go through are in object + const state *m_start; + const state *m_end; + std::set m_current; + std::set m_next; +}; + +/** + * class definition. This object can be followed with syntax + * it should have code to build the parser for the defined syntax + * and check if the object defined respects the defined syntax + * + * in order to parser the tokens properly, I should passe the object as + * reference. The object contains the token, the parser will set + * the appropriate fields according to the tokens and the defined parser + */ +class classdef : public constructed +{ + public: + typedef syntax_parser::fragment fragment; + typedef syntax_parser::state_pool state_pool; + + typedef std::vector OptionalArrayType; + typedef OptionalArrayType::iterator OptionalIterator; + + classdef() ; + ~classdef() ; + /** + * At a given time, the with syntax must have been used. + * parse all token and build a simple automaton. + * + */ + fragment *parse_token(asn1::node *t); + // + fragment *parse_optional(fragment *f); + // + fragment *parse_append(fragment *f1,fragment *f2); + // + fragment *parse_new(); + // + void set_nfa(fragment *f); + // + void start_syntax(); + + bool check_object_syntax(object *_o); + // + void add_field(asn1::classfield *); + + asn1::classfield *get_classfield(const std::string &name) ; + // Order fields + void sort_fields(); + + OptionalIterator opt_begin() { return m_optionals.begin() ; } + OptionalIterator opt_end() { return m_optionals.end() ; } + + size_t opt_size( ) const { return m_optionals.size(); } + + protected: + OptionalArrayType m_optionals; + std::shared_ptr m_pool; + std::shared_ptr m_nfa; + // Should own a list of tokens +}; + + +#endif diff --git a/adt/asn1_node_constructed.cpp b/adt/asn1_node_constructed.cpp new file mode 100644 index 0000000..e422c98 --- /dev/null +++ b/adt/asn1_node_constructed.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +/** + * + */ +constructed::constructed(const constructed &c) + : typenode(c) +{ + +} + +asn1::constructed * +constructed::clone() +{ + asn1::constructed *nc = new constructed(*this); + std::cerr<<"constructed::clone "<(_nn); + bool eq = (type_id()() == _n.type_id()()); + if ( ! is_empty() && eq) + { + const_iterator field_it,nfield_it; + for (field_it = begin() , nfield_it =_n.begin() + ; field_it != end() && nfield_it != end() + ; ++field_it, ++nfield_it ) + { + asn1::field *f = dynamic_cast(*field_it); + asn1::field *nf = dynamic_cast(*nfield_it); + if ( f->get_type() != NULL + && nf->get_type() != NULL) + { + asn1::node *t = f->get_type(); + asn1::node *nt = nf->get_type(); + eq = eq && (*t == *nt) ; + if (! eq ) + return false; // Don't continue looking + } + } + if ( (field_it == end() ) && (nfield_it == _n.end()) ) + { + return flags() == _n.flags(); + } + return false; + } else + return ( eq ); +} + +// Lookup for field name in node list +asn1::field * +constructed::get_field(const std::string &name) +{ + asn1::node::iterator found = std::find_if( begin() + , end() + , asn1::find_node(name)); + if (found != end() ) + return dynamic_cast(*found); + + return NULL; +} + +} diff --git a/adt/asn1_node_constructed.h b/adt/asn1_node_constructed.h new file mode 100644 index 0000000..7cbf525 --- /dev/null +++ b/adt/asn1_node_constructed.h @@ -0,0 +1,66 @@ +#ifndef ASN1_NODE_CONSTRUCTED_H +#define ASN1_NODE_CONSTRUCTED_H + +/** + * + * Container class. All types that contain elements must + * ibherit from this class. Example: + * bit_string, enumerate,integer + * sequence,set,choice,object,objectclass + * imports,exports,paramters,act_parameters + */ +class constructed : public typenode +{ + public: + typedef node::iterator field_iterator; + typedef node::const_iterator const_field_iterator; + + // constructed(const std::string s,type _t) : node(s,_t) { } ; + + constructed(const std::string name, type t = type::INVALID,meta m = meta::TYPE) + : typenode(name,t,m) {}; + + constructed(const constructed &c) ; + + constructed *clone() ; + + virtual ~constructed() {}; + + virtual bool equals(const node &_n) const ; + + node::iterator begin() {return m_nodes.begin();} + node::const_iterator begin() const {return m_nodes.begin();} + + node::iterator end() {return m_nodes.end();} + node::const_iterator end() const {return m_nodes.end();} + + size_t size() const {return m_nodes.size();} + + bool is_empty() const { return m_nodes.begin() == m_nodes.end(); }; + // alternative_constructed_iterator + node::node_list &nodes() { return m_nodes; } + // Lookup for field name in node list + asn1::field *get_field(const std::string &name); + + inline void sort_childs() + { + m_nodes.sort(node::op_sort); + }; + + void append(node *n) + { + if (n) + { + m_nodes.push_back(n); + if (n->get_parent() == NULL ) n->set_parent(this); + } else + { + std::cerr<<"node::append NULL node is wierd"< +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +/** + * + */ +field::field(const field &f) + : node(f) +{ + std::cerr<<"field::field copy - "<clone(); + nt->identifier(this); + type_node(nt); +#if 0 + if (nt->type_id()() != asn1::type::ASN1_REFERENCE) + { + nt->name(name()+"_t"); + } +#endif + } +} + +/** + * + */ +field::field(const std::string _s,asn1::node *_type) + : node(_s,asn1::type::INVALID) +{ + type_node(_type); + if (_type != NULL) + _type->identifier(this); +}; + +typenode * +field::get_type() const +{ + return reinterpret_cast(type_node()); +} + +void +field::set_type(asn1::typenode *t) +{ + type_node(t); +} + +/** + * + */ +field * +field::clone() +{ + return new field(*this); +} + +/** + * extension field class + */ +extension_field::extension_field(const extension_field &ef) + : field("...",NULL) +{ +} + +extension_field * +extension_field::clone() +{ + return new extension_field(*this); +} + +extension_field::extension_field() + : field("...",NULL) +{ + type_id(asn1::type::ASN1_EXTENSIBLE); +} + +/** + * + */ +classfield::classfield(const std::string &_s,type t) + : node(_s,t,meta::OBJECTFIELD) + , m_reference(NULL) +{ +} +typenode * +classfield::get_type() const +{ + assert( 0 && "Should not be called"); + return NULL; +} + +/** + * CLASSFIELD FTVSF + */ +classfield_ftvf::classfield_ftvf( const std::string &n,asn1::typenode *t,type _t) + : classfield(n,_t) +{ + type_node(t); +} +typenode * +classfield_ftvf::get_type() const +{ + return reinterpret_cast(type_node()); +} + +classfield_ftvsf::classfield_ftvsf( const std::string &n,asn1::typenode *t,type _t) + : classfield(n,_t) +{ + type_node(t); +} +typenode * +classfield_ftvsf::get_type() const +{ + return reinterpret_cast(type_node()); +} +/** + * CLASSFIELD OSF + */ +classfield_osf::classfield_osf( const std::string &n,asn1::typeref *t,type _t) + : classfield(n,_t) +{ + type_node(t); +} +typeref * +classfield_osf::get_typeref() const +{ + return reinterpret_cast(type_node()); +} + +typenode * +classfield_osf::get_type() const +{ + return reinterpret_cast(type_node()); +} + + +} diff --git a/adt/asn1_node_field.h b/adt/asn1_node_field.h new file mode 100644 index 0000000..6519713 --- /dev/null +++ b/adt/asn1_node_field.h @@ -0,0 +1,120 @@ +#ifndef ASN1_NODE_FIELD_H +#define ASN1_NODE_FIELD_H + +/** + * This class represents the componentType in ASN1 definition + * -> It's most lickely that "components of" will also be handled + * by this class. + * -> SEQUENCE AND SET contained elements are fields + */ +class field : public node +{ + field(const field &f); + public: + field *clone(); + + field(const std::string _s,asn1::node *_type) ; + ~field() {}; + + typenode *get_type() const; + void set_type(asn1::typenode *t); + // a field in set or sequence, use same type for choice as well + protected: +}; + +/** + * @brief represents the ... in ASN1 specification + * still missing the possible exception value. + */ +class extension_field : public field +{ + protected: + extension_field(const extension_field &ef); + public: + extension_field *clone(); + extension_field(); + protected: + // Exception should be added here +}; + + +/** + * + * It would have been good to have function like get + * components this would return the list of components + */ +class components_of : public field +{ + public: + components_of(asn1::node *_typeref) + : field("components_of",_typeref) + { + type_node(_typeref); + _typeref->identifier(this); + type_id(asn1::type::ASN1_COMPONENTS_OF); + } + asn1::typeref *get_typeref() + { + return dynamic_cast(type_node()); + } + protected: +}; + +/** + * Classfield classes + */ +/** + * + */ +class classfield : public node +{ + public: + + classfield(const std::string &_s,type t); + + ~classfield() {}; + + // a field in set or sequence + // 2017/05/17 does not work yet !!! 15 errors in hpp + inline reference *get_reference() const { return m_reference;}; + inline void set_reference(reference *r) {m_reference =r;}; + virtual typenode *get_type() const; + protected: + asn1::reference *m_reference; +}; + + +#define ASN1_CLASSFIELD_GEN(cls,parent,tp) \ + class cls : public parent \ + {\ + public:\ + cls(const std::string &s) : parent( s,tp) {} ; \ + ~cls() {}; \ + + +#define ASN1_CLASSFIELD_ADD_classfield_tf ; +#define ASN1_CLASSFIELD_ADD_classfield_ftvf \ + classfield_ftvf( const std::string &n \ + , asn1::typenode *t \ + , type _t = asn1::type::ASN1_CLASSFIELD_FTVF) ; \ + typenode *get_type() const; +#define ASN1_CLASSFIELD_ADD_classfield_vtvf ; +#define ASN1_CLASSFIELD_ADD_classfield_ftvsf \ + classfield_ftvsf( const std::string &n \ + , asn1::typenode *t \ + , type _t = asn1::type::ASN1_CLASSFIELD_FTVSF) ; \ + typenode *get_type() const; +#define ASN1_CLASSFIELD_ADD_classfield_vtvsf ; +#define ASN1_CLASSFIELD_ADD_classfield_of ; +#define ASN1_CLASSFIELD_ADD_classfield_osf \ + classfield_osf( const std::string &n \ + , asn1::typeref *t \ + , type _t = asn1::type::ASN1_CLASSFIELD_OSF) ; \ + typeref *get_typeref() const; \ + typenode *get_type() const; + +#define ASN1_CLASSFIELD_TYPE(cls,parent,tp) \ + ASN1_CLASSFIELD_GEN(cls,parent,asn1::type::ASN1_##tp) ASN1_CLASSFIELD_ADD_##cls }; + +#endif + diff --git a/adt/asn1_node_imports.cpp b/adt/asn1_node_imports.cpp new file mode 100644 index 0000000..809681f --- /dev/null +++ b/adt/asn1_node_imports.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +bool +import_list::get_item(const std::string &type_name,import *&imp,typeref *&ref) +{ + bool ret = false; + + asn1::node::iterator it = begin(); +// GEN_LOG_DEBUG("lookup for type %s\n",type.c_str()); + for (; it != end() ;it++) + { + asn1::import *import = dynamic_cast(*it); + + if (asn1::typeref *_ref = import->get_item(type_name)) + { + +// GEN_LOG_DEBUG("found %s in %s\n",type_name.c_str(),import->identifier()->name().c_str()); + imp = import; + ref = _ref; + ret = true; + break; + } + } + return ret; +} + +asn1::typeref * +import::get_item(const std::string &item) +{ + + asn1::node::iterator found = std::find_if( begin() + , end() + , asn1::find_node(item)); + if (found != end() ) + return (*found)->as_typeref(); + return NULL; +} + +} +/** + * vim: et sw=2 ts=2 list: + */ diff --git a/adt/asn1_node_imports.h b/adt/asn1_node_imports.h new file mode 100644 index 0000000..1eb7813 --- /dev/null +++ b/adt/asn1_node_imports.h @@ -0,0 +1,47 @@ +#ifndef ASN1_NODE_IMPORTS_H +#define ASN1_NODE_IMPORTS_H + +class import; +/** + * import_list class contains a list + * of import. + * + */ +class import_list : public constructed +{ + public: + + import_list() + : constructed("IMPORTS",type::INVALID) {}; + ~import_list() {}; + + /** + * @brief find type_name in import_list of current module. + * if found return true. ref and imp will be initialized + * if not found ref and imp are unchanged. + */ + bool get_item(const std::string &type_name,import *&imp,typeref *&ref); + // alternative_imports_iterator + protected: +}; + +/** + * import class contains the elements imported. + * + */ +class import :public constructed +{ + public: + import(const std::string &n) + : constructed(n,type::INVALID) { } ; + ~import() { }; + /** + * lookup for item in this import + */ + typeref *get_item( const std::string &item) ; +}; + +/** + * vim: et sw=2 ts=2 list: + */ +#endif diff --git a/adt/asn1_node_object.cpp b/adt/asn1_node_object.cpp new file mode 100644 index 0000000..11f8000 --- /dev/null +++ b/adt/asn1_node_object.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +/** + * + */ +object::object() + : constructed("OBJECT",type::INVALID) + , m_classdef(NULL) +{ +} + +/** + */ +object::~object() +{ +} + +void +object::parsed_field(const std::string &fname,asn1::node *t) +{ + m_fields[fname] = t; +} + +void object::update_field(const std::string &fname,asn1::node *t) +{ + m_fields[fname] = t; +} + +// defined fields +asn1::node * +object::get_field(const std::string &fname) +{ + iterator it = m_fields.find(fname); + if (it != m_fields.end()) + { + return it->second; + } else + { + return NULL; + } +} + +asn1::objectset * +object::get_objectset(const std::string &fname) +{ + return dynamic_cast(get_field(fname)); +} + +} diff --git a/adt/asn1_node_object.h b/adt/asn1_node_object.h new file mode 100644 index 0000000..e1f8eae --- /dev/null +++ b/adt/asn1_node_object.h @@ -0,0 +1,37 @@ +#ifndef ASN1_NODE_OBJECT_H +#define ASN1_NODE_OBJECT_H + +class classdef; +class valuetype; +/** + * object that containes + */ +class object : public constructed +{ + typedef std::map fieldmap_type; + typedef fieldmap_type::iterator iterator; + typedef fieldmap_type::const_iterator const_iterator; + public: + + object() ; + ~object() ; + + void parsed_field(const std::string &fname,asn1::node *t); + // defined fields + asn1::node *get_field(const std::string &fname); + asn1::valuetype *get_ftvf(const std::string &fname) + { return dynamic_cast(get_field(fname)); } + asn1::objectset *get_objectset(const std::string &fname); + + void update_field(const std::string &fname,asn1::node *t); + // Once parsed, keep a pointer to the classdef. We will need + // it for each processing This avoids calls to resolver + inline classdef *get_classdef() const { return m_classdef; } + inline void set_classdef(classdef *cd) { m_classdef = cd; } + protected: + classdef *m_classdef; + fieldmap_type m_fields; +}; + + +#endif diff --git a/adt/asn1_node_parameters.cpp b/adt/asn1_node_parameters.cpp new file mode 100644 index 0000000..2c1cbc3 --- /dev/null +++ b/adt/asn1_node_parameters.cpp @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +parameters::parameters(const parameters &p) + : constructed(p) +{ + if (this != &p) + { + // duplicate elements in vector + for ( asn1::node::const_iterator it = p.begin() + ; it != p.end() + ; ++it) + { + asn1::parameter *param = dynamic_cast(*it); + asn1::parameter *nn = param->clone(); + nn->set_parent(this); + if (nn->type_node()) + nn->type_node()->set_parent(this); + append(nn); + } + identifier(p.identifier()); + } +} + +parameters* +parameters::clone() +{ + return new parameters(*this); +} + +bool +parameters::have_reference(const std::string &name,node::iterator &it) +{ + it = std::find_if(begin(),end(),find_node(name)); + return it != end(); +} + +void +parameters::add_parameter(parameter *p) +{ + append(p); +} + +asn1::parameter * +parameters::operator [](int l) +{ + asn1::node *result = *(begin()); + int i = 0; + for (asn1::node::const_iterator it = begin(); + (it !=end() ) && (i != l + 1) + ; ++it,++i) + { + result = *it; + } + return dynamic_cast(result); +} + + +/** + * + */ + +act_parameters::act_parameters(const act_parameters &p) + : constructed(p) +{ + if (this != &p) + { + // duplicate elements in vector + for ( asn1::node::const_iterator it = p.begin() + ; it != p.end() + ; ++it) + { + asn1::node *nn = (*it)->clone(); + nn->set_parent(this); + if (nn->type_node()) + nn->type_node()->set_parent(this); + append(nn); + } + identifier(p.identifier()); + } +} + +act_parameters* +act_parameters::clone() +{ + return new act_parameters(*this); +} + +asn1::node * +act_parameters::operator [](int l) +{ + asn1::node *result = *(begin()); + int i = 0; + for (asn1::node::const_iterator it = begin(); + (it !=end() ) && (i != l + 1) + ; ++it,++i) + { + result = *it; + } + return result; +} + +/* + * parameter class implementation + */ +parameter::parameter(asn1::node *_gov,asn1::typeref *_ref) + : node(_ref->name(),_ref->type_id()(),_ref->meta_id()) + , m_param_ref(_ref) + , m_governor(_gov) +{ + type_node(_gov); + //set_reference(_ref->get_reference()); + // To stay compatible with the existing code +} + + +} diff --git a/adt/asn1_node_parameters.h b/adt/asn1_node_parameters.h new file mode 100644 index 0000000..df75d8d --- /dev/null +++ b/adt/asn1_node_parameters.h @@ -0,0 +1,102 @@ +#ifndef ASN1_NODE_PARAMETERS_H +#define ASN1_NODE_PARAMETERS_H + +class typeref ; +class parameter; +/** + * Instead of creating nodes in the parser, + * It's better to build specialized classes with better + * services. + * - parmeters class is a container of parameters + * SHOULD inherit from something like node_container or container + */ +class parameters : public constructed +{ + parameters(const parameters &p); + public: + parameters() + : constructed("",type::INVALID) {} + ~parameters() {} + parameters *clone(); + // Provide some function to find reference according to name + // will return the appropriate parameter + bool have_reference(const std::string &name,node::iterator &it) ; + + void add_parameter(asn1::parameter *n); + + asn1::parameter *operator [](int l); + protected: +}; + +/** + * Instead of creating nodes in the parser, + * It's better to build specialized classes with better + * services. + * this class contains the actual parameters of a type. + * not to mix with parameters. + * typeref {parameters} ::= SEQ { + * toto Toto {act_parameters} + * } + */ +class act_parameters : public constructed +{ + act_parameters(const act_parameters &ap); + public: + act_parameters() + : constructed("",type::INVALID) {} + ~act_parameters() {} + + act_parameters *clone(); + // Provide some function to find reference according to name + // will return the appropriate parameter + bool have_reference(const std::string &name,node::iterator &it) + { + it = std::find_if(begin(),end(),find_node(name)); + return it != end(); + } + + void add_parameter(asn1::node *n) + { + append(n); + } + + asn1::node *operator [](int l); + protected: +}; + + +/** + * A parameter is contained in parameters + * a parameter is either a dummyReference -> reference + * or governor : dummyReference + * governor + * reference + * a parameter can be a typeref, a value or valueSet or even ObjectSet + */ +class parameter : public node +{ + parameter(const parameter &p) + : node(p) , m_param_ref(p.m_param_ref),m_governor(p.m_governor) + { + } + public: + parameter(asn1::node *_gov,asn1::typeref *_ref) ; + + ~parameter() {}; + + parameter *clone() { return new parameter(*this); }; + + asn1::node *get_governor() const { return m_governor; } ; + + asn1::typeref * get_typeref() const { return m_param_ref; } + protected: + // Shall own two nodes. + asn1::typeref *m_param_ref; + // governor and reference. + asn1::node *m_governor; +}; + +/* + * vim:et:sw=2 + */ +#endif diff --git a/adt/asn1_node_primitive.cpp b/adt/asn1_node_primitive.cpp new file mode 100644 index 0000000..1d83320 --- /dev/null +++ b/adt/asn1_node_primitive.cpp @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ +#undef DEBUG + + +/********************************************* + * integer type specific methods for generator + */ +bool integer::is_unsigned() const +{ + long min,max; + if (get_range(min,max) && (min >= 0)) + { + return true; + } + return false; +} + +/** + * @brief asn1 integers most often have range + * constraints. + * @return false if no constraint or no real MAX + * + */ +bool integer::get_range(long &_min,long &_max) const +{ + if (has_constraints()) + { + asn1::constraint_range *cr =( *constraint_begin())->as_constraint_range() ; + if (cr) + { + return cr->get_min_max(_min,_max); + } else + { + //GEN_LOG_ERROR("integer::%s not a range constraint",__FUNCTION__); + std::cerr<<"integer::"<<__FUNCTION__<<" not a range constraint"< 1)) { + intsize--; + integer <<=8; +#ifdef DEBUG + GEN_LOG_DEBUG("generator::encode_integer step 1 %lx",integer); +#endif + } + mask = (0x7f << ((intsize-1)*7)); + long decal = (intsize -1)*7; +#ifdef DEBUG + GEN_LOG_DEBUG("generator::encode_integer step 1 intsize=%ld mask=0x%lx decal=%ld",intsize,mask,decal); +#endif + while ((value & mask ) != 0) + { + long treat = ((value & mask)>>decal); + v.push_back (( treat & 0x7F) |0x80 ); +#ifdef DEBUG + std::cout<<"\tpushed :"; + std::cout<size()); +#endif + if (type_id()() != asn1::type::ASN1_OBJECT_IDENTIFIER) + { + std::cerr<<__FUNCTION__<<" BAD TYPE SHOULD be OBJECT IDENTIFIER\n"; + assert(0); + } + for (asn1::node::iterator lit = begin(); lit != end() ; lit++) + { +//#ifdef DEBUG +#if 0 + std::cout<<"object_identifier::"<<__FUNCTION__<<" "<<(*lit)->name()<<" pos="<<*pos; + std::cout<<" v.size="<size()<type_id() == asn1::type::ASN1_INTEGER) + { + asn1::valuetype *vt = (*lit)->as_value_type(); + long long l = vt->value_long(); + if (*pos == 0) { + first2 = 40 * vt->value_long(); + } else if (*pos == 1){ + first2 = first2 + vt->value_long(); + v->push_back(first2); + } else + encode_integer(l,*v); + (*pos)++; + } else + { + asn1::node *id = from_module()->lookup((*lit)); + if (id ) + { + if (asn1::object_identifier *roid = id->type_node() + ->as_object_identifier()) + roid->oid_value(pos,v); + } else + { + // Probaly I have value + asn1::valuetype *vt = (*lit)->as_value_type(); + if (*pos == 0 && vt) { + first2 = 40 * vt->value_long(); + } else if (*pos == 1 && vt) { + first2 = first2 + vt->value_long(); + v->push_back(first2); + } else if (vt) { + encode_integer(vt->value_long(),*v); + } else { + std::cerr<<"object_identifier::oid_value vt==NULL"; + std::cerr<<" tyeid="<<(*lit)->type_id()(); + std::cerr<<" cpp_name="<<(*lit)->cpp_name()< arcsType; \ + typedef arcsType::iterator arcsIterator; \ + typedef arcsType::const_iterator arcsConstIterator; \ + void arcs(arcsType &v ); \ + long hash( ); \ + void encode_integer( long value , arcsType &v); \ + void print_strhex( std::ostream &os); \ + void print_strhex( std::ostream &os,const arcsType &v); \ + protected: \ + void oid_value(long *pos,arcsType *v);\ + int m_primitive_tag; +#define ASN1_PRIMITIVE_ADD_object_descriptor ; +#define ASN1_PRIMITIVE_ADD_real ; +#define ASN1_PRIMITIVE_ADD_enumerated ; +#define ASN1_PRIMITIVE_ADD_relative_oid ; +#define ASN1_PRIMITIVE_ADD_external ; +#define ASN1_PRIMITIVE_ADD_embedded_pdv ; +#define ASN1_PRIMITIVE_ADD_character_string ; +#define ASN1_PRIMITIVE_ADD_utctime ; +#define ASN1_PRIMITIVE_ADD_generalizedtime ; + + +#define ASN1_PRIMITIVE_TYPE(cls,parent,tp) \ + ASN1_PRIMITIVE_GEN(cls,parent,#tp,asn1::type::ASN1_##tp) ASN1_PRIMITIVE_ADD_##cls }; + +#define ASN1_STRING_TYPE(cls,parent,tp) \ + class cls : public parent \ + {\ + public:\ + cls() : parent( #tp,asn1::type::ASN1_STRING_##tp) {} ; \ + cls(const cls &c) : parent( c ) {} ; \ + cls *clone() { return new cls(*this); } \ + ~cls() {}; \ + }; + +#include "adt/asn1_type.inc" + +class extensible : public node +{ + public: + extensible() + : node("...",type::ASN1_EXTENSIBLE) {} +}; + +class exportvar : public node +{ + public: + exportvar() + : node("...",type::ASN1_EXPORTVAR) {} +}; + +#endif diff --git a/adt/asn1_node_selection.h b/adt/asn1_node_selection.h new file mode 100644 index 0000000..fc8ccb3 --- /dev/null +++ b/adt/asn1_node_selection.h @@ -0,0 +1,33 @@ +#ifndef ASN1_NODE_SELECTION_H +#define ASN1_NODE_SELECTION_H + +/** + * selection type object is a typeref where get_reference + * will return NULL !!!!! + * + * -> Solver might have a problem with this. + */ +class selection : public typeref +{ + protected: + selection(const selection &s) + : typeref(s) + {}; + public: + + selection(const std::string &s,asn1::node *_n = NULL) + : typeref(s,NULL,meta::TYPEREF) + { + type_id(asn1::type::ASN1_SELECTION); + meta_id(asn1::meta::TYPEREF); + type_node(_n); + }; + + selection *clone() { return new selection(*this);}; + ~selection() {}; + + protected: +}; + + +#endif diff --git a/adt/asn1_node_sequence.cpp b/adt/asn1_node_sequence.cpp new file mode 100644 index 0000000..c46691c --- /dev/null +++ b/adt/asn1_node_sequence.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +sequence::sequence() : constructed("SEQUENCE",type::ASN1_SEQUENCE) +{ +} + +sequence::sequence(const sequence &s) + : constructed("SEQUENCE",type::ASN1_SEQUENCE) +{ + std::cerr<<"sequence::sequence copy "<(*it); + asn1::field *nn = f->clone(); + nn->set_parent(this); + nn->get_type()->set_parent(this); + nn->get_type()->identifier(nn); + add_component(nn); + } + set_parent(s.get_parent()); + //identifier(s.identifier()); + } +} + +void +sequence::add_component(asn1::node *c) +{ + append(c); + if (c && c->flags().is_optional()) + { + m_optionals.push_back(c); + } +} + +} + diff --git a/adt/asn1_node_sequence.h b/adt/asn1_node_sequence.h new file mode 100644 index 0000000..533c59f --- /dev/null +++ b/adt/asn1_node_sequence.h @@ -0,0 +1,37 @@ +#ifndef ASN1_NODE_SEQUENCE_H +#define ASN1_NODE_SEQUENCE_H + +/** + * adt sequence type. contains the fields in the sequence. + * add methodes to collect optional fields. This will help + * in code generation. + * component items should also be added through an API from + * this class. The goal is to remove container from node class. + */ +class sequence : public constructed +{ + protected: + sequence(const sequence &s); + public: + typedef std::vector OptionalArrayType; + typedef OptionalArrayType::iterator OptionalIterator; + sequence(); + ~sequence() {}; + + sequence *clone() {return new sequence(*this); } + + OptionalIterator opt_begin() { return m_optionals.begin() ; } + OptionalIterator opt_end() { return m_optionals.end() ; } + + size_t opt_size( ) const { return m_optionals.size(); } + + /** + * Add a component. the type should be more specific + */ + void add_component(asn1::node *); + protected: + std::vector m_optionals; +}; + + +#endif diff --git a/adt/asn1_node_sequence_of.h b/adt/asn1_node_sequence_of.h new file mode 100644 index 0000000..9bcc9a1 --- /dev/null +++ b/adt/asn1_node_sequence_of.h @@ -0,0 +1,21 @@ +#ifndef ASN1_NODE_SEQUENCE_OF_H +#define ASN1_NODE_SEQUENCE_OF_H + + +class sequence_of : public typenode +{ + public: + + sequence_of(asn1::node *_type) + : typenode("SEQUENCE_OF",type::ASN1_SEQUENCE_OF) + { + type_node(_type); + _type->set_parent(this); + }; + ~sequence_of() {}; + + protected: +}; + + +#endif diff --git a/adt/asn1_node_set.h b/adt/asn1_node_set.h new file mode 100644 index 0000000..a976b30 --- /dev/null +++ b/adt/asn1_node_set.h @@ -0,0 +1,17 @@ +#ifndef ASN1_NODE_SET_H +#define ASN1_NODE_SET_H + + +class set : public constructed +{ + public: + + set() : constructed("SET",type::ASN1_SET) {}; + ~set() {}; + + // alternative_set_iterator + protected: +}; + + +#endif diff --git a/adt/asn1_node_set_of.h b/adt/asn1_node_set_of.h new file mode 100644 index 0000000..a157beb --- /dev/null +++ b/adt/asn1_node_set_of.h @@ -0,0 +1,18 @@ +#ifndef ASN1_NODE_SET_OF_H +#define ASN1_NODE_SET_OF_H + + +class set_of : public typenode +{ + public: + + set_of(asn1::node *_type) + : typenode("SET_OF",type::ASN1_SET_OF) { type_node(_type); }; + ~set_of() {}; + + // alternative_set_iterator + protected: +}; + + +#endif diff --git a/adt/asn1_node_typenode.cpp b/adt/asn1_node_typenode.cpp new file mode 100644 index 0000000..d7a17da --- /dev/null +++ b/adt/asn1_node_typenode.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_reference.h" +#include "asn1_module.h" +#include "asn1_node_assignment.h" +#include "asn1_node_typenode.h" + + +namespace asn1 { + + + +// copy constructor +typenode::typenode(const typenode &t) + : node (t) +{ +} +typenode::typenode(const std::string name + , type _t + , meta _m ) + : node(name,_t,_m) +{ +} + +typenode * +typenode::clone() +{ + return new typenode(*this); +} + +// Return the assignment the type is part of +asn1::assignment * +typenode::get_assignment( ) const +{ + assert(0 && "typenode::get_assignment TODO"); + return NULL; +} + +// Return the field the is type is part of +asn1::field * +typenode::get_field( ) const +{ + assert(0 && "typenode::get_field TODO"); + return NULL; +} + +asn1::typenode * +typenode::get_eltype( ) const +{ + //assert(0 && "typenode::get_eltype TODO"); + return dynamic_cast(type_node()); +} + +// Need to solve mess with objectset / valueset before +// Constraints on a node type +bool typenode::has_constraints() const +{ + return m_constraints.begin() != m_constraints.end(); +} + + +} + +/** + * vim: et sw=2 ts=2 list: + */ diff --git a/adt/asn1_node_typenode.h b/adt/asn1_node_typenode.h new file mode 100644 index 0000000..9116a99 --- /dev/null +++ b/adt/asn1_node_typenode.h @@ -0,0 +1,63 @@ +#ifndef _TYPENODE_H__ +#define _TYPENODE_H__ + +class field; +class assignment; +class resolver; +/** + * Base class for types. It is own by an assignment or field + * in constructed type. + * This class should be the parent class for all types (primitive + * and contructed). + * The idea is to move some features from node to type node. + * A type does not have a name. + */ +class typenode : public node +{ + public: + typenode(const std::string s, type _t) + : node(s,_t,meta::TYPE) + { } ; + + typenode(const std::string name + , type _t + , meta _m ); + // copy constructor + typenode(const typenode &t); + + typenode *clone(); + + // Return the assignment the type is part of + asn1::assignment * get_assignment( ) const; + // Return the field the is type is part of + asn1::field * get_field( ) const; + // For set_of and sequence_of ... + asn1::typenode * get_eltype( ) const; + + inline void constraint(asn1::constraint *c) + { m_constraints.append(c); }; + // Constraints on a node type + bool has_constraints() const; + // iterators + inline asn1::constraint::iterator constraint_begin() + { return m_constraints.begin(); }; + + // + inline asn1::constraint::const_iterator constraint_begin() const + { return m_constraints.begin(); }; + + // + inline asn1::constraint::iterator constraint_end() + { return m_constraints.end();}; + + // + inline asn1::constraint::const_iterator constraint_end() const + { return m_constraints.end();}; + /** + * For recursive typeref resolution + */ + virtual void resolve(asn1::resolver &r) {}; + protected: +}; + +#endif diff --git a/adt/asn1_node_typeref.cpp b/adt/asn1_node_typeref.cpp new file mode 100644 index 0000000..647eebd --- /dev/null +++ b/adt/asn1_node_typeref.cpp @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" +#include "asn1_resolver.h" + + +namespace asn1 +{ + +/** + * May ben + */ +typeref::typeref(const typeref &r) + : typenode(r) + , m_real_type(r.m_real_type) + , m_reference(r.m_reference) +{ + //set_reference(r.get_reference()); + if (r.parameters()) + { + std::cerr<<"typeref::typeref copy "<clone()); + } +} + +typeref * +typeref::clone() +{ + return new typeref(*this); +} + +bool typeref::is_complex() const +{ + return (get_reference()->size() >1); +} + +bool typeref::is_simple() const +{ + return dynamic_cast(get_reference()) != NULL; +} +// +bool typeref::is_external() const +{ + return dynamic_cast(get_reference()) != NULL; +} +// +bool typeref::is_objectclass() const +{ + return dynamic_cast(get_reference()) != NULL; +} + +bool typeref::is_type_identifier() const +{ + try + { + objectclass_reference &_ref = get_objectclass(); + return ! std::string("TYPE-IDENTIFIER::&Type").compare(_ref.name()); + } catch (std::exception &e) + { + return false; + } +} + +objectclass_reference & +typeref::get_objectclass() const +{ + return dynamic_cast(*get_reference()); +} + +simple_reference & +typeref::get_simple() const +{ +return dynamic_cast(*get_reference()); +} + +/** + * + */ +bool +typeref::is_imported(std::string &m) const +{ + asn1::module *_module = from_module(); + bool ret = false; + asn1::import_list *imports = _module->imports(); + if (imports == NULL) + { +#if 0 + GEN_LOG_ERROR("%s type %s not in imports no imports\n" + , __FUNCTION__ + , name().c_str()); +#endif + return ret; + } + asn1::node::iterator it = imports->begin(); +#if 0 + GEN_LOG_DEBUG("%s lookup for type %s\n" + , __FUNCTION__ + , name().c_str()); +#endif + for (; it != imports->end();it++) + { + asn1::import *import = dynamic_cast(*it); + asn1::node::iterator found = std::find_if( import->begin() + , import->end() + , asn1::find_node(name())); + if (found != import->end() ) + { +#if 0 + GEN_LOG_DEBUG("%s found %s in %s\n" + , __FUNCTION__ + , name().c_str() + , import->identifier()->name().c_str()); +#endif + m = import->identifier()->name(); + ret = true; + break; + } + } + return ret; + +} + +/** + * + */ +bool +typeref::equals(const node &_n ) const +{ + if (asn1::typeref *tref = const_cast(_n).as_typeref()) + { + return ! get_reference()->name().compare(tref->get_reference()->name()); + } else + return false; +}; + + +asn1::node::tag_type +typeref::otag(asn1::resolver &resolver) const +{ + asn1::node *t = m_real_type; + if (!t) + { + std::cerr<<"typeref::"<<__FUNCTION__<<" START "; + std::cerr<<"have real type: "<<((t != NULL)?1:0); + std::cerr<<" "<name()<<"::"<tagged() && t->as_typeref()) + { + if (t->as_typeref() ) + { + asn1::node *nt = t->as_typeref()->get_real_type(); + if (! nt) + { + std::cerr<<"typeref::"<<__FUNCTION__<<" should have real type "; + std::cerr<from_module()->name()<<"::"<name()<as_typeref()); + if (nt) + { + std::cerr<<__FUNCTION__<<" got "<from_module()->name(); + std::cerr<<"::"<name()<tagged()) + return t->tag(); + + if (asn1::choice *c = dynamic_cast(t)) + { + std::cerr<<"typeref::"<<__FUNCTION__<<" "<get_tag(resolver); + } + /* What does this mean ? */ + std::cerr<<"typeref::"<<__FUNCTION__<<" ERROR "<name(); + std::cerr<<"::"<tag(); + } + assert((t != NULL) && "otag no tag in reference chaine !"); + if (t->tag().m_value == -1) + std::cerr<<"typeref::"<<__FUNCTION__<<" "<name()<name().compare("ANY")) + assert((t->tag().m_value != -1) && "Tag must have a value"); + return t->tag(); +} + +void +typeref::resolve(asn1::resolver &_resolver) +{ + asn1::node *pi = NULL; + asn1::assignment *p = NULL; + + if ( get_parent() ) + { + if (asn1::module *m = dynamic_cast(get_parent())) + { + //std::cerr<<" typeref="<cpp_name(); + std::cerr<<" m_real_type= "<is_primitive() + || m_real_type->is_constructed()) + && (is_objectclass() && ! is_complex())) + { + asn1::reference *ref = get_reference(); + set_reference( new asn1::simple_reference(ref->name())); + + std::cerr<<"typeref::"<<__FUNCTION__<<" Issue with "<as_typeref(); + if (oref) + { + // std::cerr<<"typeref::"<<__FUNCTION__<<" !! recursif call resolve real_type "<name()<resolve(_resolver); + } +} +// +asn1::typenode * +typeref::get_canonical_typenode() const +{ + assert( (m_real_type != NULL) && "typeref::get_canonical_typenode must have m_real_type"); + if (asn1::typeref *lr = m_real_type->as_typeref() ) + { + while ( lr && lr->get_real_type()->as_typeref()) + lr = lr->get_real_type()->as_typeref(); + assert((lr != NULL) && "typeref::get_canonical_typenode should not have NULL for lr"); + return lr->as_typenode(); + } else + return m_real_type->as_typenode(); +} + +} diff --git a/adt/asn1_node_typeref.h b/adt/asn1_node_typeref.h new file mode 100644 index 0000000..532c5ce --- /dev/null +++ b/adt/asn1_node_typeref.h @@ -0,0 +1,87 @@ +#ifndef ASN1_NODE_TYPEREF_H +#define ASN1_NODE_TYPEREF_H + +/** + * Helper node that deals with all kind of references. + * value reference, typerefence, objectclass and + * so one. + * This class will be used by resolver to find the + * primary type + * + */ +class resolver; +class typeref : public typenode +{ + protected: + typeref(const typeref &r); + public: + + typeref(asn1::reference *_ref,meta _m = meta::TYPE) + : typenode("TYPEREF",type::ASN1_REFERENCE,_m) + , m_real_type(NULL) + , m_reference(_ref) + { + set_reference(_ref); + }; + + typeref(const std::string &name,asn1::reference *_ref,meta _m = meta::TYPE) + : typenode(name,type::ASN1_REFERENCE,_m) + , m_real_type(NULL) + , m_reference(_ref) + { + } ; + + typeref *clone(); + + ~typeref() {}; + // from node + inline reference *get_reference() const { return m_reference;}; + inline void set_reference(reference *r) {m_reference =r;}; + // get_canonical_typenode() return the primitive asn1::typenode + // in case of multiple typereference lists + // Str3 ::= [ 1] Str2 Str2 ::= [4] IMPLICIT Str1 Str1 ::= VisibleString + // canonical typenode will be VisibleString Typenode + asn1::typenode *get_canonical_typenode() const; + + // Yes for references like OPERATION.&Id + bool is_complex() const; + // + bool is_simple() const; + // + bool is_external() const; + // + bool is_objectclass() const; + + bool is_type_identifier() const; + + objectclass_reference &get_objectclass() const ; + + simple_reference &get_simple() const ; + /** + * Check if reference is imported. If so + * return the module it's imported from. + */ + bool is_imported(std::string &m) const; + // + virtual bool equals(const node &_n ) const ; + // alternative_typeref_iterator + + // The idea here is to save the real type + // and fix objectclass that are pointing + // to primitive types. Example H323 TBCD-STRING + // Which is a IA5String + // + void resolve(asn1::resolver &_resolver); + // Return real type. Null if resolve has + // not been called. + asn1::node *get_real_type() const + { return m_real_type; } + /// Return outer most tag + asn1::node::tag_type otag(asn1::resolver &r) const; + protected: + asn1::reference *m_reference; + asn1::node *m_real_type; +}; + + +#endif diff --git a/adt/asn1_node_valuetype.cpp b/adt/asn1_node_valuetype.cpp new file mode 100644 index 0000000..165f332 --- /dev/null +++ b/adt/asn1_node_valuetype.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_node.h" +#include "asn1_module.h" + + +namespace asn1 +{ + +valuetype::valuetype(asn1::value *_val,meta _m ) + : node("VALUE",type::INVALID,_m) +{ + value(_val); +} + +valuetype::valuetype( const std::string &name + , asn1::value *_ref + , meta _m ) + : node(name,type::INVALID,_m) +{ + value(_ref); +} + +valuetype::~valuetype() {}; + +//TODO Macro to debug an work on value_long that needs to be changed +//#define WVAL +// +// Value ... +void +valuetype::value_long(long long l) +{ +#ifdef WVAL + std::cerr<<"ERR valuetype::value_long called with value_long "<m_integer; + } +#ifdef WVAL +// std::cerr<<"ERROR value_type called with value_long "<= 1) + { + if (asn1::celt_type *ct = dynamic_cast(*m_constraints.begin())) + { + if (ct->value()) + return ct->value()->as_typeref(); + } + } + return NULL; +} + +/** + * objectset + */ +objectset_assignment * +objectset::get_assignment() const +{ + return dynamic_cast(identifier()); +} + +void +objectset::set_classref(asn1::typeref *ref) +{ + //TODO needs to be removed + type_node(ref); + // Final place + m_classref = ref; +} + +} diff --git a/adt/asn1_node_valuetype.h b/adt/asn1_node_valuetype.h new file mode 100644 index 0000000..d0ba83e --- /dev/null +++ b/adt/asn1_node_valuetype.h @@ -0,0 +1,87 @@ +#ifndef ASN1_NODE_VALUETYPE_H +#define ASN1_NODE_VALUETYPE_H + +class objectset_assignment; +/** + * Helper node that deals with all kind of value. + * Possible meta + * -> VALUE + * -> VALUESET + * -> OBJECTSET + * details about the value are given in asn1_value structure + * VT_MIN, VT_MAX, VT_TRUE, VT_FALSE + * if VT is CT_COLON, type should be CHOICE + * if VT is TRUE or FALSE, type should be BOOLEAN + * if VT is MIN,MAX,NUMBER it should be INTEGER + * if VT is string, OCTET_STRING + * this could allow better correlation between type and + * value at the first place + * if VT REFERENCED, type could be OBJECT, OBJECTSET,VALUESET + */ +class valuetype : public node +{ + public: + + valuetype(asn1::value *_val,meta _m = meta::VALUE); + + valuetype( const std::string &name + , asn1::value *_ref + , meta _m = meta::VALUE) ; + + ~valuetype(); + // + // Value ... + void value_long(long long l) ; + + long long value_long() const ; + protected: +}; + +/** + * + */ +class valueset : public typenode +{ + public: + valueset(asn1::constraint *_val) : + typenode("valueset",type::ASN1_VALUESET,meta::VALUE) + { + type_id(type::ASN1_VALUESET); + constraint(_val); + } + ~valueset() {}; + /* + * Specific for Rose .... + */ + asn1::typeref *get_typeref(); + protected: + +}; + +/** + * + */ +class objectset : public typenode +{ + public: + objectset(asn1::constraint *_val) : + typenode("objectset",type::ASN1_OBJECTSET,meta::VALUE) + { + type_id(type::ASN1_VALUESET); + constraint(_val); + } + ~objectset() {}; + + objectset_assignment *get_assignment() const; + + void set_classref(asn1::typeref *); + + asn1::typeref *get_classref() const + { return m_classref; } + protected: + asn1::typeref *m_classref; + +}; + + +#endif diff --git a/adt/asn1_recursive_visitor.h b/adt/asn1_recursive_visitor.h new file mode 100644 index 0000000..ad562c6 --- /dev/null +++ b/adt/asn1_recursive_visitor.h @@ -0,0 +1,640 @@ +#ifndef ASN1_RECURSIVE_VISITOR_H__ +#define ASN1_RECURSIVE_VISITOR_H__ + +namespace asn1 +{ + + +//std::cout<<"TRY_TO FAILED calling "<< #f< +class recursive_visitor +{ + public: + Derived &getDerived() { + return *static_cast(this); + }; + + bool traverse_module(asn1::module *); + bool traverse_assignment(asn1::node *); + // Assignment traversal +#define ASSIGNMENT(tp,CLASS,PARENT) bool traverse_assign_##CLASS(CLASS##_assignment *S); +#include "asn1_meta.inc" + + bool walkup_from_assignment(asn1::node *s) + { return getDerived().visit_assignment(s);} + + bool visit_assignment(asn1::node *s) {return true;} + +#define ASSIGNMENT(tp,CLASS,PARENT) \ + bool walkup_from_assign_##CLASS(CLASS##_assignment *S) { \ + TRY_TO(walkup_from_##PARENT(S)); \ + TRY_TO(visit_assign_##CLASS(S)); \ + return true; \ + } \ + bool visit_assign_##CLASS(CLASS##_assignment *S) {return true; } + +#include "asn1_meta.inc" + + // Type traversal + bool traverse_type(asn1::node *); +#if 0 +#define ASN1_TYPE(CLASS,PARENT,ID) \ + bool traverse_##CLASS(asn1::node *S); +#define ASN1_CONSTRUCTED_TYPE(CLASS,PARENT,ID) \ + bool traverse_##CLASS(asn1::node *S); +#define ASN1_PRIMITIVE_TYPE(CLASS,PARENT,ID) \ + bool traverse_##CLASS(asn1::node *S); +#else +#define ASN1_TYPE(CLASS,PARENT,ID) \ + bool traverse_##CLASS(CLASS *S); +#define ASN1_CONSTRUCTED_TYPE(CLASS,PARENT,ID) \ + bool traverse_##CLASS(CLASS *S); +#define ASN1_PRIMITIVE_TYPE(CLASS,PARENT,ID) \ + bool traverse_##CLASS(CLASS *S); +#endif + +#define ASN1_CLASSFIELD_TYPE(CLASS,PARENT,ID) \ + bool traverse_##CLASS(CLASS *S); \ + bool traverse_object_##CLASS(CLASS *S,asn1::node *field ); \ + + bool traverse_object_field(asn1::classfield *S,asn1::node *field); + + +#include "adt/asn1_type.inc" + bool walkup_from_node(asn1::node *s) + { return getDerived().visit_node(s);} + + bool visit_node(asn1::node *s) {return true;} + // + bool walkup_from_typenode(asn1::node *s) + { return getDerived().visit_typenode(s);} + + bool visit_typenode(asn1::node *s) {return true;} + // + bool walkup_from_typeref(asn1::node *s) + { return getDerived().visit_typeref(s);} + + bool visit_typeref(asn1::node *s) {return true;} + // + bool walkup_from_primitive(asn1::node *s) + { return getDerived().visit_primitive(s);} + + bool visit_primitive(asn1::node *s) {return true;} + // + bool walkup_from_constructed(asn1::node *s) + { return getDerived().visit_constructed(s);} + + bool visit_constructed(asn1::node *s) {return true;} + // + bool walkup_from_object_classfield(asn1::classfield *s,asn1::node *f) + { return getDerived().visit_object_classfield(s,f);} + + bool visit_object_classfield(asn1::classfield *s,asn1::node *f) + {return true;} +#if 0 +#define ASN1_TYPE(CLASS,PARENT,ID) \ + bool walkup_from_##CLASS(asn1::node *S) { \ + TRY_TO(walkup_from_##PARENT(S)); \ + TRY_TO(visit_##CLASS(S)); \ + return true; \ + } \ + bool visit_##CLASS(asn1::node *S) {return true; } +#else +#define ASN1_TYPE(CLASS,PARENT,ID) \ + bool walkup_from_##CLASS(CLASS *S) { \ + TRY_TO(walkup_from_##PARENT(S)); \ + TRY_TO(visit_##CLASS(S)); \ + return true; \ + } \ + bool visit_##CLASS(CLASS *S) {return true; } + +#endif +#define ASN1_CLASSFIELD_TYPE(CLASS,PARENT,ID) \ + bool walkup_from_##CLASS(asn1::node *S) { \ + TRY_TO(walkup_from_##PARENT(S)); \ + TRY_TO(visit_##CLASS(S)); \ + return true; \ + } \ + bool visit_##CLASS(asn1::node *S) {return true; } \ + \ + bool walkup_from_object_##CLASS(CLASS *S,asn1::node *f) { \ + TRY_TO(walkup_from_##PARENT(S)); \ + TRY_TO(visit_object_##CLASS(S,f)); \ + return true; \ + } \ + bool visit_object_##CLASS(CLASS *S,asn1::node *f) {return true; } + + + +#include "adt/asn1_type.inc" + // CONSTRAINT traversal + // + bool traverse_constraint(constraint *S) ; + bool traverse_constraint_element(constraint_element *S) ; + bool traverse_constraint_type(constraint_type *S) ; + bool traverse_constraint_array(constraint_array *S) ; +#define ELEMENT_CONSTRAINT(tp,CLASS,PARENT) bool traverse_##CLASS(CLASS *S); +#include "asn1_constraint.inc" + // constraint + bool walkup_from_constraint(asn1::constraint *s) + { return getDerived().visit_constraint(s);} + + bool visit_constraint(asn1::constraint *s) {return true;} + // constraint_array + + // constraint_element + bool walkup_from_constraint_element(asn1::constraint_element *s) + { + TRY_TO(walkup_from_constraint(s)); + return getDerived().visit_constraint_element(s); + } + + bool visit_constraint_element(asn1::constraint_element *s) {return true;} + + // constraint_range + bool walkup_from_constraint_range(asn1::constraint_range *s) + { + TRY_TO(walkup_from_constraint(s)); + return getDerived().visit_constraint_range(s); + } + + bool visit_constraint_range(asn1::constraint_range *s) {return true;} + + + + // constraint_type + bool walkup_from_constraint_type(asn1::constraint_type *s) + { + TRY_TO(walkup_from_constraint(s)); + return getDerived().visit_constraint_type(s); + } + + bool visit_constraint_type(asn1::constraint_type *s) {return true;} + // constraint_array + bool walkup_from_constraint_array(asn1::constraint_array *s) + { + TRY_TO(walkup_from_constraint(s)); + return getDerived().visit_constraint_array(s); + } + + bool visit_constraint_array(asn1::constraint_array *s) {return true;} + + + +#define ELEMENT_CONSTRAINT(tp,CLASS,PARENT) \ + bool walkup_from_##CLASS(CLASS *S) { \ + TRY_TO(walkup_from_##PARENT(S)); \ + TRY_TO(visit_##CLASS(S)); \ + return true; \ + } \ + bool visit_##CLASS(CLASS *S) {return true; } + +#include "asn1_constraint.inc" + + + // Actual_choice + bool traverse_alternative_choice(asn1::field *); + + bool walkup_from_alternative_choice(asn1::field *s) + { return getDerived().visit_alternative_choice(s);} + + bool visit_alternative_choice(asn1::field *s) {return true;} + // Component type + bool traverse_component_type(asn1::field *); + + bool walkup_from_component_type(asn1::field *s) + { return getDerived().visit_component_type(s);} + + bool visit_component_type(asn1::field *s) {return true;} + + protected: + asn1::module::iterator m_module_iterator; +}; + +/** + * Implementation part + */ +template +bool recursive_visitor::traverse_module(asn1::module *S) { + if (! S) + return true; + for ( m_module_iterator = S->begin() + ; m_module_iterator != S->end() + ; ++m_module_iterator) + { + // I should probably stop if traverse return false + // std::cerr<<"recursive_visitor traverse "<<(*m_module_iterator)->name()<name()< +bool recursive_visitor::traverse_alternative_choice(asn1::field *S) +{ + TRY_TO(walkup_from_alternative_choice(S)); + return traverse_type(S->get_type()); +} + + + +template +bool recursive_visitor::traverse_component_type(asn1::field *S) +{ + TRY_TO(walkup_from_component_type(S)); + return traverse_type(S->get_type()); +} +// -- Assignment Traversal + +#define DEF_TRAVERSE_ASSIGN(STAMT,CODE) \ + template \ + bool recursive_visitor::traverse_assign_##STAMT(STAMT##_assignment *S) { \ + TRY_TO(walkup_from_assign_##STAMT(S)); \ + { CODE ; } \ + /* Traverse Children to be done*/ \ + return traverse_type(S->get_type()); \ + /*return true; */ \ + } \ + +#if 0 +#define DISPATCH(NAME,CLASS,VAR) \ + return getDerived().traverse_##NAME(static_cast(VAR)) +#else +#define DISPATCH(NAME,CLASS,VAR) \ + return getDerived().traverse_##NAME(static_cast(VAR)) +#endif + +#define DISPATCH_CLS(NAME,CLASS,VAR) \ + return getDerived().traverse_##NAME(static_cast(VAR)) + +template +bool recursive_visitor::traverse_assignment(asn1::node *S) +{ +#define DISPATCH_ASSIGN(NAME,CLASS,VAR) \ + return getDerived().traverse_assign_##NAME(static_cast(VAR)) + if (! S) + return true; + // Dispatch according to statement + switch (S->meta_id()()) { + case asn1::meta::MAX: + case asn1::meta::INVALID: + break; +#define ASSIGNMENT(TP,CLASS,PARENT) \ + case asn1::meta::TP : \ + DISPATCH_ASSIGN(CLASS,CLASS,S); +#include "asn1_meta.inc" + } + return true; +} + +template +bool recursive_visitor::traverse_type(asn1::node *S) +{ + if (! S) + return true; +#define DISPATCH_TYPE(NAME,CLASS,VAR) DISPATCH(NAME,CLASS,VAR) + // Dispatch according to statement + switch (S->type_id()()) { + case asn1::type::INVALID: + break; +#define ASN1_TYPE(CLASS,PARENT,TP) \ + case asn1::type::ASN1_##TP : \ + DISPATCH_TYPE(CLASS,CLASS,S); + +#define ASN1_CLASSFIELD_TYPE(CLASS,PARENT,TP) \ + case asn1::type::ASN1_##TP : \ + DISPATCH_CLS(CLASS,CLASS,S); + +#define ASN1_STRING_TYPE(CLASS,PARENT,TP) \ + case asn1::type::ASN1_STRING_##TP : \ + DISPATCH_TYPE(CLASS,CLASS,S); + + +#include "adt/asn1_type.inc" + default: + ; + } + return true; +} + +template +bool recursive_visitor::traverse_object_field(asn1::classfield *S + ,asn1::node *field) +{ + if (! S) + return true; +#define DISPATCH_OBJF(NAME,CLASS,VAR) \ + return getDerived().traverse_object_##NAME(static_cast(VAR),field) + // Dispatch according to statement + switch (S->type_id()()) { + case asn1::type::INVALID: + break; +#define ASN1_TYPE(CLASS,PARENT,TP) +#define ASN1_PRIMITIVE_TYPE(CLASS,PARENT,TP) +#define ASN1_CONSTRUCTED_TYPE(CLASS,PARENT,TP) +#define ASN1_STRING_TYPE(CLASS,PARENT,TP) + +#define ASN1_CLASSFIELD_TYPE(CLASS,PARENT,TP) \ + case asn1::type::ASN1_##TP : \ + DISPATCH_OBJF(CLASS,CLASS,S); + + +#include "adt/asn1_type.inc" + default: + ; + } + return true; +} + +/* Implementation Traverse assignment */ +DEF_TRAVERSE_ASSIGN(typeref,{}) +DEF_TRAVERSE_ASSIGN(type,{}) +DEF_TRAVERSE_ASSIGN(value,{}) +DEF_TRAVERSE_ASSIGN(valueset,{ + if ( asn1::value *v = S->value()) + { + traverse_constraint(v->m_constraint); + } +}) +DEF_TRAVERSE_ASSIGN(object,{ + asn1::object *obj = dynamic_cast(S->type_node()->type_node()); + // Now, Get classdef and visit the fields + if (asn1::classdef *cdef = obj->get_classdef()) + { + for ( asn1::node::iterator it = cdef->begin() + ; it != cdef->end() + ; ++it) + { + if (asn1::node *field = obj->get_field((*it)->name())) + { + traverse_object_field(static_cast(*it),field); + } + } + } +}) +DEF_TRAVERSE_ASSIGN(objectclass,{}) +DEF_TRAVERSE_ASSIGN(objectset,{ +}) +DEF_TRAVERSE_ASSIGN(objectfield,{}) + +/* Implementation Traverse type */ + + +#define DEF_TRAVERSE_TYPE(STAMT,CODE) \ + template \ + bool recursive_visitor::traverse_##STAMT(STAMT *S) { \ + TRY_TO(walkup_from_##STAMT(S)); \ + { CODE ; } \ + /* Traverse Children to be done*/ \ + /*return traverse_type(S->todo()); */ \ + return true; \ + } \ + + +DEF_TRAVERSE_TYPE(reference,{}) +DEF_TRAVERSE_TYPE(exportvar,{}) +//DEF_TRAVERSE_TYPE(universal,{}) +//DEF_TRAVERSE_TYPE(bitvector,{}) +DEF_TRAVERSE_TYPE(extensible,{}) +DEF_TRAVERSE_TYPE(components_of,{}) +DEF_TRAVERSE_TYPE(valueset,{ + if ( asn1::value *v = S->value()) + { + traverse_constraint(v->m_constraint); + } +}) + +DEF_TRAVERSE_TYPE(objectset,{ + if ( asn1::value *v = S->value()) + { + traverse_constraint(v->m_constraint); + } +}) + +DEF_TRAVERSE_TYPE(classdef,{ + for (asn1::node::iterator it = S->begin() + ; it != S->end() + ; ++it) + traverse_component_type(reinterpret_cast(*it)); +}) +//DEF_TRAVERSE_TYPE(instance,{}) +DEF_TRAVERSE_TYPE(classfield,{}) +/** + * CLASS FIELD TYPE + */ +#define DEF_TRAVERSE_CLASSFIELD(STAMT,CODE,CODE1) \ + template \ + bool recursive_visitor::traverse_##STAMT(STAMT *S) { \ + TRY_TO(walkup_from_classfield(S)); \ + TRY_TO(visit_##STAMT(S)); \ + { CODE ; } \ + /* Traverse Children to be done*/ \ + /*return traverse_type(S->todo()); */ \ + return true; \ + } \ + template \ + bool recursive_visitor::traverse_object_##STAMT \ + (STAMT *S,asn1::node *f) { \ + TRY_TO(walkup_from_object_classfield(S,f)); \ + TRY_TO(visit_object_##STAMT(S,f)); \ + { CODE1; } \ + /* Traverse Children to be done*/ \ + /*return traverse_type(S->todo()); */ \ + return true; \ + } \ + +DEF_TRAVERSE_CLASSFIELD(classfield_tf,{},{}) +DEF_TRAVERSE_CLASSFIELD(classfield_ftvf,{},{}) +DEF_TRAVERSE_CLASSFIELD(classfield_vtvf,{},{}) +DEF_TRAVERSE_CLASSFIELD(classfield_ftvsf,{},{}) +DEF_TRAVERSE_CLASSFIELD(classfield_vtvsf,{},{}) +DEF_TRAVERSE_CLASSFIELD(classfield_of,{},{}) +DEF_TRAVERSE_CLASSFIELD(classfield_osf,{ +}, +{ + if (f) + { + if ( asn1::value *v = f->value()) + { + traverse_constraint(v->m_constraint); + } + } + } +) + +/* + * CONSTRUCTED TYPES + */ +#define DEF_TRAVERSE_CONSTRUCTED DEF_TRAVERSE_TYPE +DEF_TRAVERSE_CONSTRUCTED(sequence,{ + for (asn1::node::iterator it = S->begin() + ; it != S->end() + ; ++it) + traverse_component_type(reinterpret_cast(*it)); +}) +DEF_TRAVERSE_CONSTRUCTED(choice,{ + for (asn1::node::iterator it = S->begin() + ; it != S->end() + ; ++it) + traverse_alternative_choice(reinterpret_cast(*it)); +}) +DEF_TRAVERSE_CONSTRUCTED(set,{ + for (asn1::node::iterator it = S->begin() + ; it != S->end() + ; ++it) + traverse_component_type(reinterpret_cast(*it)); +}) +DEF_TRAVERSE_CONSTRUCTED(sequence_of,{ + traverse_type(S->get_eltype()); +}) +DEF_TRAVERSE_CONSTRUCTED(set_of,{ + traverse_type(S->get_eltype()); +}) +DEF_TRAVERSE_CONSTRUCTED(selection,{}) +/* + * PRIMITIVE TYPES + */ +#define DEF_TRAVERSE_PRIMITIVE DEF_TRAVERSE_TYPE +DEF_TRAVERSE_PRIMITIVE(any,{}) +DEF_TRAVERSE_PRIMITIVE(boolean,{}) +DEF_TRAVERSE_PRIMITIVE(integer,{}) +DEF_TRAVERSE_PRIMITIVE(bit_string,{}) +DEF_TRAVERSE_PRIMITIVE(octet_string,{}) +DEF_TRAVERSE_PRIMITIVE(null,{}) +DEF_TRAVERSE_PRIMITIVE(object_identifier,{}) +DEF_TRAVERSE_PRIMITIVE(object_descriptor,{}) +DEF_TRAVERSE_PRIMITIVE(real,{}) +DEF_TRAVERSE_PRIMITIVE(enumerated,{}) +DEF_TRAVERSE_PRIMITIVE(relative_oid,{}) +DEF_TRAVERSE_PRIMITIVE(external,{}) +DEF_TRAVERSE_PRIMITIVE(embedded_pdv,{}) +DEF_TRAVERSE_PRIMITIVE(character_string,{}) +DEF_TRAVERSE_PRIMITIVE(utctime,{}) +DEF_TRAVERSE_PRIMITIVE(generalizedtime,{}) +/* + * STRING TYPES + */ +/* +ASN1_STRING_TYPE(string,primitive,STRING) +*/ +#define DEF_TRAVERSE_STRING DEF_TRAVERSE_TYPE +DEF_TRAVERSE_STRING(ia5string,{}) +DEF_TRAVERSE_STRING(printablestring,{}) +DEF_TRAVERSE_STRING(visiblestring,{}) +DEF_TRAVERSE_STRING(iso646string,{}) +DEF_TRAVERSE_STRING(numericstring,{}) +DEF_TRAVERSE_STRING(universalstring,{}) +DEF_TRAVERSE_STRING(bmpstring,{}) +DEF_TRAVERSE_STRING(utf8string,{}) +DEF_TRAVERSE_STRING(generalstring,{}) +DEF_TRAVERSE_STRING(graphicstring,{}) +DEF_TRAVERSE_STRING(teletexstring,{}) +DEF_TRAVERSE_STRING(t61string,{}) +DEF_TRAVERSE_STRING(videotexstring,{}) +DEF_TRAVERSE_STRING(objectdescriptor_string,{}) + +/** + * VISITE CONSTRAINTS + */ +template +bool recursive_visitor::traverse_constraint(asn1::constraint *S) +{ + if (! S) + return true; +#define DISPATCH_CONSTRAINT(NAME,CLASS,VAR) DISPATCH_CLS(NAME,CLASS,VAR) + // Dispatch according to statement + switch (S->type()) { + case asn1::constraint::EL_INVALID: + break; +#define ELEMENT_CONSTRAINT(TP,CLASS,PARENT) \ + case asn1::constraint::TP : \ + DISPATCH_CONSTRAINT(CLASS,CLASS,S); + +#include "asn1_constraint.inc" + default: + std::cout<<"UNKNOWN CONSTRAINT"< \ + bool recursive_visitor::traverse_##STAMT(STAMT *S) { \ + TRY_TO(walkup_from_##STAMT(S)); \ + { CODE ; } \ + /* Traverse Children to be done*/ \ + /*return traverse_type(S->todo()); */ \ + return true; \ + } \ + +DEF_TRAVERSE_CONSTRAINT(constraint_element,{}) +DEF_TRAVERSE_CONSTRAINT(constraint_type,{}) +DEF_TRAVERSE_CONSTRAINT(constraint_array,{}) +/* Element type */ +DEF_TRAVERSE_CONSTRAINT(celt_type,{}) +DEF_TRAVERSE_CONSTRAINT(celt_value,{}) +DEF_TRAVERSE_CONSTRAINT(celt_range,{}) +DEF_TRAVERSE_CONSTRAINT(celt_llrange,{}) +DEF_TRAVERSE_CONSTRAINT(celt_rlrange,{}) +DEF_TRAVERSE_CONSTRAINT(celt_ulrange,{}) +DEF_TRAVERSE_CONSTRAINT(celt_encodedby,{}) +DEF_TRAVERSE_CONSTRAINT(celt_ext,{}) + +/*Constraint type */ +#define DEF_TRAVERSE_CONSTRAINT_TYPE(elt,code) DEF_TRAVERSE_CONSTRAINT(elt,code) +DEF_TRAVERSE_CONSTRAINT_TYPE(ctype_size,{}) +DEF_TRAVERSE_CONSTRAINT_TYPE(ctype_from,{}) +DEF_TRAVERSE_CONSTRAINT_TYPE(ctype_wcomp,{}) +DEF_TRAVERSE_CONSTRAINT_TYPE(ctype_wcomps,{}) +DEF_TRAVERSE_CONSTRAINT_TYPE(ctype_ctdby,{}) +DEF_TRAVERSE_CONSTRAINT_TYPE(ctype_ctng,{}) + +/* Array Constraints */ +#define DEF_TRAVERSE_CONSTRAINT_ARRAY(elt,code) DEF_TRAVERSE_CONSTRAINT(elt,code) +DEF_TRAVERSE_CONSTRAINT_ARRAY(ca_set,{ + for (asn1::constraint::iterator it = S->begin() + ; it != S->end() + ; ++it) + { + traverse_constraint(*it); + } +}) +DEF_TRAVERSE_CONSTRAINT_ARRAY(ca_crc,{}) +DEF_TRAVERSE_CONSTRAINT_ARRAY(ca_csv,{}) +DEF_TRAVERSE_CONSTRAINT_ARRAY(ca_uni,{ + for (asn1::constraint::iterator it = S->begin() + ; it != S->end() + ; ++it) + { + traverse_constraint(*it); + } + +}) +DEF_TRAVERSE_CONSTRAINT_ARRAY(ca_int,{}) +DEF_TRAVERSE_CONSTRAINT_ARRAY(ca_exc,{}) +DEF_TRAVERSE_CONSTRAINT_ARRAY(ca_aex,{}) + + +/** + * END + */ +#undef DEF_TRAVERSE_STRING +#undef DEF_TRAVERSE_TYPE +#undef DEF_TRAVERSE_CONSTRUCTED +#undef DEF_TRAVERSE_PRIMITIVE +#undef DEF_TRAVERSE_CLASSFIELD + +/* END NAMESPACE ASN1 */ +} + +#endif diff --git a/adt/asn1_reference.cpp b/adt/asn1_reference.cpp new file mode 100644 index 0000000..c54c209 --- /dev/null +++ b/adt/asn1_reference.cpp @@ -0,0 +1,199 @@ + +#include +#include +#include +#if defined(_WIN32) +#include +#endif +#include "asn1_node.h" +#include "asn1_reference.h" + +namespace asn1 { + +static +char lop_substitute(char c) +{ + return (c == '-')?'_':c; +} + +reference::reference() + : node ("",type::ASN1_REFERENCE) +{ +} + +reference::reference(const asn1::reference::component &c) + : node("",type::ASN1_REFERENCE) +{ + add_component(c); +} + +reference::reference(const asn1::reference::component_list &c) + : node("",type::ASN1_REFERENCE) +{ + add_components(c); +} + +reference::reference(const reference &ref) + : node(ref) +{ + std::copy( ref.m_components.begin() + , ref.m_components.end() + , std::back_inserter(m_components)); +} + +reference::~reference() +{ +} + +void +reference::add_component(const struct component &c) +{ + m_components.push_back(c); +} + +void +reference::add_components(const component_list &c) +{ + std::copy(c.begin(),c.end(),std::back_inserter(m_components)); +} + + +std::string +reference::name() const +{ + std::string s; + if (m_components.size() > 0) + { + for (component_const_iterator it = m_components.begin(); + it != m_components.end(); + ++it) + { + if (s.size() > 0) + s = s + "::"; + s = s + (*it).m_identifier; + } + } + return s; +} + +void +reference::replace_objectclass(const std::string &o) +{ + component n(o,component::CAPITALS); + m_components.pop_front(); + m_components.push_front(n); +} + +std::string +reference::cpp_name() const +{ + std::string n = name(); + std::string cppname; + cppname.resize(n.size()); + + std::transform(n.begin(),n.end(),cppname.begin(),asn1::lop_substitute); + return cppname; +} + + + +reference::component::component(const std::string &n ,component::eType _t) : type(_t), m_identifier(n) {} + +bool +reference::component::operator ==(const struct component &c) +{ +return (!m_identifier.compare(c.m_identifier) && type == c.type); +} + + + + + +reference::component_iterator +reference::begin() { return m_components.begin();}; + +reference::component_iterator +reference::end() { return m_components.end();}; + +reference::component_const_iterator +reference::begin() const { return m_components.begin();}; + +reference::component_const_iterator +reference::end() const { return m_components.end();}; + +reference::component +reference::back() { return m_components.back();}; + +reference::component +reference::front() const { return m_components.front();}; + +size_t +reference::size() const { return m_components.size();} ; + +reference::component_list & +reference::get_components() { return m_components; }; + +const +reference::component_list & +reference::get_components() const { return m_components; }; + +bool +reference::equals(const reference &) const { return false; } ; + +bool +reference::operator ==(const reference &r) const{ return equals(r); }; + + + +/** **/ +bool simple_reference::equals(const reference &r) +{ + return (size() == r.size()) + && (front() == r.front()); +} +/** **/ +external_type_reference::external_type_reference(const std::string &module,const std::string &tp) + : reference(component(module,component::Uppercase)) +{ + component c(tp,component::Uppercase); + add_component(c); +} + +external_type_reference::external_type_reference(const std::string &module,const reference::component_list &tp) + : reference(component(module,component::Uppercase)) +{ + add_components(tp); +} + +external_type_reference::external_type_reference(const std::string &module,const reference &tp) + : reference(component(module,component::Uppercase)) +{ + add_components(tp.get_components()); +} + + +bool external_type_reference::equals(const reference &r) +{ + return (size() == r.size()) + && (front() == r.front()); +} + +/** **/ + +external_value_reference::external_value_reference(const std::string &module,const std::string &val) +: reference(component(module,component::Uppercase)) +{ + component c(val,component::Lowercase); + add_component(c); +} + +external_value_reference::~external_value_reference() {} + +bool external_value_reference::equals(const reference &r) +{ + return (size() == r.size()) + && (front() == r.front()); +} + + +} diff --git a/adt/asn1_reference.h b/adt/asn1_reference.h new file mode 100644 index 0000000..21fb427 --- /dev/null +++ b/adt/asn1_reference.h @@ -0,0 +1,197 @@ +#ifndef ASN1_REFERENCE_H +#define ASN1_REFERENCE_H + +namespace asn1 { + +class node; + +class reference : public node { + public: + struct component; + + typedef std::list component_list; + typedef std::list::iterator component_iterator; + typedef std::list::const_iterator component_const_iterator; + + reference(); + + reference(const struct component &c) ; + + reference(const reference &_r) ; + + reference(const component_list &cl); + + ~reference(); + + /** + * + */ + struct component + { + enum eType { + UNKNOWN, + CAPITALS, + Uppercase, + Lowercase, + AmpUppercase, + AmpLowercase + + } type; + + std::string m_identifier; + + inline std::string name() const { return m_identifier; }; + + component(const std::string &n = "" ,eType _t = UNKNOWN) ; + + bool operator ==(const struct component &c); + + }; + + + void add_component(const struct component &c); + + void add_components(const component_list &cl); + + std::string name() const; + + std::string cpp_name() const; + + component_iterator begin() ; + + component_iterator end(); + + component_const_iterator begin() const; + + component_const_iterator end() const; + + component back(); + component front() const ; + size_t size() const ; + + component_list &get_components() ; + + const component_list &get_components() const; + + virtual bool equals(const reference &) const; + + bool operator ==(const reference &r) const ; + + void replace_objectclass(const std::string &o); + protected: + component_list m_components; +}; + +/** + * + */ +class simple_reference : public reference +{ + public: + simple_reference(const struct component &c) : reference() + { + } + + simple_reference(const std::string &n,component::eType _t = component::Uppercase) + : reference(component(n,_t) ) + { + } + + ~simple_reference() {} + + virtual bool equals(const reference &r) ; + protected: +}; + +/** + * + */ +class external_type_reference : public reference +{ + public: + external_type_reference(const std::string &module,const std::string &tp) ; + + external_type_reference(const std::string &module,const reference::component_list &tp) ; + + external_type_reference(const std::string &module,const reference &tp); + + ~external_type_reference() {} + + virtual bool equals(const reference &r) ; + protected: +}; + + +/** + * + */ +class external_value_reference : public reference +{ + public: + external_value_reference(const std::string &module,const std::string &val) ; + ~external_value_reference() ; + + virtual bool equals(const reference &r) ; + protected: +}; + + +/** + * objectclass reference can contain + * typefield reference + * valuefied reference + * type referece + * I think that this is the only class that needs a list of fields + */ +class objectclass_reference : public reference +{ + public: + objectclass_reference(const std::string &n) + : reference(component(n,component::CAPITALS)) + { + } ; + ~objectclass_reference() {} ; + + std::string objectclass() + { + return m_components.front().m_identifier; + } + + std::string field() const + { return m_components.back().m_identifier; } +}; + + +/** + * + */ +class typefield_reference : public reference +{ + public: + typefield_reference(const std::string &n) + : reference(component(n,component::AmpUppercase)) + { + } ; + ~typefield_reference() {} ; +}; + + +/** + * + */ +class valuefield_reference : public reference +{ + public: + valuefield_reference(const std::string &n) + : reference(component(n,component::AmpLowercase)) + { + } ; + ~valuefield_reference() {} ; +}; + + + + +} +#endif + diff --git a/adt/asn1_resolver.cpp b/adt/asn1_resolver.cpp new file mode 100644 index 0000000..e865bfd --- /dev/null +++ b/adt/asn1_resolver.cpp @@ -0,0 +1,494 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_meta.h" +#include "asn1_type.h" +#include "asn1_value.h" +#include "asn1_constraint.h" +#include "aeb/pointer/intrusive_ptr.h" +#include "asn1_module.h" //includes nodes. + +#include "asn1_resolver.h" +#if defined(_WIN32) +#define GEN_LOG_DEBUG(fmt,...) +#define GEN_LOG_INFO(fmt,...) +#define GEN_LOG_ERROR(fmt,...) +#define GEN_LOG_WARN(fmt,...) +#else +#define GEN_LOG_DEBUG(fmt,args...) +#define GEN_LOG_INFO(fmt,args...) +#define GEN_LOG_ERROR(fmt,args...) fprintf(stderr,fmt,args) +#define GEN_LOG_WARN(fmt,args...) +#endif +namespace asn1 { + +/** + * + */ +resolver::resolver( const asn1::module &_m + , const asn1::module::modules_type &_mods) + : m_module(_m),m_module_list(_mods) +{ +} + +/** + * + */ +resolver::~resolver() +{ +} + +/** + * Resolve with reference + * Simple references should be found in the current module + */ +asn1::node * resolver::resolve(const typeref &_ref) +{ + asn1::node *nr = NULL; + if ( _ref.is_simple()) + { + asn1::node::const_iterator it = std::find_if(m_module.begin() + , m_module.end() + , asn1::find_node(_ref.name())); + if (it != m_module.end()) + { +#if 0 + // 2017/05/10 Issue with H323 and typeref resolve !! Fails with ClearToken + // Found Here null in caller. Looks like a stack overflow + std::cerr<<"resolver::resolve type "<<_ref.name()<<" Found in module\n"; + std::cerr<<"resolver::resolve "<<(*it)->as_assignment()->get_type()->name()<<" Found in module "; + std::cerr<<(*it)->as_assignment()->get_type()<<"\n"; +#endif + return (*it)->as_assignment()->get_type(); + }else + { + // Node not found in module, try other modules from imports + asn1::node *ns; + if (type_in_imports(_ref.name(),&ns)) + { + if ( !get_type_in_module(ns->name(),_ref.name(),&nr) ) + { + std::cerr<<"resolver::resolve type <"<<_ref.name(); + std::cerr<<"> Not Found in module "<name()<from_module()->name()<<" Found\n"; +#endif + GEN_LOG_WARN("resolver::resolve tye %s found in imports %s\n" + , _ref.name().c_str() + , ns->name().c_str() + ); + nr = nr->as_assignment()->get_type(); + } + } else + { + std::string modname(""); + if (! _ref.is_imported(modname)) + modname = _ref.from_module()->name(); + // Type not in imports. + std::cerr<<"resolver::resolve type <"<<_ref.name()<<" not in imports"<name(); + std::cerr<<" meta="<<(*it)->meta_id()()<as_assignment()->get_type(); + it = std::find_if(m_module.begin() + , m_module.end() + , asn1::find_node(nt->name())); + std::cerr<<"resolver::resolve warning object class reference "<name()<name()<name()); + asn1::node *n = resolve_objcls(_ref,rr); + return n; + } else + { + asn1::node *n = resolve_objcls(_ref,ocr); + if (! n) + { + std::cerr<<"resolver::resolve unable to resolve "<<_ref.name()<type_node()) + { + std::cerr<<"resolver::resolve result from resolve_objcls "<<_ref.name()<as_typenode()) + n = n->type_node(); + } + return n; + } + } else if (_ref.is_external()) + { + asn1::reference::component_const_iterator it = _ref.get_reference()->begin(); + asn1::module *m = module((*it).name()); + assert(0 && " external ref should never occur, it's transformed at parsing level"); + } else + { + // Loop over components. + asn1::reference::component_const_iterator it = _ref.get_reference()->begin(); + std::cerr<<"resolver::resolve Not Yet Supported " <<_ref.name()<<"\n"; + } + return nr; +} + +/** Resolve with parameters + * parameter can be a typereference. + * typeref contains act_parameters, + * lookup in _params, in module, in imports + */ + +bool resolver::resolve(typeref &_ref,parameters _params,asn1::node &type) +{ + return false; +} + +/** + * + */ +asn1::node * +resolver::resolve_objcls(const asn1::typeref &tref,asn1::objectclass_reference &ref) +{ + asn1::node *nr = NULL; + if (ref.size() <= 1) + { + asn1::node::const_iterator it = std::find_if(m_module.begin() + , m_module.end() + , asn1::find_node(ref.name())); + if (it != m_module.end()) + { + nr = (*it)->as_assignment()->get_type(); + } else + { + // Node not found in module, try other modules + asn1::node *ns; + if (type_in_imports(ref.name(),&ns)) + { + if ( !get_type_in_module(ns->name(),ref.name(),&nr) ) + { + std::cerr<<"Object "<name(); + std::cerr<<" Not Found in module "<as_assignment()->get_type(); + } + } + } + + } else if (std::string("TYPE-IDENTIFIER::&Type").compare(ref.name()) == 0) + { + asn1::constraint::const_iterator c = tref.constraint_begin(); + if ((*c)->type() == asn1::constraint::EL_TYPE) + { + asn1::typeref *ctype = dynamic_cast((*c)->value()); + assert(ctype != NULL); + std::cerr<<__FUNCTION__<<" GOT TYPE-IDENTIFIER&Type "<name()<name()<type_node(); + } + } else + { + asn1::classdef *current_cls = NULL; + asn1::reference::component_const_iterator it = ref.begin(); + do + { + asn1::node *cident = NULL; + std::string cname = (*it).m_identifier; + if ( (cname[0] != '&') ) + { + asn1::node *ns; + if (get_type_in_module(m_module.name(),cname,&cident)) + { + current_cls = dynamic_cast(cident->as_assignment()->get_type()); + } else if (type_in_imports(cname,&ns) + && get_type_in_module(ns->name(),cname,&cident) + ) + { + current_cls = dynamic_cast(cident->as_assignment()->get_type()); + } else + { + assert(0); + } + } else if (cname[0] == '&' && current_cls) + { + //asn1::node::iterator cls_attribute = std::find_if(current_cls->begin(), + // current_cls->end(), + // asn1::find_node((*it).m_identifier)); + asn1::classfield *cls_attribute = current_cls->get_classfield((*it).m_identifier); + if (cls_attribute != NULL) + { + //std::cerr<<"Found "<<(*cls_attribute)->name()<<" In class\n"; + // Wow attribute found in class Now I can decide what to do + switch( cls_attribute->type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_TF: + GEN_LOG_DEBUG("resolver::Found typefield %s in class %s\n" + , (*it).m_identifier.c_str() + , current_class->name().c_str()); + + break; + case asn1::type::ASN1_CLASSFIELD_FTVF: + { + GEN_LOG_DEBUG("resolver::Found typefield FTVF %s in class %s\n" + , (*it).m_identifier.c_str() + , current_class->name().c_str()); + } + break; + case asn1::type::ASN1_CLASSFIELD_OSF: + { + asn1::typeref *rnode = + dynamic_cast(cls_attribute->get_type()); + std::cerr<<"PRBL "<<(*it).m_identifier<<" CLS:"<name()<<"\n"; + asn1::node *n = resolve(*rnode); + if (n) + { + std::cerr<<"Got N"<<" CLS:"<name()<<"\n"; + current_cls = dynamic_cast(n); + } + + } + break; + default: + GEN_LOG_ERROR("resolver::Found typefield %s in class %s NOT HANDLED\n" + , (*it).m_identifier.c_str() + , current_cls->name().c_str()); + break; + } /* end switch */ + //TODO not good, nr should not be classfield + std::cerr<<__FUNCTION__<<" nr should not be class field "<name()<identifier()->name()<<"\n"; + assert(0); + } + } else + { + std::cerr<<"NOT Found "<name(),ns); +} + +bool resolver::type_in_imports(const std::string &type + , asn1::node **ns) const +{ + bool ret = false; + asn1::import_list *imports = m_module.imports(); + if (imports == NULL) + { + GEN_LOG_ERROR("type %s not in imports no imports\n",type.c_str()); + return ret; + } + asn1::node::iterator it = imports->begin(); + GEN_LOG_DEBUG("lookup for type %s\n",type.c_str()); + for (; it != imports->end();it++) + { + asn1::import *import = dynamic_cast(*it); + asn1::node::iterator found = std::find_if( import->begin() + , import->end() + , asn1::find_node(type)); + if (found != import->end() ) + { + GEN_LOG_DEBUG("found %s in %s\n",type.c_str(),import->identifier()->name().c_str()); + *ns = import->identifier(); + ret = true; + break; + } + } + return ret; +} + +/** + * + * + */ +asn1::module * +resolver::module(const std::string &mod_name) const +{ + modules_const_iterator mit = std::find_if(m_module_list.begin() + , m_module_list.end() + , asn1::find_module(mod_name)); + if (mit != m_module_list.end()) + { + return *mit; + } else + return NULL; +} + +/** + * + */ +bool +resolver::get_type_in_module( const std::string &mod_name + , const std::string &typ_name + , asn1::node **n) const +{ + GEN_LOG_INFO("resolver::get_type_in_module module=%s current_module=%s name=%s modules=%lu\n" + , mod_name.c_str() + , m_module->name().c_str() + , typ_name.c_str() + , m_modules.size()); + + modules_const_iterator mit = std::find_if(m_module_list.begin() + , m_module_list.end() + , asn1::find_module(mod_name)); + + if (mit != m_module_list.end()) + { + asn1::node::iterator nit = + std::find_if( (*mit)->begin() + , (*mit)->end() + , asn1::find_node(typ_name)); + if (nit != (*mit)->end()) + { + *n = (*nit); + return true; + } else + { + std::cerr<<"resolver::get_type_in_module "<name()<size() + ); + return false; + } + } else + { + std::cerr<<"resolver::get_type_in_module did not find module "<as_assignment(); + return true; + } else + { + std::cerr<<"resolver::get_type_in_module "<begin(); + GEN_LOG_DEBUG( "%s lookup for type %s\n" + , __FUNCTION__ + , typ_name.c_str()); + for (; it != imports->end();it++) + { + asn1::import *import = dynamic_cast(*it); + asn1::node::iterator found = std::find_if( import->begin() + , import->end() + , asn1::find_node(typ_name)); + if (found != import->end() ) + { + GEN_LOG_DEBUG( "%s found %s in %s\n" + , __FUNCTION__ + , type.c_str() + , import->identifier()->name().c_str()); + *in_module = module(import->identifier()->name()); + ret = true; + break; + } + } + return ret; +} + + + + + + + +} diff --git a/adt/asn1_resolver.h b/adt/asn1_resolver.h new file mode 100644 index 0000000..0b234fc --- /dev/null +++ b/adt/asn1_resolver.h @@ -0,0 +1,68 @@ +#ifndef ASN1_RESOLVER_H +#define ASN1_RESOLVER_H + +namespace asn1 { +/** + * The purpose of the class is to resolve + * references. Example : given a reference, + * the resolver will find the correponding type. + * T1 ::= SEQUENE { } + * T2 ::= CHOICE { t1 T1 } + * resolve T1 returns type SEQUENCE T1. + */ +class resolver +{ + public: + typedef asn1::module::modules_type modules_type; + typedef asn1::module::modules_type::iterator modules_iterator; + typedef asn1::module::modules_type::const_iterator modules_const_iterator; + typedef asn1::node::iterator node_iterator; + + /// constructor + resolver( const asn1::module &_m + , const asn1::module::modules_type &_mods); + /// copy constructor + resolver( const resolver &_r) + : m_module(_r.m_module), m_module_list(_r.m_module_list) {} + /// + virtual ~resolver(); + // Resolve with reference + // If found return type node of found reference + asn1::node *resolve(const typeref &_ref); + // Resolve with parameters + // parameter can be a typereference. + // typeref contains act_parameters, + // lookup in _params, in module, in imports + bool resolve(typeref &_ref,parameters _params,asn1::node &type); + + asn1::module *module(const std::string &mn) const; + protected: + asn1::node *resolve_objcls(const typeref &tref, asn1::objectclass_reference &ref); + + bool get_type_in_module( const std::string &mod_name + , const std::string &typ_name + , asn1::node **n) const; + /** + * New way ... + */ + bool get_type_in_module( asn1::module &mod + , const std::string &typ_name + , asn1::assignment **n) const; + /** + * check if typename is in imports of module + * if so, return module that contains the type. + */ + bool get_type_in_module_import( const asn1::module &mod + , const std::string &typ_name + , asn1::module **in_module) const; + + bool type_in_imports(asn1::node *type,asn1::node **ns) const; + + bool type_in_imports(const std::string &type,asn1::node **ns)const ; + protected: + const asn1::module &m_module; // Current module + const asn1::module::modules_type &m_module_list; +}; + +} +#endif /*ASN1_RESOLVER_H*/ diff --git a/adt/asn1_type.h b/adt/asn1_type.h new file mode 100644 index 0000000..47167b6 --- /dev/null +++ b/adt/asn1_type.h @@ -0,0 +1,113 @@ +#ifndef ASN1_TYPE_H__ +#define ASN1_TYPE_H__ + + +namespace asn1 +{ + + class type + { + public: + typedef enum { + INVALID = 0 , +#if 1 +#define ASN1_TYPE(cls,parent,id) ASN1_##id , +#define ASN1_STRING_TYPE(cls,parent,id) ASN1_STRING_##id , +#define ASN1_ABSTRACT_STRING_TYPE(cls,parent,id) ASN1_##id , +#include "adt/asn1_type.inc" +#else + ASN1_REFERENCE, + ASN1_EXPORTVAR, + ASN1_UNIVERSAL, + ASN1_BITVECTOR, + ASN1_EXTENSIBLE, + ASN1_COMPONENTS_OF, + ASN1_VALUESET, + ASN1_CLASSDEF, + ASN1_INSTANCE, + + /** + * Class Field type + */ + ASN1_CLASSFIELD, /* */ + ASN1_CLASSFIELD_TF, /* Type Field 10 */ + ASN1_CLASSFIELD_FTVF, /* Fixed Type Value Field */ + ASN1_CLASSFIELD_VTVF, /* Variable Type Value Field */ + ASN1_CLASSFIELD_FTVSF, /* Fixed Type Value Set Field */ + ASN1_CLASSFIELD_VTVSF, /* Variable Type Value Set Field*/ + ASN1_CLASSFIELD_OF, /* Object Field */ + ASN1_CLASSFIELD_OSF, /* Object Set Field */ + /* Constructed Types + */ + ASN1_SEQUENCE, /* 18 */ + ASN1_CHOICE, + ASN1_SET, + ASN1_SEQUENCE_OF, + ASN1_SET_OF, + ASN1_SELECTION, + /* Basic Types + */ + ASN1_ANY, + ASN1_BOOLEAN, + ASN1_INTEGER, + ASN1_BIT_STRING, + ASN1_OCTET_STRING, + ASN1_NULL, + ASN1_OBJECT_IDENTIFIER, + ASN1_OBJECT_DESCRIPTOR, + ASN1_REAL, + ASN1_ENUMERATED, + ASN1_RELATIVE_OID, + ASN1_EXTERNAL, + ASN1_EMBEDDED_PDV, + ASN1_CHARACTER_STRING, + ASN1_UTCTime, + ASN1_GeneralizedTime, + /* String Types + */ + ASN1_STRING, + ASN1_STRING_IA5String, + ASN1_STRING_PrintableString, + ASN1_STRING_VisibleString, + ASN1_STRING_ISO646String, /* aka VisibleString */ + ASN1_STRING_NumericString, + ASN1_STRING_UniversalString, + ASN1_STRING_BMPString, + ASN1_STRING_UTF8String , + ASN1_STRING_GeneralString, + ASN1_STRING_GraphicString, + ASN1_STRING_TeletexString, + ASN1_STRING_T61String, + ASN1_STRING_VideotexString, + ASN1_STRING_ObjectDescriptor, +#endif + ASN1_TYPE_MAX + } id; + + inline type(type::id id = INVALID) : m_id(id) {}; + inline type(const type &m) : m_id(m.m_id) {}; + inline type &operator =( const type &m) {m_id = m.m_id; return *this;}; + inline type &operator =( const id i) {m_id = i; return *this;}; + inline ~type() {}; + inline bool operator >(const type &a) {return m_id > a.m_id; }; + inline bool operator >=(const type &a) {return m_id >= a.m_id; }; + inline bool operator <=(const type &a) {return m_id <= a.m_id; }; + inline bool operator <(const type &a) {return m_id < a.m_id; }; + inline bool operator ==(const type &a) {return m_id == a.m_id; }; + + inline id operator()() const + { + return m_id; + } + + const char *name() const ; + friend std::ostream & operator <<(std::ostream &os, const type &m) + { + os< +#include +#include + +#include +#include "asn1_node.h" +#include "asn1_reference.h" +#include "asn1_value.h" +#include "asn1_constraint.h" + +namespace asn1 { + +value::value(asn1::value::etype tp) + : type(tp) , m_ref(0) , m_constraint(NULL) +{ +} + +value::value(const asn1::value &v) +{ +} + +value::value( const std::string &_s) + : type(VT_STRING),m_string(_s),m_ref(0),m_constraint(NULL) +{ +} +value::value( const asn1::constraint *_c) + : m_ref(0),m_constraint(NULL) +{ + m_constraint = const_cast(_c); +} +value::value( double _d) + : type(VT_REAL),m_real(_d) , m_ref(0), m_constraint(NULL) +{ +} +value::value( long _l) + : type(VT_INTEGER),m_integer(_l),m_ref(0),m_constraint(NULL) +{ +} +value::value( long long _l) + : type(VT_INTEGER),m_integer(_l),m_ref(0),m_constraint(NULL) +{ +} + +value::~value() +{ +} + +std::string +value::cpp_name() const +{ + switch (type) + { + case VT_TRUE: + return std::string("true"); + case VT_FALSE: + return std::string("false"); + case VT_MIN: + return std::string("MIN"); + case VT_MAX: + return std::string("MAX"); + case VT_STRING: + return m_string; + case VT_INTEGER: + { + std::ostringstream oss; + oss<type_id()()) + { + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + std::ostringstream os; + asn1::object_identifier *oid = m_node->as_object_identifier(); + os.str(""); + os<hash(); + return os.str(); + } + case asn1::type::ASN1_INTEGER: + return m_node->cpp_name(); + default: + { + std::ostringstream os; + os.str(""); + os<<"cpp_name()<<" id="<type_id()()<<">"; + return os.str(); + } + } + case VT_VALUESET: /* {1 | 2 | 3 } */ + // this shall be a constraint .... + if (m_constraint) + { + return m_constraint->name(); + } else + return std::string("todo"); + case VT_REFERENCED: /* Reference a value elsewhere */ + return m_reference->name(); + default: + return std::string("unknown"); + ; + }; +} + +}; diff --git a/adt/asn1_value.h b/adt/asn1_value.h new file mode 100644 index 0000000..da7f5d6 --- /dev/null +++ b/adt/asn1_value.h @@ -0,0 +1,61 @@ +#ifndef ASN1_VALUE_H +#define ASN1_VALUE_H +#include "aeb/sys/log.h" +#include "aeb/sys/log.h" +#include "aeb/pointer/intrusive_ptr.h" + +namespace asn1 { +// forward declaration + class constraint; + class reference; + class node; +struct value +{ + + public: + INTRUSIVE_DECLARATION(value) + + enum etype { + VT_NOVALUE, + VT_TYPE, + VT_NULL, + VT_REAL, + VT_INTEGER, /* an Integer */ + VT_MIN, + VT_MAX, + VT_TRUE, + VT_FALSE, + VT_STRING, /* "abcd" */ + VT_BITVECTOR, /* binary - hex string */ + VT_COLON, /* choice value ex local : value */ + VT_VALUESET, /* {1 | 2 | 3 } */ + VT_SETVALUE, /* { which list} needs to be parser with the right type for assignement. Is Opaque */ + VT_REFERENCED /* Reference a value elsewhere */ + + } type; + + value( asn1::value::etype tp = VT_NOVALUE); + value( const std::string &_s); + value( const asn1::constraint *_c); + value(const asn1::value &v); + value( double _d); + value( long _l); + value( long long _l); + + ~value(); + + std::string cpp_name() const; + std::string m_string; + long long m_integer; + double m_real; + asn1::reference *m_reference; + asn1::constraint *m_constraint; + asn1::node *m_node; +}; + +}; + +/* + vim:et:sw=2:ts=2 + */ +#endif diff --git a/adt/asn1_visitor.h b/adt/asn1_visitor.h new file mode 100644 index 0000000..b0b4653 --- /dev/null +++ b/adt/asn1_visitor.h @@ -0,0 +1,164 @@ +#ifndef ASN1_VISITOR_H__ +#define ASN1_VISITOR_H__ + +class node; +class constraint; + +#ifdef DISPATCH +#undef DISPATCH +#endif +template +class node_visitor_base +{ + public: + node_visitor_base() {}; + virtual ~node_visitor_base() {}; +#define PTR(x) asn1::x * + +#define DISPATCH(NAME,CLASS,DEF) \ + return static_cast(this)->visit_ ## NAME(static_cast(n)); + +#define ASN1_TYPE(NAME,PARENT,DEF) \ + case asn1::type::ASN1_##DEF : DISPATCH(NAME,NAME,DEF) ; + +#define ASN1_STRING_TYPE(NAME,PARENT,DEF) \ + case asn1::type::ASN1_STRING_##DEF : DISPATCH(NAME,NAME,DEF) ; + + RetTyp visit(asn1::node *n) + { + switch (n->type_id()()) + { +#include "adt/asn1_type.inc" + default: + ; + } + } + // Default behavior is : If user does not implement a certain class + // move to parent class +#define ASN1_TYPE(NAME,PARENT,DEF) \ + RetTyp visit_##NAME( PTR(NAME) n) \ + {\ + DISPATCH(PARENT,PARENT,DEF) ; \ + } + +#include "adt/asn1_type.inc" + // Missing visitors + RetTyp visit_module(asn1::module *s) + { + return RetTyp(); + } + RetTyp visit_typenode(asn1::typenode *s) + { + return RetTyp(); + } + RetTyp visit_typeref(asn1::typeref *s) + { + return RetTyp(); + } + // + RetTyp visit_primitive(asn1::primitive *s) + { + return RetTyp(); + } + RetTyp visit_constructed(asn1::constructed *s) + { + return RetTyp(); + } + RetTyp visit_node(asn1::node *s) + { + return RetTyp(); + } +}; +#undef DISPATCH +template +class node_visitor : public node_visitor_base {}; + +/** + * Same for constraints + */ +template +class constraint_visitor_base +{ + public: + constraint_visitor_base() {}; + virtual ~constraint_visitor_base() {}; + +#define DISPATCH(DEF,NAME,CLASS) \ + return static_cast(this)->visit_ ## NAME(static_cast(n)); + +#define ELEMENT_CONSTRAINT(DEF,NAME,PARENT) \ + case asn1::constraint::DEF : DISPATCH(DEF,NAME,NAME) ; + + RetTyp visit(asn1::constraint *n) + { + switch (n->type()) + { +#include "asn1_constraint.inc" + default: + ; + } + } + // Default behavior is : If user does not implement a certain class + // move to parent class +#define ELEMENT_CONSTRAINT(DEF,NAME,PARENT) \ + RetTyp visit_##NAME( PTR(NAME) n) \ + {\ + DISPATCH(DEF,PARENT,PARENT) ; \ + } + +#include "asn1_constraint.inc" +}; + +template +class constraint_visitor : public constraint_visitor_base {}; + + +/** + * And a Visitor for Assignments ... + */ +#undef DISPATCH +template +class assignment_visitor_base +{ + public: + assignment_visitor_base() {}; + virtual ~assignment_visitor_base() {}; + +#define DISPATCH(DEF,NAME,CLASS) \ + return static_cast(this)->visit_ ## NAME(static_cast(n)); + +#define DISPATCH1(DEF,NAME,CLASS) \ + return static_cast(this)->visit_ ## NAME(static_cast(n)); + +#define ASSIGNMENT(DEF,NAME,PARENT) \ + case asn1::meta::DEF : DISPATCH(DEF,NAME,NAME) ; + + RetTyp visit(asn1::assignment *n) + { + switch (n->meta_id()()) + { +#include "asn1_meta.inc" + default: + ; + } + } + RetTyp visit_assignment(asn1::assignment *a) + {} + // Default behavior is : If user does not implement a certain class + // move to parent class +#define ASSIGNMENT(DEF,NAME,PARENT) \ + RetTyp visit_##NAME( PTR(NAME##_assignment) n) \ + {\ + DISPATCH1(DEF,PARENT,PARENT) ; \ + } + +#include "asn1_meta.inc" +}; + +template +class assignment_visitor : public assignment_visitor_base {}; +#undef DISPATCH +#undef DISPATCH1 + + +#endif diff --git a/cmip/CMIPActionListener.h b/cmip/CMIPActionListener.h new file mode 100644 index 0000000..83efc63 --- /dev/null +++ b/cmip/CMIPActionListener.h @@ -0,0 +1,7 @@ +#ifndef CMIPACTIONLISTENER_H +#define CMIPACTIONLISTENER_H + +class CMIPActionListener +{ +}; +#endif /*CMIPACTIONLISTENER_H*/ diff --git a/cmip/CMIPAgent.cpp b/cmip/CMIPAgent.cpp new file mode 100644 index 0000000..c6099ef --- /dev/null +++ b/cmip/CMIPAgent.cpp @@ -0,0 +1,151 @@ +#include +#include "Remote_Operations_Generic_ROS_PDUs.h" +#include "CMIP_1.h" +#include "CMIP_1.hpp" + +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +#include "CMIPListener.h" +#include "CMIPActionListener.h" +#include "CMIPEventReportListener.h" +#include "CMIPStack.h" +#include "CMIPAgent.h" + +using namespace CMIP_1; +using namespace Remote_Operations_Generic_ROS_PDUs; +using namespace Remote_Operations_Information_Objects; +namespace rose_ie = Remote_Operations_Information_Objects; + + + + + +/** + * + */ +CMIPAgent::CMIPAgent(CMIPStack &cmip_stack) + : m_CMIPStack(cmip_stack) +{ + std::cout<<"CMIPAgent::"<<__FUNCTION__< +#include +#include +#include "Remote_Operations_Generic_ROS_PDUs.h" +#include "CMIP_1.h" +#include "CMIP_1.hpp" + +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +#include "CMIPListener.h" +#include "CMIPActionListener.h" +#include "CMIPEventReportListener.h" +#include "CMIPStack.h" + +using namespace CMIP_1; +using namespace Remote_Operations_Generic_ROS_PDUs; +using namespace Remote_Operations_Information_Objects; +namespace rose_ie = Remote_Operations_Information_Objects; + + + +CMIPStack::CMIPStack() +{ +} + +/** + * + */ +void +CMIPStack::registerListener(CMIPActionListener *a) +{ +} + +/** + * + */ +void +CMIPStack::registerListener(CMIPEventReportListener *a) +{ +} + +/** + * + */ +void +CMIPStack::registerListener(CMIPListener *a) +{ + m_Listeners.push_back(a); +} + + +/** + * Down stream methods + * {m-Action | m-Action-Confirmed | m-CancelGet | m-Create | m-Delete | + * m-EventReport | m-EventReport-Confirmed | m-Get | m-Linked-Reply | m-Set | + * m-Set-Confirmed} + */ +void +CMIPStack::send_m_Action(CMIP_1::m_Action &action) +{ + m_Ctx.reset(); + ROS ros(ROS::typeof_invoke,asn1::tag(2,1)); + // + + Invoke &i = ros.get_invoke(); + i.invokeId.get_present() = 8; + i.argument = &action; + i.opcode.set_tag(asn1::tag(0,2)); + i.opcode.get_local() = action.get_operationCode().get_local(); + std::cout<(*(i.argument)); + } + break; + case opEventConfirm : + break; + case opLinkedReply : + break; + case opGet : + { + struct doGet { + doGet(CMIP_1::GetArgument &a) : m_arg(a) {}; + void operator ()(CMIPListener *l) + { l->on_m_Get(m_arg);} + CMIP_1::GetArgument &m_arg; + }; + CMIP_1::m_Get *o + = static_cast(*(i.argument)); + std::cout<<"CMIPStack::"<<__FUNCTION__; + std::cout<<" process GET"<<"\n"; + std::for_each(m_Listeners.begin() + , m_Listeners.end() + , doGet(o->get_ArgumentType()) + ); + std::cout<<" END process GET"<<"\n"; + } + break; + case opSet : + { + CMIP_1::m_Set *o + = static_cast(*(i.argument)); + } + break; + case opSetConfirm : + { + CMIP_1::m_Set_Confirmed *o + = static_cast(*(i.argument)); + } + break; + case opAction : + { + CMIP_1::m_Action *o + = static_cast(*(i.argument)); + } + break; + case opActionConfirm : + break; + case opCreate : + { + CMIP_1::m_Create *o + = static_cast(*(i.argument)); + } + break; + case opDelete : + { + CMIP_1::m_Delete *o + = static_cast(*(i.argument)); + } + break; + case opCancelGet : + break; + default: + ; + } +} + +void +CMIPStack::doReturnResult(rose_pdu::ReturnResult &r) +{ + if (r.bit_mask.test(rose_pdu::ReturnResult::result_present)) + { + assert(r.result->opcode.get_kind() == Code::typeof_local); + std::cout<<"CMIPStack::"<<__FUNCTION__; + std::cout<<" got "<opcode.get_local()<<"\n"; + rose_pdu::ReturnResult_result *result = *r.result; + switch (result->opcode.get_local().get_sys_value()) + { + case opEvent: + { + CMIP_1::m_EventReport *o + = static_cast(*(result->result)); + } + break; + case opEventConfirm : + break; + case opLinkedReply : + break; + case opGet : + { + CMIP_1::m_Get *o + = static_cast(*(result->result)); + std::cout<<"CMIPStack::"<<__FUNCTION__; + std::cout<<" process GET"<<"\n"; + o->printf(std::cout); + std::cout<<" END process GET"<<"\n"; + + } + break; + case opSet : + { + CMIP_1::m_Set *o + = static_cast(*(result->result)); + } + break; + case opSetConfirm : + { + CMIP_1::m_Set_Confirmed *o + = static_cast(*(result->result)); + } + break; + case opAction : + { + CMIP_1::m_Action *o + = static_cast(*(result->result)); + } + break; + case opActionConfirm : + break; + case opCreate : + { + CMIP_1::m_Create *o + = static_cast(*(result->result)); + } + break; + case opDelete : + { + CMIP_1::m_Delete *o + = static_cast(*result->result); + } + break; + case opCancelGet : + break; + default: + ; + } + } else + { + std::cout<<"CMIPStack::"<<__FUNCTION__; + std::cout<<" got "<<"no result"<<"\n"; + } +} + +void +CMIPStack::doReturnError(rose_pdu::ReturnError &re) +{ + std::cout<<"CMIPStack::"<<__FUNCTION__; + std::cout<<" TODO "<<"no result"<<"\n"; +} + +void +CMIPStack::doReject(rose_pdu::Reject &r) +{ + std::cout<<"CMIPStack::"<<__FUNCTION__; + std::cout<<" TODO "<<"no result"<<"\n"; +} + +namespace CMIP_1 { +extern rose_ie::IOPERATION *CMIP_Operations[]; +} +// Handle receive data from lower layer +void +CMIPStack::onReceive(asn1::streams::ber &ctx) +{ + //::asn1::types::debug_level = 8; + ROS ros; + ros.Invokable = CMIP_1::CMIP_Operations; + int result = ros.decode(ctx); + switch (ros.get_kind()) + { + case ROS::typeof_invoke: + doInvoke(ros.get_invoke()); + break; + case ROS::typeof_returnResult: + doReturnResult(ros.get_returnResult()); + break; + case ROS::typeof_returnError: + doReturnError(ros.get_returnError()); + break; + case ROS::typeof_reject: + doReject(ros.get_reject()); + break; + default: + std::cerr<<"CMIPStack::"<<__FUNCTION__<<" Big Issue\n"; + ; + } +} + diff --git a/cmip/CMIPStack.h b/cmip/CMIPStack.h new file mode 100644 index 0000000..1e2049f --- /dev/null +++ b/cmip/CMIPStack.h @@ -0,0 +1,94 @@ +#ifndef CMIPSTACK_H +#define CMIPSTACK_H + +namespace rose_pdu = Remote_Operations_Generic_ROS_PDUs; +/** + * @brief Public interface for the CMIP Stack + * Basicallly, the class allows sending data to lower + * and receive data from the lower layer. + * The layer below CMIP is ACSE / STASE The sub layer + * is responsible for association and authentication and so on + * Thus the stack should implement a Listener interface of + * the underneth Stack ACSE + */ +class CMIPStack +{ + public: + // Operations + enum { + opEvent = 0 + , opEventConfirm = 1 + , opLinkedReply = 2 + , opGet = 3 + , opSet = 4 + , opSetConfirm = 5 + , opAction = 6 + , opActionConfirm = 7 + , opCreate = 8 + , opDelete = 9 + , opCancelGet = 10 + }; + + public: + typedef std::list ActionListenerList; + typedef std::list EventReportListenerList; + typedef std::list ListenerList; + // Above Rose... And Stase + // + CMIPStack(); + /** + * + */ + void registerListener(CMIPActionListener *a); + /** + * + */ + void registerListener(CMIPEventReportListener *a); + /** + * + */ + void registerListener(CMIPListener *a); + + /** + * Down stream methods + * {m-Action | m-Action-Confirmed | m-CancelGet | m-Create | m-Delete | + * m-EventReport | m-EventReport-Confirmed | m-Get | m-Linked-Reply | m-Set | + * m-Set-Confirmed} + */ + void send_m_Action(CMIP_1::m_Action &o); + + void send_m_Action_Confirmed(CMIP_1::m_Action_Confirmed &o); + + void send_m_CancelGet(CMIP_1::m_CancelGet &o); + + void send_m_Create(CMIP_1::m_Create &o); + + void send_m_Delete(CMIP_1::m_Delete &o); + + void send_m_EventReport(CMIP_1::m_EventReport &o); + + void send_m_EventReport_Confirmed(CMIP_1::m_EventReport_Confirmed &o); + + void send_m_Get(CMIP_1::m_Get &o); + + void send_m_Linked_Reply(CMIP_1::m_Linked_Reply &o); + + void send_m_Set(CMIP_1::m_Set &o); + + void send_m_Set_Confirmed(CMIP_1::m_Set_Confirmed &o); + // Handle receive data from lower layer + void onReceive(asn1::streams::ber &ctx); + protected: + asn1::streams::ber m_Ctx; + ListenerList m_Listeners; + + void doInvoke(rose_pdu::Invoke &i); + void doReturnResult(rose_pdu::ReturnResult &rr); + void doReturnError(rose_pdu::ReturnError &re); + void doReject(rose_pdu::Reject &r); +}; + +/* + * vi:et sw=2 ts=2: + */ +#endif diff --git a/cmip/CMakeLists.txt b/cmip/CMakeLists.txt new file mode 100644 index 0000000..9b54d8f --- /dev/null +++ b/cmip/CMakeLists.txt @@ -0,0 +1,164 @@ +PROJECT(cmip-lib) + + +ADD_DEFINITIONS(-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER) + +IF (WITH_CMIP) +FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt CMIPMODULES) +SET(CMIP_ASN1P ${CMAKE_CURRENT_BINARY_DIR}/../asn1p) +SET(CMIP_ERULE "-e ber") +FOREACH(ITEM ${CMIPMODULES}) + STRING(REGEX REPLACE "-" "_" HITEM ${ITEM}) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h GENERATED) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp GENERATED) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp COMPILE_FLAGS "-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER") + SET(CMIPSRC ${CMIPSRC} ${ITEM}.cpp) + SET(CMIPHDR ${CMIPHDR} ${HITEM}.h) +ENDFOREACH(ITEM) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMIPSRC} ${CMIPHDR}" + ) + +SET(ROSE_PARSER_INC -n false -I ${asn1-data-models_SOURCE_DIR}/) +SET(ROSE_PARSER_OPT ${ROSE_PARSER_INC} -fRemote-Operations-Generic-ROS-PDUs.asn1) +SET(ROSE_PARSER_OPT ${ROSE_PARSER_OPT} -fRemote-Operations-Information-Objects.asn1) +SET(ROSE_PARSER_OPT ${ROSE_PARSER_OPT} + -fRemote-Operations-Useful-Definitions.asn1) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +# +#Remote-Operations-Generic-ROS-PDUs {joint-iso-itu-t remote-operations(4) +# +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Generic_ROS_PDUs.h + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Generic-ROS-PDUs.cpp + COMMAND ${CMIP_ASN1P} + ARGS ${ROSE_PARSER_OPT} -o Remote-Operations-Generic-ROS-PDUs + DEPENDS ${CMIP_ASN1P} + COMMENT "Build Remote-Operations-Generic-ROS-PDUs .h and .cpp" + ) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Generic-ROS-PDUs.h + GENERATED) +# +# +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Useful_Definitions.h + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Useful-Definitions.cpp + COMMAND ${CMIP_ASN1P} + ARGS ${ROSE_PARSER_OPT} -o Remote-Operations-Useful-Definitions + DEPENDS ${CMIP_ASN1P} + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Generic-ROS-PDUs.cpp + COMMENT "Build Remote-Operations-Usful-Definitions .h and .cpp" + ) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Useful-Definitions.h + GENERATED) +# +# +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + COMMAND ${CMIP_ASN1P} + ARGS ${ROSE_PARSER_OPT} -o Remote-Operations-Information-Objects + DEPENDS ${CMIP_ASN1P} + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Useful-Definitions.cpp + COMMENT "Build Remote-Operations-Informations-Objects .h and .cpp" + ) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.h + GENERATED) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CMIP_1.h + ${CMAKE_CURRENT_BINARY_DIR}/CMIP-1.cpp + COMMAND ${CMIP_ASN1P} + + ARGS ${ROSE_PARSER_OPT} -o CMIP-1 + -f CMIP-1.asn1 + DEPENDS ${CMIP_ASN1P} + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + COMMENT "Build CMIP-1 .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/ACSE_1.h + ${CMAKE_CURRENT_BINARY_DIR}/ACSE-1.cpp + COMMAND ${CMIP_ASN1P} + + ARGS ${ROSE_PARSER_OPT} -o ACSE-1 + -f cstav1/apdu_acse.asn1 + DEPENDS ${CMIP_ASN1P} + COMMENT "Build ACSE-1 .h and .cpp" + ) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/ACSE-1.cpp + GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/ACSE-1.cpp + COMPILE_FLAGS "-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER") +# Attribute-ASN1Module +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Attribute_ASN1Module.h + ${CMAKE_CURRENT_BINARY_DIR}/Attribute-ASN1Module.cpp + COMMAND ${CMIP_ASN1P} + + ARGS ${ROSE_PARSER_OPT} -o Attribute-ASN1Module + -f cstav1/apdu_acse.asn1 + -f cmip/Attribute-ASN1Module.asn1 + -f CMIP-1.asn1 + DEPENDS ${CMIP_ASN1P} + COMMENT "Build Attribute-ASN1Module .h and .cpp" + ) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Attribute-ASN1Module.cpp + GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Attribute-ASN1Module.cpp + COMPILE_FLAGS "-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER") + + + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/X721.h + ${CMAKE_CURRENT_BINARY_DIR}/X721.hpp + ${CMAKE_CURRENT_BINARY_DIR}/X721.cpp + COMMAND ${CMIP_ASN1P} + + ARGS ${ROSE_PARSER_OPT} -o X721 + -f cmip/x721-gdmo.asn1 + -f cmip/Attribute-ASN1Module.asn1 + -f CMIP-1.asn1 + -f x227/ACSE-1.asn1 + DEPENDS ${CMIP_ASN1P} + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + ${CMAKE_CURRENT_BINARY_DIR}/Attribute-ASN1Module.cpp + COMMENT "Build X721 .h and .cpp from x721-gdmo.asn1" + ) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/X721.hpp + GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/X721.cpp + GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/X721.cpp + COMPILE_FLAGS "-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER") + +ADD_LIBRARY(cmip + ${CMAKE_CURRENT_BINARY_DIR}/X721.hpp + ${CMIPSRC} + ) + +ADD_EXECUTABLE( test_cmip + X721.cpp + Attribute-ASN1Module.cpp + ACSE-1.cpp + CMIPStack.cpp + CMIPAgent.cpp + main.cpp + ) +TARGET_LINK_LIBRARIES(test_cmip cmip asn1) +ENDIF(WITH_CMIP) diff --git a/cmip/main.cpp b/cmip/main.cpp new file mode 100644 index 0000000..f3cc06e --- /dev/null +++ b/cmip/main.cpp @@ -0,0 +1,210 @@ +#include + +#include "Remote_Operations_Generic_ROS_PDUs.h" +#include "CMIP_1.h" +#include "CMIP_1.hpp" + +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +#include "CMIPListener.h" +#include "CMIPActionListener.h" +#include "CMIPEventReportListener.h" +#include "CMIPStack.h" +#include "CMIPAgent.h" + +#include "Attribute_ASN1Module.h" +#include "X721.h" +#include "X721.hpp" +using namespace CMIP_1; +using namespace Remote_Operations_Generic_ROS_PDUs; +using namespace Remote_Operations_Information_Objects; + +void test1() +{ + std::cerr<<"\n*\n* test CODE\n*"<set_ArgumentType(aaa); + Invoke &i = ros.get_invoke(); + i.invokeId.get_present() = 8; + i.argument = a; + i.opcode.set_tag(asn1::tag(0,2)); + i.opcode.get_local() = 7; + std::cout<set_tag(asn1::tag(2,CMISFilter::typeof_item)); + cl.filter->set_tag(asn1::tag(2,8)); + FilterItem &item = cl.filter->get_item(); + item.set_tag(asn1::tag(2,FilterItem::typeof_equality)); + + Attribute &attr = item.get_equality(); + X721::systemId *sid = new X721::systemId(); + attr.id.set_globalForm( sid->get_id().get_globalForm()); + sid->get_Value().set_number(asn1::INTEGER(3)); + attr.value = sid; + cl.scope->get_namedNumbers() = 403; + + std::cout<push_back(ai); + + ai.get_localForm() = 28; + getArgument.attributeIdList->push_back(ai); + + ai.set_globalForm( OBJECT_IDENTIFIER(4,"\x2a\x14\x23\x41")); + getArgument.attributeIdList->push_back(ai); + + m_Get *get = new m_Get(); + // + getArgument.baseManagedObjectClass.set_globalForm( + OBJECT_IDENTIFIER(5,"\x2a\x32\x12\x35\x12")); + + get->set_ArgumentType(getArgument); + + CMIPStack stack; + CMIPAgent agent(stack); + stack.send_m_Get(*get); +} + +void test6() +{ + std::cout<<"\n*\n* test CMIPStack "<<__FUNCTION__<<"\n*"<set_tag(asn1::tag(2,8)); // Way is this required ? + FilterItem &item = aaa.filter->get_item(); + //item.set_tag(asn1::tag(2,FilterItem::typeof_equality)); + item.set_tag(asn1::tag(2,0)); + Attribute &attr = item.get_equality(); + attr.id.set_tag(asn1::tag(2,2)); + X721::pdusSentCounter *pdusS = new X721::pdusSentCounter(); + pdusS->get_Value() = 23; + attr.id.set_globalForm( pdusS->get_id().get_globalForm()); + attr.value = pdusS; + + aaa.scope->get_namedNumbers() = 404; + + a->set_ArgumentType(aaa); + CMIPStack stack; + stack.send_m_Action(**a); +} + +void test7() +{ + std::cout<<"\n*\n* test CMIPStack "<<__FUNCTION__<<"\n*"<set_tag(asn1::tag(2,8)); // Why is this required ? + FilterItem &item = setA.filter->get_item(); + item.set_tag(asn1::tag(2,0)); + + Attribute &attr = item.get_equality(); + attr.id.set_tag(asn1::tag(2,2)); +#endif + X721::pdusSentCounter *pdusS = new X721::pdusSentCounter(); + pdusS->get_Value() = 25; +#if UF + attr.id.set_globalForm( pdusS->get_id().get_globalForm()); + attr.value = pdusS; +#endif + setA.scope->get_namedNumbers() = 407; + // +#if 1 + SetArgument_modificationList_type sa_mlt; + sa_mlt.attributeId.set_globalForm( pdusS->get_id().get_globalForm()); + sa_mlt.attributeValue = pdusS; + setA.modificationList.push_back(sa_mlt); + // Add another attribute + X721::systemId *sid = new X721::systemId(); + sid->get_Value().set_number(asn1::INTEGER(9)); + sa_mlt.attributeId.set_globalForm( sid->get_id().get_globalForm()); + sa_mlt.attributeValue = sid; + setA.modificationList.push_back(sa_mlt); +#endif + a->set_ArgumentType(setA); + CMIPStack stack; + stack.send_m_Set(**a); +} + + + +int main(int argc,char **argv) +{ + asn1::INTEGER op(1); + ::asn1::types::debug_level = 1; + std::cout<<"main get_local"< +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +#include "CSTA_event_report_definitions.h" +#include "CSTA_event_report_definitions.hpp" + +/** + +CSTAEventReportArgument ::= SEQUENCE { + crossRefIdentifier MonitorCorssRefID + eventSpecificInfo EventSpecificInfo +} + * +EventSpecificInfo ::= CHOICE { + callControlEvent [0] CallcontrolEvents, + +} + * +ConnectionID ::= [APPLICATION 11] CHOICE { + callID [0] IMPLICIT CallID, + deviceID [1] LocalDeviceID, + both SEQUENCE { + callID [0] IMPLICIT CallID, + deviceID [1] LocalDeviceID + } +} + +CallID ::= OCTET STRING +LocalDeviceID ::= CHOICE [ + staticID DeviceID + dynamicID [3] IMPLICIT OCTET STRING +} + +DeviceID ::= SEQUENCE { + deviceIdentifier CHOICE { + } +} + */ + +int test_decode() +{ + /* This sequence is for Alcatel CSTA which is not compatible with the ecma + * 285 description. Just forget it. Events are described diferently*/ + const unsigned char d[] ={ 0x30,0x46, + 0x55,0x04,0x00,0x00,0x00,0x04, + 0x80,0x01,0x0d, // For alcated, this Event Type 13 + //Context Specific - Primitive - Id=0 tag. Len 1 - value 0d 13 what is this ? + 0x30,0x1d, /* OriginatedEvent SEQUENCE len 0x1d 29*/ + 0x6b,0x0a, /* ConnectionID tag APPL 11 len 10 CHOICE*/ + 0x82,0x02,0x00,0x76, /* This should be both of ConnectionID*/ + 0x83,0x04,0x00, 0x03,0x00,0x00, /* supposed to be dynamic ID*/ + /** + SubjectDeviceID is (APPLICATION 3 Choice) + CalledDeviceID is (APPLICATION 2 Choice) + + */ + 0x4e,0x01,0x01, /* State initated */ + 0x0a,0x01, 0x16, /* Event Cause newCall*/ + /* I d'ont know what this is PRIVATE data */ + 0x63,0x05,0x84,0x03,0x31,0x30,0x32, /* loocks like SubjectDeviceID */ + 0x62,0x02,0x87,0x00}; /* looks like CalledDeviceID*/ + + CSTA_event_report_definitions::cSTAEventReport report; + asn1::context ctx; + memcpy(ctx.buffer(),d,41); + report.decode(ctx); + +} + +int main(int argc,char **argv) +{ + + CSTA_event_report_definitions::cSTAEventReport report; + //asn1::context ctx; + test_decode(); + //report.codec(ctx,asn1::CODEC_ENCODE); + std::cout<<"Hello world"< +// lib curl muli. +#include "curl/curl.h" +#include "AtraceReader.h" + + +AtraceCurlReader::AtraceCurlReader() +{ +} + +AtraceCurlReader::~AtraceCurlReader() +{ +} diff --git a/cstav1/AtraceDecoder.h b/cstav1/AtraceDecoder.h new file mode 100644 index 0000000..facd93c --- /dev/null +++ b/cstav1/AtraceDecoder.h @@ -0,0 +1,43 @@ +#ifndef ATRACEDECODER_H +#define ATRACEDECODER_H + +/** + * This class is responsible to decode binary traces and + * converte them into a readable form. + * -> Needs tbl files to be able to make the correspondance + * -> Need another listener. People might want trace from + * decoder and not Binary traces. + * + */ +class AtraceDecoder : public AtraceBinListener +{ + public: + AtraceDecoder(); + ~AtraceDecoder(); + + // + virtual void onBinState() {}; + virtual void onBinAel() {}; + virtual void onBinSend() {}; + virtual void onBinCmRecv() {}; + + // + virtual void onBinSoftAno() {}; + virtual void onBinHardAno() {}; + virtual void onBinHistoric() {}; + virtual void onBinDba() {}; + virtual void onBinString() {}; + + // + virtual void onIsbTrace() {}; + virtual void onIsbDump() {}; + + // + virtual void onBinPrintf() {}; + virtual void onCstaCore() {}; + virtual void onCstaServer() {}; + virtual void onManagedServices() {}; + + protected: +}; +#endif /*ATRACEDECODER_H*/ diff --git a/cstav1/AtraceListener.h b/cstav1/AtraceListener.h new file mode 100644 index 0000000..6ce237b --- /dev/null +++ b/cstav1/AtraceListener.h @@ -0,0 +1,50 @@ +#ifndef ATRACELISTENER_H +#define ATRACELISTENER_H + +/** + * Interface to be implemented by + * classes that intend to process + * Atrace Messages Implemented by Binary decoder + */ +class AtraceBinListener +{ + public: + AtraceBinListener() = 0 ; + ~AtraceBinListener() {} ; + // + virtual void onBinState() {}; + virtual void onBinAel() {}; + virtual void onBinSend() {}; + virtual void onBinCmRecv() {}; + + // + virtual void onBinSoftAno() {}; + virtual void onBinHardAno() {}; + virtual void onBinHistoric() {}; + virtual void onBinDba() {}; + virtual void onBinString() {}; + + // + virtual void onIsbTrace() {}; + virtual void onIsbDump() {}; + + // + virtual void onBinPrintf() {}; + virtual void onCstaCore() {}; + virtual void onCstaServer() {}; + virtual void onManagedServices() {}; +}; +/** + * Interface to be implemented by + * classes that intend to process + * Atrace Messages + */ +class AtraceListener +{ + public: + AtraceListener() = 0 ; + ~AtraceListener() {} ; + + virtual void onIsbMessage() {}; +}; +#endif /*ATRACELISTENER_H*/ diff --git a/cstav1/AtraceMsgs.h b/cstav1/AtraceMsgs.h new file mode 100644 index 0000000..e0f79cb --- /dev/null +++ b/cstav1/AtraceMsgs.h @@ -0,0 +1,60 @@ +#ifndef ATRACEMSGS_H +#define ATRACEMSGS_H + +typedef unsigned char byte; +typedef byte g_isb_id; +typedef byte g_isb_class; + +#define AT_DBG_BIN_STATE ((byte)0x0x01) +#define AT_DBG_BIN_AEL ((byte)0x0x02) +#define AT_DBG_BIN_CMSEND ((byte)0x0x03) +#define AT_DBG_BIN_CMRECV ((byte)0x0x04) + +#define AT_DBG_BIN_SOFTANO ((byte)0x0x07) +#define AT_DBG_BIN_HARDANO ((byte)0x0x08) +#define AT_DBG_BIN_HISTORIC ((byte)0x0x09) +#define AT_DBG_BIN_DBA ((byte)0x0x0A) +#define AT_DBG_BIN_STRING ((byte)0x0x0B) + +#define AT_DBG_BIN_ISB_TRACE ((byte)0x0x0D) +#define AT_DBG_BIN_ISB_DUMP ((byte)0x0x0E) +#define AT_DBG_BIN_PRINTF ((byte)0x0x0F) + +#define AT_DBG_BIN_CSTA_CORE ((byte)0x0x19) +#define AT_DBG_BIN_CSTA_SERVER ((byte)0x0x1A) +#define AT_DBG_BIN_MANAGED_SERVICES ((byte)0x0x1B) + + +/** + * + */ +typedef struct + char spyb_header; + byte high_length; + byte low_length; + g_isb_id transmitter_id; + g_isb_class clas; + byte msg_family; + byte msg_name; + byte eqt_id; + byte sub_eqt_id; + byte param[1]; +} g_header; + +/** + * + */ +typedef struct { + byte trace_pattern; + byte trace_format; + WORD trace_sequence; + // This is an endianess problem + unsigned trace_length_hi : 1; + unsigned trace_sender : 5; + unsigned trace_truncated : 1; + unsigned /* alignment */ : 1; + unsigned trace_length_lo : 8; +} g_dbg_trace_header; + + +#endif /*ATRACEMSGS_H*/ diff --git a/cstav1/AtraceReader.h b/cstav1/AtraceReader.h new file mode 100644 index 0000000..3b27538 --- /dev/null +++ b/cstav1/AtraceReader.h @@ -0,0 +1,39 @@ +#ifndef ATRACEREADER_H +#define ATRACEREADER_H + +/** + * Generique class to read Debug messages. + * Decline this class into two other classes + * -> AtraceCURLReader + * -> AtraceFileReader + */ +class AtraceReader +{ + public: + typedef std::list ListenerList; + typedef ListenerList::iterator iterator; + + AtraceReader(); + ~AtraceReader(); + + void registerListener(AtraceListener *l) + { m_Listener.push_back(l); }; + protected: + ListenerList m_Listerners; + +}; + + +/** + * Atrace reader specialisation + * I need Host, Password Endianess + */ +class AtraceCurlReader : public AtraceReader +{ + public: + AtraceCurlReader(); + ~AtraceCurlReader(); + protected: +}; + +#endif /*ATRACEREADER_H*/ diff --git a/cstav1/CExpatImpl.h b/cstav1/CExpatImpl.h new file mode 100644 index 0000000..929c2ff --- /dev/null +++ b/cstav1/CExpatImpl.h @@ -0,0 +1,862 @@ +#ifndef DSSI_EXPATIMPL_H + #define DSSI_EXPATIMPL_H +#ifdef __GNUC__ +#define __cdecl __attribute__((__cdecl__)) +#endif + //----------------------------------------------------------------------------- + // + // @doc + // + // @module ExpatImpl.h - Expat class container | + // + // This module contains the definition of the expat class container. + // + // Copyright (c) 1994-2002 - Descartes Systems Sciences, Inc. + // + // @end + // + // $History: ExpatImpl.h $ + // + // ***************** Version 1 ***************** + // User: Tim Smith Date: 1/29/02 Time: 1:57p + // Created in $/Omni_V2/_ToolLib + // 1. String.h now replaced with StringCode.h. + // 2. StringRsrc.h modified to use new string class. + // 3. Added tons of new classes from the wedge work. + // + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // + // Required include files + // + //----------------------------------------------------------------------------- + + #include + #include "expat.h" + + //----------------------------------------------------------------------------- + // + // Forward definitions + // + //----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- + // + // Template class definition + // + //----------------------------------------------------------------------------- + + template + class CExpatImpl + { + + // @access Constructors and destructors + public: + + // @cmember General constructor + + CExpatImpl () + { + m_p = NULL; + } + + // @cmember Destructor + + ~CExpatImpl () + { + Destroy (); + } + + // @access Parser creation and deletion methods + public: + + // @cmember Create a parser + + bool Create (const XML_Char *pszEncoding = NULL, + const XML_Char *pszSep = NULL) + { + + // + // Destroy the old parser + // + + Destroy (); + + // + // If the encoding or seperator are empty, then NULL + // + + if (pszEncoding != NULL && pszEncoding [0] == 0) + pszEncoding = NULL; + if (pszSep != NULL && pszSep [0] == 0) + pszSep = NULL; + + // + // Create the new one + // + + m_p = XML_ParserCreate_MM (pszEncoding, NULL, pszSep); + if (m_p == NULL) + return false; + + // + // Invoke the post create routine + // + + _T *pThis = static_cast <_T *> (this); + pThis ->OnPostCreate (); + + // + // Set the user data used in callbacks + // + + XML_SetUserData (m_p, (void *) this); + return true; + } + + // @cmember Destroy the parser + + void Destroy () + { + if (m_p != NULL) + XML_ParserFree (m_p); + m_p = NULL; + } + + // @access Parser parse methods + public: + + // @cmember Parse a block of data + + bool Parse (const char *pszBuffer, int nLength = -1, bool fIsFinal = true) + { + + // + // Validate + // + + assert (m_p != NULL); + + // + // Get the length if not specified + // + + if (nLength < 0) + nLength = strlen (pszBuffer); + + // + // Invoke the parser + // + + return XML_Parse (m_p, pszBuffer, nLength, fIsFinal) != 0; + } + + // @cmember Parse a block of data + + #ifdef WCHAR + bool Parse (const WCHAR *pszBuffer, int nLength = -1, bool fIsFinal = true) + { + + // + // Validate + // + + assert (m_p != NULL); + + // + // Get the length if not specified + // + + if (nLength < 0) + nLength = wcslen (pszBuffer) * 2; + + // + // Invoke the parser + // + + return XML_Parse (m_p, pszBuffer, nLength, fIsFinal) != 0; + } + #endif + + // @cmember Parse internal buffer + + bool ParseBuffer (int nLength, bool fIsFinal = true) + { + assert (m_p != NULL); + return XML_ParseBuffer (m_p, nLength, fIsFinal) != 0; + } + + // @cmember Get the internal buffer + + void *GetBuffer (int nLength) + { + assert (m_p != NULL); + return XML_GetBuffer (m_p, nLength); + } + + // @access Parser callback enable/disable methods + public: + + // @cmember Enable/Disable the start element handler + + void EnableStartElementHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetStartElementHandler (m_p, fEnable ? StartElementHandler : NULL); + } + + // @cmember Enable/Disable the end element handler + + void EnableEndElementHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetEndElementHandler (m_p, fEnable ? EndElementHandler : NULL); + } + + // @cmember Enable/Disable the element handlers + + void EnableElementHandler (bool fEnable = true) + { + assert (m_p != NULL); + EnableStartElementHandler (fEnable); + EnableEndElementHandler (fEnable); + } + + // @cmember Enable/Disable the character data handler + + void EnableCharacterDataHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetCharacterDataHandler (m_p, + fEnable ? CharacterDataHandler : NULL); + } + + // @cmember Enable/Disable the processing instruction handler + + void EnableProcessingInstructionHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetProcessingInstructionHandler (m_p, + fEnable ? ProcessingInstructionHandler : NULL); + } + + // @cmember Enable/Disable the comment handler + + void EnableCommentHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetCommentHandler (m_p, fEnable ? CommentHandler : NULL); + } + + // @cmember Enable/Disable the start CDATA section handler + + void EnableStartCdataSectionHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetStartCdataSectionHandler (m_p, + fEnable ? StartCdataSectionHandler : NULL); + } + + // @cmember Enable/Disable the end CDATA section handler + + void EnableEndCdataSectionHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetEndCdataSectionHandler (m_p, + fEnable ? EndCdataSectionHandler : NULL); + } + + // @cmember Enable/Disable the CDATA section handlers + + void EnableCdataSectionHandler (bool fEnable = true) + { + assert (m_p != NULL); + EnableStartCdataSectionHandler (fEnable); + EnableEndCdataSectionHandler (fEnable); + } + + // @cmember Enable/Disable default handler + + void EnableDefaultHandler (bool fEnable = true, bool fExpand = true) + { + assert (m_p != NULL); + if (fExpand) + { + XML_SetDefaultHandlerExpand (m_p, + fEnable ? DefaultHandler : NULL); + } + else + XML_SetDefaultHandler (m_p, fEnable ? DefaultHandler : NULL); + } + + // @cmember Enable/Disable external entity ref handler + + void EnableExternalEntityRefHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetExternalEntityRefHandler (m_p, + fEnable ? ExternalEntityRefHandler : NULL); + } + + // @cmember Enable/Disable unknown encoding handler + + void EnableUnknownEncodingHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetUnknownEncodingHandler (m_p, + fEnable ? UnknownEncodingHandler : NULL,NULL); + } + + // @cmember Enable/Disable start namespace handler + + void EnableStartNamespaceDeclHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetStartNamespaceDeclHandler (m_p, + fEnable ? StartNamespaceDeclHandler : NULL); + } + + // @cmember Enable/Disable end namespace handler + + void EnableEndNamespaceDeclHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetEndNamespaceDeclHandler (m_p, + fEnable ? EndNamespaceDeclHandler : NULL); + } + + // @cmember Enable/Disable namespace handlers + + void EnableNamespaceDeclHandler (bool fEnable = true) + { + EnableStartNamespaceDeclHandler (fEnable); + EnableEndNamespaceDeclHandler (fEnable); + } + + // @cmember Enable/Disable the XML declaration handler + + void EnableXmlDeclHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetXmlDeclHandler (m_p, fEnable ? XmlDeclHandler : NULL); + } + + // @cmember Enable/Disable the start DOCTYPE declaration handler + + void EnableStartDoctypeDeclHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetStartDoctypeDeclHandler (m_p, + fEnable ? StartDoctypeDeclHandler : NULL); + } + + // @cmember Enable/Disable the end DOCTYPE declaration handler + + void EnableEndDoctypeDeclHandler (bool fEnable = true) + { + assert (m_p != NULL); + XML_SetEndDoctypeDeclHandler (m_p, + fEnable ? EndDoctypeDeclHandler : NULL); + } + + // @cmember Enable/Disable the DOCTYPE declaration handler + + void EnableDoctypeDeclHandler (bool fEnable = true) + { + assert (m_p != NULL); + EnableStartDoctypeDeclHandler (fEnable); + EnableEndDoctypeDeclHandler (fEnable); + } + + // @access Parser error reporting methods + public: + + // @cmember Get last error + + enum XML_Error GetErrorCode () + { + assert (m_p != NULL); + return XML_GetErrorCode (m_p); + } + + // @cmember Get the current byte index + + long GetCurrentByteIndex () + { + assert (m_p != NULL); + return XML_GetCurrentByteIndex (m_p); + } + + // @cmember Get the current line number + + int GetCurrentLineNumber () + { + assert (m_p != NULL); + return XML_GetCurrentLineNumber (m_p); + } + + // @cmember Get the current column number + + int GetCurrentColumnNumber () + { + assert (m_p != NULL); + return XML_GetCurrentColumnNumber (m_p); + } + + // @cmember Get the current byte count + + int GetCurrentByteCount () + { + assert (m_p != NULL); + return XML_GetCurrentByteCount (m_p); + } + + // @cmember Get the input context + + const char *GetInputContext (int *pnOffset, int *pnSize) + { + assert (m_p != NULL); + return XML_GetInputContext (m_p, pnOffset, pnSize); + } + + // @cmember Get last error string + + const XML_LChar *GetErrorString () + { + return XML_ErrorString (GetErrorCode ()); + } + + // @access Parser other methods + public: + + // @cmember Return the version string + + static const XML_LChar *GetExpatVersion () + { + return XML_ExpatVersion (); + } + + // @cmember Get the version information + + static void GetExpatVersion (int *pnMajor, int *pnMinor, int *pnMicro) + { + XML_Expat_Version v = XML_ExpatVersionInfo (); + if (pnMajor) + *pnMajor = v .major; + if (pnMinor) + *pnMinor = v .minor; + if (pnMicro) + *pnMicro = v .micro; + } + + // @cmember Get last error string + + static const XML_LChar *GetErrorString (enum XML_Error nError) + { + return XML_ErrorString (nError); + } + + // @access Public handler methods + public: + + // @cmember Start element handler + + void OnStartElement (const XML_Char *pszName, const XML_Char **papszAttrs) + { + return; + } + + // @cmember End element handler + + void OnEndElement (const XML_Char *pszName) + { + return; + } + + // @cmember Character data handler + + void OnCharacterData (const XML_Char *pszData, int nLength) + { + return; + } + + // @cmember Processing instruction handler + + void OnProcessingInstruction (const XML_Char *pszTarget, + const XML_Char *pszData) + { + return; + } + + // @cmember Comment handler + + void OnComment (const XML_Char *pszData) + { + return; + } + + // @cmember Start CDATA section handler + + void OnStartCdataSection () + { + return; + } + + // @cmember End CDATA section handler + + void OnEndCdataSection () + { + return; + } + + // @cmember Default handler + + void OnDefault (const XML_Char *pszData, int nLength) + { + return; + } + + // @cmember External entity ref handler + + bool OnExternalEntityRef (const XML_Char *pszContext, + const XML_Char *pszBase, const XML_Char *pszSystemID, + const XML_Char *pszPublicID) + { + return false; + } + + // @cmember Unknown encoding handler + + bool OnUnknownEncoding (const XML_Char *pszName, XML_Encoding *pInfo) + { + return false; + } + + // @cmember Start namespace declaration handler + + void OnStartNamespaceDecl (const XML_Char *pszPrefix, + const XML_Char *pszURI) + { + return; + } + + // @cmember End namespace declaration handler + + void OnEndNamespaceDecl (const XML_Char *pszPrefix) + { + return; + } + + // @cmember XML declaration handler + + void OnXmlDecl (const XML_Char *pszVersion, const XML_Char *pszEncoding, + bool fStandalone) + { + return; + } + + // @cmember Start DOCTYPE declaration handler + + void OnStartDoctypeDecl (const XML_Char *pszDoctypeName, + const XML_Char *pszSysID, const XML_Char *pszPubID, + bool fHasInternalSubset) + { + return; + } + + // @cmember End DOCTYPE declaration handler + + void OnEndDoctypeDecl () + { + return; + } + + // @access Protected methods + protected: + + // @cmember Handle any post creation + + void OnPostCreate () + { + } + + // @access Protected static methods + protected: + + // @cmember Start element handler wrapper + + static void __cdecl StartElementHandler (void *pUserData, + const XML_Char *pszName, const XML_Char **papszAttrs) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnStartElement (pszName, papszAttrs); + } + + // @cmember End element handler wrapper + + static void __cdecl EndElementHandler (void *pUserData, + const XML_Char *pszName) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnEndElement (pszName); + } + + // @cmember Character data handler wrapper + + static void __cdecl CharacterDataHandler (void *pUserData, + const XML_Char *pszData, int nLength) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnCharacterData (pszData, nLength); + } + + // @cmember Processing instruction handler wrapper + + static void __cdecl ProcessingInstructionHandler (void *pUserData, + const XML_Char *pszTarget, const XML_Char *pszData) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnProcessingInstruction (pszTarget, pszData); + } + + // @cmember Comment handler wrapper + + static void __cdecl CommentHandler (void *pUserData, + const XML_Char *pszData) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnComment (pszData); + } + + // @cmember Start CDATA section wrapper + + static void __cdecl StartCdataSectionHandler (void *pUserData) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnStartCdataSection (); + } + + // @cmember End CDATA section wrapper + + static void __cdecl EndCdataSectionHandler (void *pUserData) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnEndCdataSection (); + } + + // @cmember Default wrapper + + static void __cdecl DefaultHandler (void *pUserData, + const XML_Char *pszData, int nLength) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnDefault (pszData, nLength); + } + + // @cmember External entity ref wrapper + + static int __cdecl ExternalEntityRefHandler (void *pUserData, + const XML_Char *pszContext, const XML_Char *pszBase, + const XML_Char *pszSystemID, const XML_Char *pszPublicID) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + return pThis ->OnExternalEntityRef (pszContext, + pszBase, pszSystemID, pszPublicID) ? 1 : 0; + } + + // @cmember Unknown encoding wrapper + + static int __cdecl UnknownEncodingHandler (void *pUserData, + const XML_Char *pszName, XML_Encoding *pInfo) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + return pThis ->OnUnknownEncoding (pszName, pInfo) ? 1 : 0; + } + + // @cmember Start namespace decl wrapper + + static void __cdecl StartNamespaceDeclHandler (void *pUserData, + const XML_Char *pszPrefix, const XML_Char *pszURI) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnStartNamespaceDecl (pszPrefix, pszURI); + } + + // @cmember End namespace decl wrapper + + static void __cdecl EndNamespaceDeclHandler (void *pUserData, + const XML_Char *pszPrefix) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnEndNamespaceDecl (pszPrefix); + } + + // @cmember XML declaration wrapper + + static void __cdecl XmlDeclHandler (void *pUserData, + const XML_Char *pszVersion, const XML_Char *pszEncoding, + int nStandalone) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnXmlDecl (pszVersion, pszEncoding, nStandalone != 0); + } + + // @cmember Start Doctype declaration wrapper + + static void __cdecl StartDoctypeDeclHandler (void *pUserData, + const XML_Char *pszDoctypeName, const XML_Char *pszSysID, + const XML_Char *pszPubID, int nHasInternalSubset) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnStartDoctypeDecl (pszDoctypeName, pszSysID, + pszPubID, nHasInternalSubset != 0); + } + + // @cmember End Doctype declaration wrapper + + static void __cdecl EndDoctypeDeclHandler (void *pUserData) + { + _T *pThis = static_cast <_T *> ((CExpatImpl <_T> *) pUserData); + pThis ->OnEndDoctypeDecl (); + } + + // @access Protected members + protected: + + XML_Parser m_p; + }; + + //----------------------------------------------------------------------------- + // + // Virtual method class definition + // + //----------------------------------------------------------------------------- + + class CExpat : public CExpatImpl + { + // @access Constructors and destructors + public: + + CExpat () + { + } + + // @access Public handler methods + public: + + // @cmember Start element handler + + virtual void OnStartElement (const XML_Char *pszName, + const XML_Char **papszAttrs) + { + return; + } + + // @cmember End element handler + + virtual void OnEndElement (const XML_Char *pszName) + { + return; + } + + // @cmember Character data handler + + virtual void OnCharacterData (const XML_Char *pszData, int nLength) + { + return; + } + + // @cmember Processing instruction handler + + virtual void OnProcessingInstruction (const XML_Char *pszTarget, + const XML_Char *pszData) + { + return; + } + + // @cmember Comment handler + + virtual void OnComment (const XML_Char *pszData) + { + return; + } + + // @cmember Start CDATA section handler + + virtual void OnStartCdataSection () + { + return; + } + + // @cmember End CDATA section handler + + virtual void OnEndCdataSection () + { + return; + } + + // @cmember Default handler + + virtual void OnDefault (const XML_Char *pszData, int nLength) + { + return; + } + + // @cmember External entity ref handler + + virtual bool OnExternalEntityRef (const XML_Char *pszContext, + const XML_Char *pszBase, const XML_Char *pszSystemID, + const XML_Char *pszPublicID) + { + return false; + } + + // @cmember Unknown encoding handler + + virtual bool OnUnknownEncoding (const XML_Char *pszName, XML_Encoding *pInfo) + { + return false; + } + + // @cmember Start namespace declaration handler + + virtual void OnStartNamespaceDecl (const XML_Char *pszPrefix, + const XML_Char *pszURI) + { + return; + } + + // @cmember End namespace declaration handler + + virtual void OnEndNamespaceDecl (const XML_Char *pszPrefix) + { + return; + } + + // @cmember XML declaration handler + + virtual void OnXmlDecl (const XML_Char *pszVersion, + const XML_Char *pszEncoding, bool fStandalone) + { + return; + } + + // @cmember Start DOCTYPE declaration handler + + virtual void OnStartDoctypeDecl (const XML_Char *pszDoctypeName, + const XML_Char *pszSysID, const XML_Char *pszPubID, + bool fHasInternalSubset) + { + return; + } + + // @cmember End DOCTYPE declaration handler + + virtual void OnEndDoctypeDecl () + { + return; + } + }; + +#endif // DSSI_EXPATIMPL_H diff --git a/cstav1/CMakeLists.txt b/cstav1/CMakeLists.txt new file mode 100644 index 0000000..da25dc7 --- /dev/null +++ b/cstav1/CMakeLists.txt @@ -0,0 +1,541 @@ +PROJECT(cstav1-lib) + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${rules_SOURCE_DIR}/") + +FIND_PACKAGE(PCAP REQUIRED) +INCLUDE_DIRECTORIES(${PCAP_INCLUDE_DIRS}) + +IF (WITH_CSTAV1) +#for mingw32 +INCLUDE_DIRECTORIES(/include) +INCLUDE_DIRECTORIES(${MAKE_CURRENT_BINARY_DIR}) +IF(NOT WIN32) +FIND_PACKAGE(EXPAT REQUIRED ) +ENDIF(NOT WIN32) + +ADD_DEFINITIONS(-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER) +SET(CSTAV1_ERULE "-e ber") +SET(CSTAV1_MODEL ${asn1-data-models_SOURCE_DIR}/cstav1/ CACHE STRING "CSTA V1 datamodel source directory") +FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt CSTAV1MODULES) + +FOREACH(ITEM ${CSTAV1MODULES}) + STRING(REGEX REPLACE "-" "_" HITEM ${ITEM}) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h GENERATED) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp GENERATED) + SET(CSTAV1SRC ${CSTAV1SRC} ${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp) + SET(CSTAV1HDR ${CSTAV1HDR} ${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h) +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp" + ) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h" + ) + +ENDFOREACH(ITEM) + + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Generic_ROS_PDUs.h + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Generic-ROS-PDUs.cpp + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} + -f Remote-Operations-Information-Objects.asn1 + -f Remote-Operations-Generic-ROS-PDUs.asn1 + -oRemote-Operations-Generic-ROS-PDUs + DEPENDS ${asn1p_EXE} + COMMENT "Build ROGR .h and .cpp" + ) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Generic_ROS_PDUs.h + GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Generic-ROS-PDUs.cpp + GENERATED) +# +# +# +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} + -f Remote-Operations-Information-Objects.asn1 + -oRemote-Operations-Information-Objects + DEPENDS ${asn1p_EXE} + COMMENT "Build ROIO .h and .cpp" + ) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + GENERATED) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-event.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_event.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} + -f Remote-Operations-Information-Objects.asn1 + -f apdu_rose_94.asn1 + -f evt_definition_94.asn1 + -f err_error.asn1 + -f obj_extension_94.asn1 + -f obj_private_94.asn1 + -f obj_feature.asn1 -f obj_status.asn1 + -f obj_device.asn1 -f obj_call.asn1 + -f obj_connection.asn1 -f obj_switch.asn1 -oCSTA-event + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_extend.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_status.h + COMMENT "Build CSTA-event .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Model.uml + COMMAND cat + ${asn1-data-models_SOURCE_DIR}/cstav1/apdu_rose_94.asn1 + ${asn1-data-models_SOURCE_DIR}/cstav1/evt_definition_94.asn1 + ${asn1-data-models_SOURCE_DIR}/cstav1/obj_connection.asn1 + ${asn1-data-models_SOURCE_DIR}/cstav1/obj_call.asn1 + ${asn1-data-models_SOURCE_DIR}/cstav1/obj_feature.asn1 + ${asn1-data-models_SOURCE_DIR}/cstav1/obj_status.asn1 + ${asn1-data-models_SOURCE_DIR}/cstav1/err_error.asn1 + ARGS | ${asn1p_EXE} -u CstaV1Events.uml + COMMAND ${CMAKE_COMMAND} -E rename _model.uml Model.uml + DEPENDS ${asn1p_EXE} + COMMENT "Build UML cstav1 Events for UML" + ) + +#ADD_CUSTOM_TARGET(Model.uml ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_model.uml) +#SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_CLEAN Model.uml) +#SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_CLEAN _model.uml) + + + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-connect.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_connect.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} + -f obj_device.asn1 + -f obj_call.asn1 + -f obj_connection.asn1 + -f obj_switch.asn1 + -oCSTA-connect + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build CSTA-connect.h and .cpp" + ) + + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-status.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_status.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} -f obj_status.asn1 -f obj_device.asn1 + -f obj_call.asn1 -f obj_connection.asn1 -f obj_switch.asn1 + -oCSTA-status + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build CSTA-status.h and .cpp" + ) + + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-feature.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_feature.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} -f obj_device.asn1 -f obj_feature.asn1 + -f obj_call.asn1 -oCSTA-feature + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build CSTA-feature.h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-private.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_private.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} -f obj_device.asn1 + -f obj_feature.asn1 + -f obj_switch.asn1 + -f obj_call.asn1 + -f obj_extension_94.asn1 + -f err_error.asn1 + -f Remote-Operations-Information-Objects.asn1 + -f obj_private_94.asn1 -oCSTA-private + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build CSTA-private.h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-call.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_call.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} ${CSTAV1_ERULE} -f obj_device.asn1 -f obj_status.asn1 -f obj_call.asn1 -oCSTA-call + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-event.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_status.h + COMMENT "Build CSTA-call .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-device.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_device.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} -f obj_device.asn1 -f obj_status.asn1 -f obj_extension_94.asn1 -oCSTA-device + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build CSTA-device .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-extend.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_extend.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} + -f obj_extension_94.asn1 + -f obj_security.asn1 -f Remote-Operations-Information-Objects.asn1 + -oCSTA-extend + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/ACSE_1.h + COMMENT "Build CSTA-extend .h and .cpp ${asn1-data-models_SOURCE_DIR}/cstav1" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Rose-Apdu.cpp + ${CMAKE_CURRENT_BINARY_DIR}/Rose_Apdu.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} -fapdu_rose_94.asn1 + -fobj_call.asn1 + -fobj_status.asn1 + -fobj_switch.asn1 + -fobj_connection.asn1 -fobj_device.asn1 -fobj_feature.asn1 + -ferr_error.asn1 -fevt_definition_94.asn1 + -f obj_extension_94.asn1 -f obj_security.asn1 + -f Remote-Operations-Information-Objects.asn1 + -oRose-Apdu + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/ACSE_1.h + COMMENT "Build Rose-Apdu .h and .cpp" + ) + + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-switch.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_switch.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} + -fobj_call.asn1 + -fobj_device.asn1 + -ferr_error.asn1 + -f obj_switch.asn1 + -f Remote-Operations-Information-Objects.asn1 + -oCSTA-switch + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build cstav1 CSTA-switch.h and CSTA-switch.cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-secure.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_secure.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} + -fobj_security.asn1 + -oCSTA-secure + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build CSTA-secure .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-error.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_error.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} + -f Remote-Operations-Information-Objects.asn1 + -ferr_error.asn1 + -oCSTA-error + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build CSTA-error .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/ACSE-1.cpp + ${CMAKE_CURRENT_BINARY_DIR}/ACSE_1.h + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} + -fapdu_acse.asn1 + -f Remote-Operations-Information-Objects.asn1 + -oACSE-1 + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + COMMENT "Build ACSE-1 .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/CSTA-MSG.cpp + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_MSG.h + + COMMAND ${asn1p_EXE} + ARGS -I ${CSTAV1_MODEL} -f apdu_csta.asn1 -f apdu_acse.asn1 -f + apdu_rose_94.asn1 -oCSTA-MSG + DEPENDS ${asn1p_EXE} + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/ACSE_1.h + COMMENT "Build CSTA-MSG .h and .cpp" + ) + + +ADD_LIBRARY(cstav1 + ${CSTAV1SRC} + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + ) + +ADD_EXECUTABLE(test_cstav1 + main.cpp + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + ) +TARGET_LINK_LIBRARIES(test_cstav1 cstav1 asn1) + +IF (NOT CMAKE_CROSSCOMPILING) + IF(NOT WIN32) + FIND_PACKAGE(FLTK REQUIRED + NAME FLTK) + IF(FLTK_BUILT_WITH_CMAKE) + INCLUDE_DIRECTORIES(${FLTK_INCLUDE_DIR}/../include) + ELSE(FLTK_BUILT_WITH_CMAKE) + INCLUDE_DIRECTORIES(${FLTK_INCLUDE_DIR}) + ENDIF(FLTK_BUILT_WITH_CMAKE) + + FIND_PACKAGE(OpenGL REQUIRED) + ELSE(NOT WIN32) + INCLUDE_DIRECTORIES(${FLTK_INCLUDE_DIR}) + ENDIF(NOT WIN32) +FLTK_WRAP_UI(Ui cstaspyui.fl) + +ADD_LIBRARY(Ui + SequenceView.cpp + HeaderView.cpp + Model.cpp + Controler.cpp + ${Ui_FLTK_UI_SRCS} + Pcap.cpp + Packet.cpp + Timeline.cpp + TLMsg.cpp + IconFactory.cpp + CstaInsightLog.cpp + ) +ADD_DEPENDENCIES(Ui cstav1) + +ADD_EXECUTABLE(csta_insight + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + ) + +ADD_DEPENDENCIES(csta_insight Ui) +ADD_DEPENDENCIES(csta_insight cstav1) +IF(APPLE) +TARGET_LINK_LIBRARIES(csta_insight Ui) +TARGET_LINK_LIBRARIES(csta_insight ${EXPAT_LIB}) +SET_TARGET_PROPERTIES(csta_insight PROPERTIES LINKER_FLAGS "-framework Cocoa") +#Missing and don't know why +MESSAGE(" FLTK_INCLUDE_DIR = ${FLTK_INCLUDE_DIR}") +SET(FLTK_PNG_LIB /Users/aeb/Externals/MacOSX.10.11/fltk-1.3/lib/libfltk_png.a) +#TARGET_LINK_LIBRARIES(csta_insight /usr/local/lib/libfltk_png.a) +TARGET_LINK_LIBRARIES(csta_insight ${FLTK_PNG_LIB}) +ENDIF(APPLE) + +IF(UNIX AND NOT APPLE) +# Find libdl for fltk on Ubuntu dlsym +FIND_LIBRARY(DL_LIBRARY NAMES dl libdl) +MESSAGE("Looking for DL library") +TARGET_LINK_LIBRARIES(csta_insight ${DL_LIBRARY}) +MESSAGE("Have for DL library ${DL_LIBRARY}") +TARGET_LINK_LIBRARIES(csta_insight Ui X11 Xft Xinerama fltk_images ${EXPAT_LIB}) +ENDIF() + +IF(WIN32) +MESSAGE("WIN32 SETTINGS ") + TARGET_LINK_LIBRARIES(csta_insight Ui ws2_32) + TARGET_LINK_LIBRARIES(csta_insight ${EXPAT_LIBRARY}) + TARGET_LINK_LIBRARIES(csta_insight ${FLTK_LIBRARIES}) +ELSEIF(MINGW) + MESSAGE("MINGW SETTINGS ") +TARGET_LINK_LIBRARIES(Ui C:/MinGW/msys/1.0/opt/lib/libfltk_png.a) +TARGET_LINK_LIBRARIES(Ui C:/MinGW/msys/1.0/opt/lib/libfltk_z.a) +TARGET_LINK_LIBRARIES(csta_insight C:/MinGW/msys/1.0/opt/lib/libfltk_png.a) +TARGET_LINK_LIBRARIES(csta_insight Ui ws2_32) +TARGET_LINK_LIBRARIES(csta_insight ${EXPAT_LIBRARY}) +#Missing and don't know why +ENDIF(WIN32) + +TARGET_LINK_LIBRARIES(csta_insight ${FLTK_LIBRARIES}) +TARGET_LINK_LIBRARIES(csta_insight cstav1) +TARGET_LINK_LIBRARIES(csta_insight asn1) +TARGET_LINK_LIBRARIES(csta_insight ${PCAP_LIBRARIES}) + +ENDIF(NOT CMAKE_CROSSCOMPILING) + +# +# Install stuff +# + +IF (NOT CMAKE_CROSSCOMPILING) +INSTALL(TARGETS csta_insight DESTINATION bin + COMPONENT Csta + ) + +FILE(GLOB CSTA_IMAGES ${CMAKE_CURRENT_SOURCE_DIR}/images/*.png) +INSTALL(FILES ${CSTA_IMAGES} DESTINATION share/csta_insight/images + COMPONENT Csta) +ENDIF(NOT CMAKE_CROSSCOMPILING) + +INSTALL(FILES + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_feature.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_private.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_secure.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_status.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_switch.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_device.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_error.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_event.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_extend.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_private.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_connect.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_call.h + ${CMAKE_CURRENT_BINARY_DIR}/CSTA_MSG.h + ${CMAKE_CURRENT_BINARY_DIR}/ACSE_1.h + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/Rose_Apdu.h + DESTINATION include/CSTA/ + COMPONENT Csta-Header) + +FILE(GLOB CSTA_ACSE ${CMAKE_CURRENT_BINARY_DIR}/include/ACSE_1/*.h) +INSTALL(FILES ${CSTA_ACSE} DESTINATION include/CSTA/ACSE_1 + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_MSG ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_MSG/*.h) +INSTALL(FILES ${CSTA_MSG} DESTINATION include/CSTA/CSTA_MSG + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_CONNECT ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_connect/*.h) +INSTALL(FILES ${CSTA_CONNECT} DESTINATION include/CSTA/CSTA_connect + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_EVENT ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_event/*.h) +INSTALL(FILES ${CSTA_EVENT} DESTINATION include/CSTA/CSTA_event + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_ERROR ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_error/*.h) +INSTALL(FILES ${CSTA_ERROR} DESTINATION include/CSTA/CSTA_error + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_EXTEND ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_extend/*.h) +INSTALL(FILES ${CSTA_EXTEND} DESTINATION include/CSTA/CSTA_extend + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_FEATURE ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_feature/*.h) +INSTALL(FILES ${CSTA_FEATURE} DESTINATION include/CSTA/CSTA_feature + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_private/*.h) +INSTALL(FILES ${CSTA_PRIVATE} DESTINATION include/CSTA/CSTA_private + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_SECURE ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_secure/*.h) +INSTALL(FILES ${CSTA_SECURE} DESTINATION include/CSTA/CSTA_secure + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_STATUS ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_status/*.h) +INSTALL(FILES ${CSTA_STATUS} DESTINATION include/CSTA/CSTA_status + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_SWITCH ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_switch/*.h) +INSTALL(FILES ${CSTA_SWITCH} DESTINATION include/CSTA/CSTA_switch + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_CALL ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_call/*.h) +INSTALL(FILES ${CSTA_CALL} DESTINATION include/CSTA/CSTA_call + COMPONENT Csta-Headers) + +FILE(GLOB CSTA_DEVICE ${CMAKE_CURRENT_BINARY_DIR}/include/CSTA_device/*.h) +INSTALL(FILES ${CSTA_DEVICE} DESTINATION include/CSTA/CSTA_device + COMPONENT Csta-Headers) + +INSTALL(TARGETS cstav1 + DESTINATION lib + COMPONENT Csta-Lib + ) + +# +# Ok start working with Packaging stuff +# +INCLUDE(InstallRequiredSystemLibraries) +#SET(CPACK_OUTPUT_CONFIG_FILE "${PROJECT_BINARY_DIR}/CPackConfig.cmake" ) +#SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Graphical user interface to visualize csta messages from pcap files") +#SET(CPACK_PACKAGE_VENDOR "Aeb") +#SET(CPACK_PACKAGE_DESCRIPTION_FILE "") +#SET(CPACK_RESOURCE_FILE_LICENSE "") +#SET(CPACK_PACKAGE_VERSION_MAJOR "1") +#SET(CPACK_PACKAGE_VERSION_MINOR "0") +#SET(CPACK_PACKAGE_VERSION_PATCH "0") + +#SET(CPACK_PACKAGE_FILE_NAME "CstaSpyInstaller") +#SET(CPACK_PACKAGE_NAME "CstaSpy") + +IF(WIN32) + SET(CPACK_GENERATOR "NSIS") +ENDIF() + +# IF(UNIX) +IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) + SET(CPACK_INSTALL_CMAKE_PROJECTS "${PROJECT_BINARY_DIR};cstav1-lib;ALL;/") + SET(CPACK_RPM_COMPONENT_INSTALL ON) + SET(CPACK_PACKAGE_FILE_NAME "CstaSpyInstaller") + set(CPACK_COMPONENTS_ALL Csta-Headers Csta-Lib Csta) + SET(CPACK_COMPONENTS_IGNORE_GROUPS 1) + SET(CPACK_COMPONENTS_GROUPING "IGNORE") + SET(CPACK_GENERATOR "RPM") +ENDIF() +IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" ) + SET(CPACK_GENERATOR "Bundel") +ENDIF() +#SET(CPACK_PACKAGE_EXECUTABLES "cstaspy") +SET(CPACK_PACKAGE_EXECUTABLES "cstaInsight" "CSTA Insight") +INCLUDE(CPack) + +ENDIF (WITH_CSTAV1) diff --git a/cstav1/Call.h b/cstav1/Call.h new file mode 100644 index 0000000..355eb4c --- /dev/null +++ b/cstav1/Call.h @@ -0,0 +1,29 @@ +#ifndef __CALL_H__ + +/** + * + */ +class Call { + public: + enum Type + { + UNKNOWN, + CSTA, + SIP + }; + + Call(std::string id, Type t = UNKNOWN) : m_Type(t), m_Id(id) {}; + Call(const Call &c) : m_Type(c.Type), m_Id(c.m_Id) {}; + virtual ~Call() {} ; + + // set get + Type get_Type() const; + void set_Type(Type t) {m_Type = t;}; + + std::string get_CallId() const; + void set_CallId(std::string &s) {m_Id = s;}; + protected: + Type m_Type; + std::string m_Id; // Call Identifier, can be string for tags, and an integer or OCTET STRING for CSTA +}; +#endif diff --git a/cstav1/Controler.cpp b/cstav1/Controler.cpp new file mode 100644 index 0000000..a95b699 --- /dev/null +++ b/cstav1/Controler.cpp @@ -0,0 +1,1127 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Pcap.h" +#if defined(__WIN32__) || defined(_WINDOWS) +#else +#include +#include +#endif +#include +#include "TLMsg.h" + +#include "Model.h" +#include +#include +#include + +//Asn1 +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +// CSTA Stubs +#include "Rose_Apdu.h" +#include "CSTA_event.h" +#include "ACSE_1.h" +#include "CSTA_MSG.h" + +#include "Controler.h" + + +#include "Rose_Apdu.hpp" +#include "CSTA_event.hpp" + +Controler::Controler(Model *m) + : m_Model(m), + m_SequenceUi(NULL), + m_HeaderUi(NULL) +{ + m_Events[2] = std::string("conferenced"); + m_Events[3] = std::string("connectionCleared"); + m_Events[4] = std::string("delivered"); + m_Events[5] = std::string("diverted"); + m_Events[6] = std::string("established"); + m_Events[7] = std::string("failed"); + m_Events[8] = std::string("held"); + m_Events[9] = std::string("networkReached"); + m_Events[10] = std::string("originated"); + m_Events[11] = std::string("queued"); + m_Events[12] = std::string("retrieved"); + m_Events[13] = std::string("serviceInitiated"); + m_Events[14] = std::string("transfered"); + m_Events[101] = std::string("callInformation"); + m_Events[102] = std::string("doNotDisturb"); + m_Events[103] = std::string("forwarding"); + m_Events[104] = std::string("messageWaiting"); + m_Events[174] = std::string("maintenance"); + m_Events[401] = std::string("privateEvent"); + m_Events[301] = std::string("backInService"); + m_Events[302] = std::string("outOfService"); + + m_Ops[10] = std::string("makeCall"); + m_Ops[12] = std::string("queryDevice"); + m_Ops[13] = std::string("reconnectCall"); + m_Ops[14] = std::string("retrieveCall"); + m_Ops[15] = std::string("setFeature"); + m_Ops[16] = std::string("tranferCall"); + m_Ops[2] = std::string("answerCall"); + m_Ops[5] = std::string("clearConnection"); + m_Ops[7] = std::string("consultationCall"); + m_Ops[8] = std::string("divertCall"); + m_Ops[9] = std::string("holdCall"); + m_Ops[51] = std::string("escapeService"); + m_Ops[71] = std::string("monitorStart"); + m_Ops[52] = std::string("systemStatus"); + m_Ops[74] = std::string("snapshotDevice"); + m_Ops[101] = std::string("101"); + m_Ops[107] = std::string("107xxx"); + m_Ops[235] = std::string("changeConnectionInformation"); + +} + +Controler::~Controler() +{ +} + +void +Controler::load(const char *filename,const char *expression) +{ + std::string fn(filename); + Pcap cap(fn); + Packet packet; + + if (expression != NULL) + { + cap.set_filter(expression); + } + // In case the stack is not empty + m_SizeStack = std::deque(); + + + while (cap.next(packet) == true) + { + long plength= 0; + const struct sniff_tcp *tcp = packet.get_tcp(); + const struct sniff_udp *udp = packet.get_udp(); + unsigned short sport = 0,dport=0; + + const unsigned char *data =packet.get_payload(plength); + if (tcp) + { + sport = htons(tcp->th_sport); + dport = htons(tcp->th_dport); + CI_LOG_DEBUG("%lu.%lu Controler::load TCP sport=%d dport=%d payload len=%ld", + packet.get_seconds() + ,packet.get_miliseconds() + ,sport + ,dport + ,plength + ); + } else if (udp) { + sport = htons(udp->sport); + dport = htons(udp->dport); + CI_LOG_DEBUG("%lu.%lu Controler::load UDP sport=%d dport=%d payload len=%ld", + packet.get_seconds() + ,packet.get_miliseconds() + ,sport + ,dport + ,plength + ); + } + + if (plength > 0) + { + char *ld = (char *)data; + std::stringstream ss; + ss.rdbuf()->sputn(ld,plength); + + if ((sport == 2555) ||( dport == 2555 )) { + parse_csta(packet,ss,plength); + } else if ((sport ==5059) || (dport == 5059) || (dport == 5060) || (sport == 5060)) { + //SIP Packet + parse_sip(packet,ss); + } else if ( (sport == 8894) || (dport == 8894) || (dport == 56000) || (sport == 56000) ) + { + // OTS message I think mainly soap + if (plength > 6) + parse_ots(packet,ss); + } +#if 0 + if (m_DumpHex->value() ) + for (int i = 0 ; i < plength ; i++) + { + printf("%02x ",data[i]); + } +#endif + //std::cout<<"\n"; + } + + } + if (m_Model) + { + std::cout<<"Controler::load tl_count="<tl_count()<clean(); + ; +} + + +void +Controler::onSelectTree() +{; +} +void Controler::onSelectSequence() +{ + ; +} + + +void +Controler::parse_sip(const Packet &packet,std::stringstream &is) +{; + const struct sniff_udp *udp = packet.get_udp(); + const struct sniff_tcp *tcp = packet.get_tcp(); + const struct sniff_ip *ip = packet.get_ip(); + unsigned short sport,dport; + bool is_notify = false; + bool is_xml = false; + int length = 0; + size_t found = 0; + char buf[64]; + memset(buf,0x00,64); + CI_LOG_DEBUG("Controler::parse_sip PROCESS size=%ld", + is.str().size()); + std::stringstream ss; + std::string fline,line; + ss.str(""); + // get first line + std::getline(is,fline,'\r'); + is.seekg(0); + std::replace(fline.begin(),fline.end(),'/','.'); + + if (fline.find("NOTIFY") != std::string::npos) + is_notify = true; + + if (udp) { + sport = htons(udp->sport); + dport = htons(udp->dport); + } else if (tcp) + { + sport = htons(tcp->th_sport); + dport = htons(tcp->th_dport); + + } else { + CI_LOG_WARN("Controler::parse_sip HOHO SIP nor UDP neither TCP"); + } + + ss<<" "<ip_dst,""); + Timeline tls(ip->ip_src,""); + CI_LOG_DEBUG("Controler::parse_sip PROCESS create TLMsg=%s size=%ld" + , fline.c_str() + , fline.size()); + if (fline.size() < 7) + { + fline.assign("sip wierd "); + } + TLMsg *msg = new TLMsg(packet,fline); + msg->msg_type(TLMsg::SIP); + ss.str(""); + ss<m_content = ss.str(); + if (m_Model) + { + + m_Model->add_TLMsg(msg,tls,tld); + } +#if 0 + + // Add packet in sequence + + // Ok parser data and check if it's a XML message + while (! std::getline(is,line,'\n').eof() ) + { + std::replace(line.begin(),line.end(),'\r','\n'); + + if ( (found =line.find("Content-Length:")) != std::string::npos) + { + std::cout<<"Found Length : "<insert(ss.str().c_str()); + } +#endif +} +void +Controler::parse_ots(const Packet &packet,std::stringstream &is) +{ + const struct sniff_tcp *tcp = packet.get_tcp(); + const struct sniff_ip *ip = packet.get_ip(); + unsigned short sport,dport; + + char buf[64]; + memset(buf,0x00,64); + + std::stringstream ss; + + sport = htons(tcp->th_sport); + dport = htons(tcp->th_dport); + + ss.str(""); + strcpy(buf,inet_ntoa(ip->ip_src)); + + + //Fl_Tree_Item *item = tree->add("/XML"); + + + Timeline tld(ip->ip_dst,""); + Timeline tls(ip->ip_src,""); + TLMsg *msg = new TLMsg(packet,"XML "); + ss.str(""); + CI_LOG_DEBUG("Controler::parse_ots"); + ss<msg_type(TLMsg::SOAP_RESPONSE); + msg->m_content = ss.str(); + //XMLMessage msg(tree,item); + //msg.Create(); + std::string line; + size_t found; + int length = 0; + while (! std::getline(is,line,'\n').eof() ) + { + std::replace(line.begin(),line.end(),'\r','\n'); + + if ( (found =line.find("Content-Length:")) != std::string::npos) + { + CI_LOG_DEBUG("Controler::parse_ots Found Length : %s",line.c_str()); + found = line.find(":"); + // Found length extract + length =atoi(line.substr(found+1).c_str()); + } + if ( (found =line.find("SOAPAction:")) != std::string::npos) + { + CI_LOG_DEBUG("Controler::parse_ots Found Action : %s",line.c_str()); + found = line.find(":"); + // Found length extract + std::string soapaction(line.substr(found+1)); + std::replace(soapaction.begin(),soapaction.end(),'\r',' '); + std::replace(soapaction.begin(),soapaction.end(),'\n',' '); + std::replace(soapaction.begin(),soapaction.end(),'\"',' '); + msg->msg_type(TLMsg::SOAP_REQUEST); + msg->name.append(soapaction.c_str()); + } + if ( line.size()==1) { + //time to break; + break; + } + // Chunk XML + if (line.find("msg_type(TLMsg::ICS_EVENT); + + long toparse = is.str().size() -pos; + //is.read((char *)p,is.str().size()-pos); + CI_LOG_DEBUG("Controler::parse_ots Read Buffer to be parsed chunk len=%ld" + , is.str().size()); + //msg.ParseBuffer(is.str().size()-pos); +#if 0 + long index = msg.GetCurrentByteIndex(); + if (index < toparse) + { + std::string notparsed((const char *)p+index,toparse-index); + + m_Editor->insert("\nUNPARSED DATA\n"); + m_Editor->insert(notparsed.c_str()); + } +#endif + } + + } + //m_Editor->insert("\n"); + if (length) + { + CI_LOG_DEBUG("Controler::parser_ots : OK got length=%ld",length); + CI_LOG_DEBUG("Controler::parser_ots : Read buffer to be parsed len=%ld" + , length); + + } else + { + CI_LOG_WARN("Controler::parse_ots: BAD len=0 true for chunk"); + } + if (m_Model) + { + m_Model->add_TLMsg(msg,tls,tld); + } + ; +} + + +void +Controler::parse_csta(const Packet &packet,std::stringstream &is,long read_len) +{ + int len = 0; + const struct sniff_tcp *tcp = packet.get_tcp(); + const struct sniff_ip *ip = packet.get_ip(); + unsigned short sport,dport; + char buf[64]; + memset(buf,0x00,64); + + sport = htons(tcp->th_sport); + dport = htons(tcp->th_dport); + strcpy(buf,inet_ntoa(ip->ip_src)); + + + unsigned char bl[3]; + + + while ( !is.eof() /*is.good()*/) + { + unsigned int low = 0,high = 0; + int at = is.tellg(); + memset(bl,0x00,3); + is.read((char *)bl,2); + low = bl[0]; + high = bl[1]; + len = (unsigned short )bl[1] | ((unsigned short)bl[0] << 8); + CI_LOG_DEBUG("\n\n * HEADER b[0]=%u %u LEN=%ld at=%x", + low + ,high + ,len + ,at); + if ( (( (bl[0] & 0xf8) == 0xa0) || ((bl[0] & 0xf8 ) == 0x60 )) && !m_SizeStack.empty() ) + { // Probably a packet + CI_LOG_DEBUG(" * HEADER pop length current=%ld new of m_SizeStack.front=%d or m_SizeStack.back=%d" + , len + , m_SizeStack.front() + , m_SizeStack.back()); + len = m_SizeStack.back(); + m_SizeStack.pop_back(); + is.seekg(at); // Go back to initial position + } else { + // Prob next value if its a packet or another length + unsigned char c; + if (is.eof() || (at == -1)) + { + CI_LOG_DEBUG(" * Probabl nothing todo at == -1 or eof"); + // On windows when at == -1 is.eof is not set + if (at == -1) + break; + } else { + c = is.get(); + is.putback(c); + if ( ! ( ( (c & 0xf8) == 0xa0) || ((c & 0xf8) == 0x60 ))) + { // Next Is not a packet stack the length and restart reading + CI_LOG_DEBUG("\n * Push and read next c=%0x LEN=%ld at=%0x" + , c + , len + , at); + CI_LOG_DEBUG(" stack empty = %d Size=%ld" + , m_SizeStack.empty() + , m_SizeStack.size()); + m_SizeStack.push_back(len); + continue; + } else if (! m_SizeStack.empty()) + { // Why should I pop the length ? + CI_LOG_DEBUG(" * HEADER use length current=%d queue len=%d" + ,len + ,m_SizeStack.front() + ); + } + } + } + + memset(bl,0x00,3); + if ( (len > 0) && (len < 4096)) + { + int before,after; + // Top level that must be used + CSTA_MSG::CSTA_msg message; + + //asn1::context ctx(len+1); + asn1::streams::ber ctx(len+1); + before = is.tellg(); + is.read((char *)ctx.buffer(),len); + after = is.tellg(); + if ((after - before ) != len) + { + CI_LOG_ERROR(" ERROR did not read right length %d expected: %ld only: %ld " + ,(after-before) + ,len + ,is.gcount()); + } else + { + CI_LOG_DEBUG(" * READ LENGTH %d",(after-before)); + } + //int result = pdu.codec(ctx,pdu,asn1::CODEC_DECODE); + //int result = message.codec(ctx,message,asn1::CODEC_DECODE); + int result = message.decode(ctx); + + + if (( (ctx.nb_read_bits()>>3) == len) || (ctx.nb_read_bits() >>3) == read_len) + { + if (( (ctx.nb_read_bits()>>3) != len) || (ctx.nb_read_bits() >>3) == read_len) + { + CI_LOG_DEBUG(" * WIERD CASE may be I should push back len : %d expected: %d payload: %d analysed: " + ,( after-before) + , len + , read_len + , (ctx.nb_read_bits()>>3)); + } + if (message.tag().byte() == asn1::tag(1,0,true).byte() + || message.tag().byte() == asn1::tag(1,1,true).byte() + || message.tag().byte() == asn1::tag(1,2,true).byte() + ) + { + std::stringstream ss,stitle; + //int invokeID = .retError.invokeID; + stitle<<"acse ()"; + + ss<m_content = ss.str(); + switch(message.get_aPDU_acse().get_kind()) + { + case ACSE_1::ACSE_apdu::typeof_aarq : + msg->msg_type(TLMsg::CSTA_REQUEST); + break; + case ACSE_1::ACSE_apdu::typeof_aare : + msg->msg_type(TLMsg::CSTA_RESPONSE); + break; + case ACSE_1::ACSE_apdu::typeof_rlrq : + msg->msg_type(TLMsg::CSTA_REQUEST); + break; + case ACSE_1::ACSE_apdu::typeof_rlre : + msg->msg_type(TLMsg::CSTA_RESPONSE); + break; + default: + msg->msg_type(TLMsg::CSTA_REJECT); + } + if (m_Model) + { + m_Model->add_TLMsg(msg,tls,tld); + } + + } else + { + Rose_Apdu::RoseAPDU &pdu= message.get_aPDU_rose(); + switch (pdu.get_kind()) + { + case Rose_Apdu::RoseAPDU::typeof_invoke: + CI_LOG_DEBUG("\tGot invoke ID=%ld",pdu.get_invoke().invokeID.get_sys_value()); + if (pdu.get_invoke().operationValue.get_kind() == Remote_Operations_Information_Objects::OpCode::typeof_local) + { + Remote_Operations_Information_Objects::IOPERATION::ptr op = pdu.get_invoke().argument; + // asn1::Object * _o = pdu.get_invoke().argument; + // Remote_Operations_Information_Objects::IOPERATION *op = + // dynamic_cast(_o); + + doInvoke( packet + , pdu.get_invoke().operationValue.get_local().get_sys_value() + , pdu.get_invoke().invokeID.get_sys_value(),op); + + } else { + + } + // std::cout<operationValue.get_kind() == Remote_Operations_Information_Objects::OpCode::typeof_local)) + { + std::stringstream ss,ss1; + + if (m_Ops[pdu.get_retResult().anonymousSEQUENCE->operationValue.get_local().get_sys_value()].size() >0) + { + ss1<<"/SR "<operationValue.get_local().get_sys_value()]<<" (id="<operationValue.get_local().get_sys_value()<<")"; + } + // complete other text fields + + ss<msg_type(TLMsg::CSTA_RESPONSE); + msg->m_content = ss.str(); + if (m_Model) + { + m_Model->add_TLMsg(msg,tls,tld); + } + + } else + { + std::cout<<"Got Result anonymous is_nul ? "<m_content = ss.str(); + msg->msg_type(TLMsg::CSTA_RESPONSE_ERROR); + if (m_Model) + { + m_Model->add_TLMsg(msg,tls,tld); + } + + + } + break; + case Rose_Apdu::RoseAPDU::typeof_reject: + { + std::stringstream ss,stitle; + + stitle<<"Reject "<msg_type(TLMsg::CSTA_REJECT); + msg->m_content = ss.str(); + + if (m_Model) + { + m_Model->add_TLMsg(msg,tls,tld); + } + + } + break; + default: + ; + + } /* end switch */ + } + } else + { + std::stringstream msg; + msg<<"Err Pdu len="<>3)<<""; + // not properly decoded see why. + // tree->add(msg.str().c_str()); + CI_LOG_DEBUG("\n * %s",msg.str().c_str()); + Timeline tld(0,dport,""); + Timeline tls(0,sport,""); + TLMsg *tmsg = new TLMsg(packet,msg.str().c_str()); + if (m_Model) + { + tmsg->m_content.resize(len *3+2); + char * buf = const_cast(tmsg->m_content.c_str()); + for (int i = 0 ; i < len ; i++) + { + char b[4]; + sprintf(b,"%02x ",ctx.buffer()[i]); + strcat(buf,b); + } + strcat(buf,"\n"); + m_Model->add_TLMsg(tmsg,tls,tld); + } + } + } else { + int at = is.tellg(); + if (at != -1 ) + { + CI_LOG_ERROR(" * BAD LENGTH %d at=%0x",len,at); + } + } + } + +} + + + +void +Controler::doInvoke(const Packet &packet,int opId,int InvokeId,Remote_Operations_Information_Objects::IOPERATION *op) +{ + + const struct sniff_tcp *tcp = packet.get_tcp(); + const struct sniff_ip *ip = packet.get_ip(); + unsigned short sport,dport; + + char buf[64]; + memset(buf,0x00,64); + + sport = htons(tcp->th_sport); + dport = htons(tcp->th_dport); + strcpy(buf,inet_ntoa(ip->ip_src)); + + CI_LOG_DEBUG("Controler::doInvoke Process invoke request opId=%d invokeId=%d",opId,InvokeId); + + if (opId == 21) + { + std::stringstream ss,ss1; + // Get OPERATION + CSTA_event::cSTAEventEvent *event; + event = dynamic_cast(op); + // Get OBJECT-TYPE + CSTA_event::CSTAEventReportArgument report; + event->get_ArgumentType(report); + CI_LOG_DEBUG("Got type info=%ld",report.eventType.get_local().get_sys_value()); + Remote_Operations_Information_Objects::IOBJECT_TYPE *event_obj; + asn1::Object * _o = report.eventInfo; + event_obj = dynamic_cast(_o); + ss.str(""); ss1.str(""); + std::string s = report.crossRefIdentifier.get_sys_value(); + unsigned char a0,a1,a2,a3; + a0 = (unsigned short)s[0]; + a1 = (unsigned short)s[1]; + a2 = (unsigned short)s[2]; + a3 = (unsigned short)s[3]; + int crid = (a2<<8) | a3; + + std::string addons; + Timeline tld(crid,dport,""); + Timeline tls(0,sport,""); + + if (m_Events[report.eventType.get_local().get_sys_value()].size()>0 ) + { + ss1<<"/"<new_TLMsg(packet,&msg); + doInvokeEvent(report.eventType.get_local().get_sys_value() + ,event_obj,tld,addons,msg); + //TLMsg *msg = new TLMsg(packet,ss1.str().c_str()); + //TLMsg *msg = new TLMsg(packet,addons); + msg->name = addons; + msg->msg_type(TLMsg::CSTA_EVENT); + + ss<m_content = ss.str(); + if (m_Model) + m_Model->add_TLMsg(msg,tls,tld); +#if 0 + + Fl_Tree_Item *item = tree->add(ss1.str().c_str()); + // Here we can decide to add sub stree information and build a string for the sequence diagram + std::string addons; + addons = m_Events[report.eventType.local]; + ProcessEvent(report.eventType.local,event_obj,item,addons); + + int lines = m_Editor->count_lines(0,m_Editor->buffer()->length(),1); + + item->user_data((void *)lines); + Fl_Text_Buffer *buffer = m_Editor->buffer(); + m_Sequence->add_event(crid,packet,addons.c_str(),item); + assign_icons(item,1); + + ss<<" == From : "<ip_dst)<<":"<append(ss.str().c_str()); + m_Editor->insert(ss.str().c_str()); +#endif + } else { + std::stringstream ss,ss1; + asn1::Object *obj= dynamic_cast(op); + Timeline tld(0,dport,""); + Timeline tls(0,sport,""); + if (m_Ops[opId].size() > 0) + { + ss1<<"/SReq "<msg_type(TLMsg::CSTA_REQUEST); + if (obj != NULL) + obj->printf(ss); + msg->m_content =ss.str(); + if (m_Model) + m_Model->add_TLMsg(msg,tls,tld); +#if 0 + Fl_Tree_Item *item = tree->add(ss1.str().c_str()); + + int lines = m_Editor->count_lines(0,m_Editor->buffer()->length(),1); + + item->user_data((void *)lines); + Fl_Text_Buffer *buffer = m_Editor->buffer(); + m_Sequence->add_invoke(packet,ss1.str().c_str(),item); + + assign_icons(item,0); + ss<<" == From : "<ip_dst)<<":"<printf(ss); +#endif + } + ; +} + + +void +Controler::doInvokeEvent(int id,Remote_Operations_Information_Objects::IOBJECT_TYPE *_evt,Timeline &tld,std::string &str,TLMsg *_msg) +{ + switch (id) + { + case 3: //connectionCleared + { + CSTA_event::connectionClearedEvent *p = dynamic_cast(_evt); + CSTA_event::ConnectionClearedEventInfo report; + p->get_ArgumentType(report); + std::string octs = report.droppedConnection.call->get_sys_value(); + std::string local(" Call="); + callToString(octs,local); + str+=local; + callToString(octs,_msg->m_callid); + //tree->add(item,local.c_str()); + //tree->close(item); + std::ostringstream oss; oss << report.localConnectionInfo; + str+= std::string(" lCI=")+oss.str(); + } + break; + + case 4: //deliveredEvent + { + CSTA_event::deliveredEvent *p = dynamic_cast(_evt); + CSTA_event::DeliEstaEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Delivered for call %s",report.connection.call->get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + + std::ostringstream oss ; oss<< report.localConnectionInfo; + str+= std::string(" lCI=") + oss.str(); + if (**report.localConnectionInfo == CSTA_connect::LocalConnectionState::alerting) + { + std::string local; + if (report.alertingDevice.get_kind() == CSTA_device::SubjectDeviceID::typeof_deviceIdentifier) + { + switch(report.alertingDevice.get_deviceIdentifier().get_kind()) + { + case CSTA_device::ExtendedDeviceID::typeof_deviceIdentifier: + break; + case CSTA_device::ExtendedDeviceID::typeof_implicitPublic: + break; + case CSTA_device::ExtendedDeviceID::typeof_explicitPublic: + break; + case CSTA_device::ExtendedDeviceID::typeof_implicitPrivate: + { + std::string result = report.alertingDevice.get_deviceIdentifier().get_implicitPrivate().get_sys_value(); + local = std::string(" initiating=") + result; + std::replace(result.begin(),result.end(),'\n',' '); + tld.set_device(result); + //tree->add(item,local.c_str()); + str+= local; + } + break; + case CSTA_device::ExtendedDeviceID::typeof_explicitPrivate: + break; + default: + ; + } + } + } + + } + break; + + case 5: //divertedEvent + { + CSTA_event::divertedEvent *p = dynamic_cast(_evt); + CSTA_event::DivertedEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Diverted %s",report.connection->call->get_sys_value().c_str()); + std::string octs = report.connection->call->get_sys_value(); + callToString(octs,_msg->m_callid); + + } + break; + case 6: //establishedEvent + { + CSTA_event::establishedEvent *p = dynamic_cast(_evt); + CSTA_event::DeliEstaEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Established for call %s",report.connection.call->get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + std::ostringstream oss ; oss<< report.localConnectionInfo; + str+= std::string(" lCI=") + oss.str(); + + + } + break; + case 7: //failedEvent + { + CSTA_event::failedEvent *p = dynamic_cast(_evt); + CSTA_event::FailNetwOrigEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Failed for call %s",report.connection.call->get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + callToString(octs,_msg->m_callid); + + } + break; + case 8: //heldEvent + { + CSTA_event::heldEvent *p = dynamic_cast(_evt); + CSTA_event::HeldEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event held for call %s",report.heldConnection.call->get_sys_value().c_str()); + std::string octs = report.heldConnection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + std::ostringstream oss ; oss<< report.localConnectionInfo; + str+= std::string(" lCI=") + oss.str(); + + } + break; + case 9: //networkReachedEvent + { + CSTA_event::networkReachedEvent *p = dynamic_cast(_evt); + CSTA_event::FailNetwOrigEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Network reached for call %s",report.connection.call->get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + std::ostringstream oss; oss <get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + std::ostringstream oss ; oss<< report.localConnectionInfo; + str+= std::string(" lCI=") + oss.str(); + + + } + break; + case 11: //queuedEvent + { + CSTA_event::queuedEvent *p = dynamic_cast(_evt); + CSTA_event::QueuedEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Queued for call %s",report.connection.call->get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + std::ostringstream oss ; oss<< report.localConnectionInfo; + str+= std::string(" lCI=") + oss.str(); + + } + break; + case 12: //retrievedEvent + { + CSTA_event::retrievedEvent *p = dynamic_cast(_evt); + CSTA_event::ConnectionEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Retrieved for call %s",report.connection.call->get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + + } + break; + case CSTA_event::serviceInitiatedEvent::uuid : //serviceInitiatedEvent + { + CSTA_event::serviceInitiatedEvent *p = dynamic_cast(_evt); + CSTA_event::ServiceInitiatedEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event Initiated for call %s",report.initiatedConnection.call->get_sys_value().c_str()); + std::string local; + std::string octs = report.initiatedConnection.call->get_sys_value(); + //std::string octs1 = report.call; + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + // convert call string to integer + switch (report.initiatingDevice.get_kind()) + { + case CSTA_device::ExtendedDeviceID::typeof_deviceIdentifier: + break; + case CSTA_device::ExtendedDeviceID::typeof_implicitPublic: + break; + case CSTA_device::ExtendedDeviceID::typeof_explicitPublic: + break; + case CSTA_device::ExtendedDeviceID::typeof_implicitPrivate: + { + std::string result = report.initiatingDevice.get_implicitPrivate().get_sys_value(); + local = std::string(" initiating=") + result; + std::replace(result.begin(),result.end(),'\n',' '); + tld.set_device(result); + //tree->add(item,local.c_str()); + str+= local; + } + break; + case CSTA_device::ExtendedDeviceID::typeof_explicitPrivate: + break; + default: + ; + } + std::ostringstream oss ; + if (!report.localConnectionInfo.is_nul()) { + oss<< (report.localConnectionInfo); + str+= std::string(" lCI=") + oss.str(); + } + //tree->close(item); + + } + break; + case 14: //transferredEvent + { + CSTA_event::transferredEvent *p = dynamic_cast(_evt); + CSTA_event::TransferredEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event CallInformation for call %s",report.primaryOldCall.call->get_sys_value().c_str()); + std::ostringstream oss ; oss<< report.localConnectionInfo; + std::string octs; + //if (! report.primaryOldCall.is_nul()) + octs = report.primaryOldCall.call->get_sys_value(); + str+= " PrimOldCall="; + callToString(octs,str); + if (! report.secondaryOldCall.is_nul()) + if ( ! report.secondaryOldCall->call.is_nul()) + octs = report.secondaryOldCall->call->get_sys_value(); + str+= " SecondOldCall="; + callToString(octs,str); + str+= std::string(" lCI=") + oss.str(); + + //octs = report.call; + if (report.transferredConnections->get_kind() == CSTA_connect::ConnectionList::typeof_callinformation) { + CSTA_call::ConnectionID conn = report.transferredConnections->get_callinformation()[0].endpoint; + if (!conn.call.is_nul()) + octs = conn.call->get_sys_value(); + callToString(octs,_msg->m_callid); + } + + + } + break; + case 101: //callInformationEvent + { + CSTA_event::callInformationEvent *p = dynamic_cast(_evt); + CSTA_event::CallInformationEventInfo report; + p->get_ArgumentType(report); + CI_LOG_DEBUG("Event CallInformation for call %s",report.connection.call->get_sys_value().c_str()); + std::string octs = report.connection.call->get_sys_value(); + str+= " Call="; + callToString(octs,str); + callToString(octs,_msg->m_callid); + + } + break; + + case 145: //otherPrivateEvent + { + CSTA_event::otherPrivateEvent *p = dynamic_cast(_evt); + } + break; + default: + _msg->m_callid = "default"; + ; + } + + +} + + +void +Controler::callToString(const std::string &ins,std::string &out) +{ + int res = 0; + for (std::string::const_iterator it = ins.begin() ; + it != ins.end(); ++it) + res = res << 8 | (unsigned char)(*it); + + std::stringstream ints; ints<evt_begin(),m_Model->evt_end(),Model::tlmsg_finder(m)); + if (it != m_Model->evt_end() ) + { + m_Model->select(m); + } +} + diff --git a/cstav1/Controler.h b/cstav1/Controler.h new file mode 100644 index 0000000..0e1173c --- /dev/null +++ b/cstav1/Controler.h @@ -0,0 +1,43 @@ +#ifndef CONTROLER_H__ +#define CONTROLER_H__ + +#include +#include +#include +#include +#include "sigslot.h" + +class Controler +{ + public: + Controler(Model *m); + ~Controler(); + + + void load(const char *fn,const char *expr = NULL); + void close(); + void onSelectTree(); + void onSelectSequence(); + //Not sur if it's the right place. + void parse_sip(const Packet &packet,std::stringstream &is); + void parse_ots(const Packet &packet,std::stringstream &is); + void parse_csta(const Packet &packet,std::stringstream &is,long read_length); + void doInvoke(const Packet &packet,int opId,int InvokeId,Remote_Operations_Information_Objects::IOPERATION *op); + void doInvokeEvent(int id,Remote_Operations_Information_Objects::IOBJECT_TYPE *_evt,Timeline &tld,std::string &str,TLMsg *_m); + + void callToString(const std::string &ins,std::string &out); + // Invoked when an item in the tree is selected + void select(TLMsg *m); + protected: + // Owns a pointer to view and one to Model + Model *m_Model; + SequenceView *m_SequenceUi; + HeaderView *m_HeaderUi; + + std::deque m_SizeStack; + std::map m_Events; + std::map m_Ops; + +}; + +#endif diff --git a/cstav1/CstaInsightLog.cpp b/cstav1/CstaInsightLog.cpp new file mode 100644 index 0000000..18cba25 --- /dev/null +++ b/cstav1/CstaInsightLog.cpp @@ -0,0 +1,2 @@ + +int cid_level = 1; diff --git a/cstav1/CstaInsightLog.h b/cstav1/CstaInsightLog.h new file mode 100644 index 0000000..f0d836f --- /dev/null +++ b/cstav1/CstaInsightLog.h @@ -0,0 +1,102 @@ +#ifndef CSTAINSIGHT_LOG_H__ +#define CSTAINSIGHT_LOG_H__ + +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ *10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__ ) +#endif + +#if defined(__APPLE__) || (GCC_VERSION > 40800) +#include +#include +#include +#include +#endif +#if defined(_WIN32) +# include +#else +#include +#endif + + +extern int cid_level; + +#if defined(__GNUC__) && defined(DEBUG) + +#define __MYFILE__ (strrchr(__FILE__,'/')?strrchr(__FILE__,'/')+1 : __FILE__) + +# define CI_LOG_DEBUG(fmt,args...) do {\ + if (cid_level >= 7) \ + { fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__MYFILE__,__LINE__); \ + } \ +} while (0); + +# define CI_LOG_INFO(fmt,args...) do {\ + if (cid_level >= 3) \ + { fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ + } \ +} while (0); + +# define CI_LOG_WARN(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__MYFILE__,__LINE__);\ +} while (0); + +# define CI_LOG_ERROR(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__MYFILE__,__LINE__);\ +} while (0); + +#elif defined(_WIN32) || defined(_WINDOWS) + +#define __MYFILE__ (strrchr(__FILE__,'/')?strrchr(__FILE__,'/')+1 : __FILE__) + +# define CI_LOG_DEBUG(fmt,...) do {\ + if (cid_level >= 7) \ + { fprintf(stderr,fmt,__VA_ARGS__);\ + fprintf(stderr," (%s : %d)\n",__MYFILE__,__LINE__); \ + } \ + } while (0); + +# define CI_LOG_INFO(fmt,...) do {\ + } while (0); + +# define CI_LOG_WARN(fmt,...) do {\ + fprintf(stderr,fmt,__VA_ARGS__);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ + } while (0); + +# define CI_LOG_ERROR(fmt,...) do {\ + fprintf(stderr,fmt,__VA_ARGS__);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ + } while (0); +#else +// Not debug but Release Target +# if not(defined(CI_LOG_DEBUG)) +# define CI_LOG_DEBUG(fmt,args...) do {} while (0); + //static inline void CI_LOG_DEBUG(const char *fmt,...) {(void)fmt;}; +# else + static inline void CI_LOG_DEBUG(const char *fmt,...) {(void)fmt;}; +# endif + +#define CI_LOG_INFO(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ +} while (0); + +# define CI_LOG_WARN(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ +} while (0); + +# define CI_LOG_ERROR(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ +} while (0); + +#endif + +#endif diff --git a/cstav1/HeaderView.cpp b/cstav1/HeaderView.cpp new file mode 100644 index 0000000..2a56363 --- /dev/null +++ b/cstav1/HeaderView.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +// For windows +#include + +#include +#include +#include +#include +#include +#include + +#include "Pcap.h" +#if defined( __WIN32__) || defined(_WINDOWS) +#include +#else +#include +#include +#endif + +#include "TLMsg.h" + +#include +#include + +#include "Model.h" + + + +HeaderView::HeaderView(int x,int y , int h, int w, const char *l) + : Fl_Widget(x,y,h,w,l) , m_Model(NULL) +{ + + ; +} + +HeaderView::~HeaderView() +{ + ; +} + +void HeaderView::resize(int X,int Y,int W,int H) +{ +#if 0 + printf("HeaderView::resize : x=%d y=%d w=%d h=%d\n",X,Y,W,H); +#endif + Fl_Widget::resize(X,Y,W,H); + damage(FL_DAMAGE_ALL); +} +void +HeaderView::draw() +{ + int m_separator = 120; + int y_base = 40; + char iPath[79]; + Fl_Preferences app(Fl_Preferences::USER,"CSTASpy","main"); + Fl_Preferences iconPath(app,"iconPath"); + iconPath.get("path",iPath,"",79); +#if 0 + printf("HeaderView:Draw x=%d y=%d\n",x(),y()); +#endif + std::string imgServer(iPath); imgServer.append(std::string("Server_24.png")); + std::string imgVT(iPath); imgVT.append("VT_24.png"); + Fl_PNG_Image s(imgServer.c_str()); + Fl_PNG_Image sip(imgVT.c_str()); + if (m_Model) + { + int i = 0; + Timeline tl_csta = Timeline(0,m_Model->portCsta(),""); + // + fl_color(FL_BLACK); + fl_font(0,8); + for (Model::TimelineType_const_iterator it = m_Model->tl_begin(); + it != m_Model->tl_end(); + ++it) + { + if ((*it) == tl_csta) { + s.draw(x()+140+i*120,y()+5); + fl_draw((*it).name(),x()+130 + i*m_separator,y()-2+y_base); + } else + { + std::string dev; + (*it).get_device(dev); + sip.draw(x()+140+i*120 ,y()+5); + if (dev.size() > 1) { + fl_draw(dev.c_str(),x()+170 + i*m_separator,y()-2+20); + } + fl_draw((*it).name(),x()+130 + i*m_separator,y()-2+y_base); + } + i++; + } + size(150 + i*m_separator + 50,h()); + } else + { + s.draw(x()+140,y()+5); + + for (int i = 1 ; i < 5; i++) + sip.draw(x()+140+i*120 ,y()+5); + } +} + +void +HeaderView::model(Model *m) +{ + m_Model = m; + m->subscribe(this); +}; + +void +HeaderView::onClean() +{ + std::cout<<"HeaderView::onClean"<redraw(); +} + +void +HeaderView::onAdd(TLMsg * ,Timeline &tls,Timeline &tld) +{ + ; + this->damage(FL_DAMAGE_ALL); + this->parent()->redraw(); +} diff --git a/cstav1/HeaderView.h b/cstav1/HeaderView.h new file mode 100644 index 0000000..6a8f3fb --- /dev/null +++ b/cstav1/HeaderView.h @@ -0,0 +1,61 @@ +#ifndef HEADERVIEW_H__ +#define HEADERVIEW_H__ + +#include +#include +#include +#include +#include + +#if defined(__WIN32__) || defined(_WINDOWS) +#include +#endif +#include +#include +#include +#include +#include +#include "Timeline.h" +// Packet information ... +#include "Pcap.h" +#if defined(__WIN32__) || defined (_WINDOWS) +#include +#else +#include +#include +#endif + +#include "TLMsg.h" +#include "sigslot.h" +#include "Observer.h" + +class Model; + +class HeaderView : public Fl_Widget, public Observer +{ + public: + + HeaderView(int x,int y , int h, int w, const char *l=NULL); + ~HeaderView(); + + void draw(); + + void resize(int X,int Y,int W,int H); + + void model(Model *m) ; + void onClean(); + void onNew(TLMsg *msg) {}; + void onAdd(TLMsg * ,Timeline &tls,Timeline &tld); + void onSelected(TLMsg *msg) {}; + inline void onScroll(int _x) { + Fl_Scroll *s = dynamic_cast(this->parent()); + Fl_Scrollbar *sb = &dynamic_cast(this->parent())->hscrollbar; + s->scroll_to(_x,s->yposition()); + s->redraw(); + }; + + protected: + Model *m_Model; +}; + +#endif diff --git a/cstav1/IconFactory.cpp b/cstav1/IconFactory.cpp new file mode 100644 index 0000000..d45019c --- /dev/null +++ b/cstav1/IconFactory.cpp @@ -0,0 +1,45 @@ +#include +#include + + +#include +#include +#include + +#include "IconFactory.h" + +IconFactory *IconFactory::m_IconFactory = NULL; + +IconFactory::IconFactory() +{ +} + +Fl_Image *IconFactory::get_Icon(const char *n) +{ + if (m_IconFactory == NULL) + { + m_IconFactory = new IconFactory(); + } + + return m_IconFactory->image(n); + +} + +Fl_Image *IconFactory::image(const char *name) +{ + if (m_Images[name] == NULL) + { + char iPath[79]; + // Build the picture + Fl_Preferences app(Fl_Preferences::USER,"CSTASpy","main"); + Fl_Preferences iconPath(app,"iconPath"); + iconPath.get("path",iPath,"",79); + std::string img(iPath); + + img.append(name); + m_Images[std::string(name)] = new Fl_PNG_Image(img.c_str()); + } + return m_Images[name]; +} + + diff --git a/cstav1/IconFactory.h b/cstav1/IconFactory.h new file mode 100644 index 0000000..a35dc04 --- /dev/null +++ b/cstav1/IconFactory.h @@ -0,0 +1,21 @@ +#ifndef ICON_FACTORY_H__ +#define ICON_FACTORY_H__ + + + +class IconFactory +{ + public: + IconFactory(); + + Fl_Image *image(const char *name); + static Fl_Image *get_Icon(const char *); + protected: + + std::map m_Images; + private: + static IconFactory *m_IconFactory; + +}; + +#endif diff --git a/cstav1/Model.cpp b/cstav1/Model.cpp new file mode 100644 index 0000000..9d43959 --- /dev/null +++ b/cstav1/Model.cpp @@ -0,0 +1,182 @@ +#include +#include + +#include + +#include "Model.h" + + +Model::Model() + : m_portCsta(2555),m_portSip(5059),m_portXml(8894) +{ + Timeline csta(0,m_portCsta,"CSTA srv"); + m_Timelines.push_back(csta); +} + +Model::~Model() +{ +} + +void +Model::parse_sip(const Packet &packet,std::stringstream &is) +{ + ; +} + +void +Model::parse_ots(const Packet &packet,std::stringstream &is) +{ + ; +} + +void +Model::parse_csta(const Packet &packet,std::stringstream &is) +{ + ; +} + +void +Model::clean() +{ + m_Timelines.erase(m_Timelines.begin(),m_Timelines.end()); + + // + for_each(m_Events.begin(),m_Events.end(),tlmsg_deleter()); + m_Events.erase(m_Events.begin(),m_Events.end()); + + int crid = 0; + unsigned short port= m_portCsta; + Timeline csta(crid,port,"CSTA srv"); + m_Timelines.push_back(csta); + + m_Calls.clear(); + m_OnClean(); +} + +void +Model::new_TLMsg(const Packet &p,TLMsg **m) +{ + std::string nm("NEWMSG"); + *m = new TLMsg(p,nm); +} + +void +Model::add_TLMsg(TLMsg *m,Timeline &tls,Timeline &tld) +{ + int dist = 0; + bool found = false; + // Find destination Timeline If not found add it in the list. + found = find_timeline(tld,dist); + if (!found) + m_Timelines.push_back(tld); + m->distance = dist; + + // Find Source Timeline + if ( ! find_timeline(tls,dist)) + m_Timelines.push_back(tls); + + if (m != NULL) + m->sdistance = dist; + + if (m != NULL) + m_Events.push_back(m); + + // Ok, process Calls msg->msg_type(TLMsg::CSTA_EVENT); + if (m->msg_type() == TLMsg::CSTA_EVENT) { + int nbcalls = m_Calls.size(); + Calls_const_iterator it = m_Calls.find(m->m_callid); + if ( it == m_Calls.end()) { + m_Calls[m->m_callid] = nbcalls; + } + } + + m_OnAdd(m,tls,tld); +} + + +bool +Model::have_Call(std::string &c,int &i) const +{ + Calls_const_iterator it = m_Calls.find(c); + if (it != m_Calls.end()) { + i = (it)->second; + return true; + } + return false; +} + +bool +Model::find_timeline(const Timeline &tl,int &distance ) +{ + bool found = false; + int dist = 0; + + + for (TimelineType_const_iterator it= m_Timelines.begin() ; + it != m_Timelines.end(); ++it) + { + if ((*it) == tl){ + found = true; + break; + } + dist++; + } + distance = dist; + return found; + +} + + +void +Model::subscribe(Observer *o) +{ + m_OnClean.connect(o,&Observer::onClean); + m_OnAdd.connect(o,&Observer::onAdd); + m_OnSelected.connect(o,&Observer::onSelected); + m_OnScroll.connect(o,&Observer::onScroll); +} + +void +Model::select(TLMsg *m) +{ + m_OnSelected(m); +} + + + +void +Model::export_msc(const char *fn) +{ + int i = 0; + std::ofstream msc(fn); + + + + for (TimelineType_const_iterator it= m_Timelines.begin() ; + it != m_Timelines.end(); ++it , i++) + { + std::string dev; + (*it).get_device(dev); + + if ((it) != m_Timelines.begin()){ + msc<<","; + } + msc<<"L"< 0) + { + msc<<" "<sdistance<<"-> L"<<(*it)->distance<<": [label=\""<<(*it)->name<<"\"];"< +#include +#include +#include +#include +#include + +#if defined(__WIN32__) || defined(_WINDOWS) +#include +#endif +#include +#include +#include +#include +#include "Timeline.h" +// Packet information ... +#include "Pcap.h" +#if defined(__WIN32__) || defined(_WINDOWS) +#else +#include +#include +#endif + +#include "TLMsg.h" +#include "sigslot.h" +#include "Observer.h" +class Model { + public: + + typedef std::vector TimelineType; + typedef std::vector::const_iterator TimelineType_const_iterator; + typedef std::vector EventType; + typedef std::vector::const_iterator EventType_const_iterator; + + typedef std::map Calls; + typedef std::map::const_iterator Calls_const_iterator; + + typedef sigslot::signal0<> cleanEvent; + typedef sigslot::signal3 addEvent; + typedef sigslot::signal1 selectEvent; + typedef sigslot::signal1 scrollEvent; + + struct tlmsg_deleter { + inline void operator ()(TLMsg *& e) { delete e; e= NULL;} + }; + + struct tlmsg_finder { + tlmsg_finder(TLMsg * e) : m_e(e) {}; + inline bool operator ()(TLMsg * e) { return e == m_e;}; + TLMsg *m_e; + }; + + Model(); + ~Model(); + + inline int tl_count() {return m_Timelines.size();}; + inline TimelineType_const_iterator tl_begin() {return m_Timelines.begin();}; + inline TimelineType_const_iterator tl_end() {return m_Timelines.end();}; + + inline EventType_const_iterator evt_begin() {return m_Events.begin();}; + inline EventType_const_iterator evt_end() {return m_Events.end();}; + + inline short portCsta() { return m_portCsta;}; + inline short portSip() { return m_portSip; }; + inline short portXml() { return m_portXml; }; + + inline void scroll_to(int x) {m_OnScroll(x);}; + void parse_sip(const Packet &packet,std::stringstream &is); + void parse_ots(const Packet &packet,std::stringstream &is); + void parse_csta(const Packet &packet,std::stringstream &is); + + // We should find setter and getters here. + + /** + * \brief build a new TimeLine Message. Also inform all views that a new entry has just been created. + */ + void new_TLMsg(const Packet &p,TLMsg **_msg); + + void add_TLMsg(TLMsg *_msg,Timeline &tsl,Timeline &tld); + + bool have_Call(std::string &,int &) const; + void clean(); + + void select(TLMsg *m); + + void export_msc(const char *fn); + + bool find_timeline(const Timeline &tl,int &distance ); + // Mvc subscription + void subscribe(Observer *o); + protected: + TimelineType m_Timelines; + EventType m_Events; + short m_portCsta; + short m_portSip; + short m_portXml; + + // Calls + Calls m_Calls; + // Events + cleanEvent m_OnClean; + addEvent m_OnAdd; + selectEvent m_OnSelected; + selectEvent m_OnNew; + scrollEvent m_OnScroll; +}; + +#endif diff --git a/cstav1/Observer.h b/cstav1/Observer.h new file mode 100644 index 0000000..0cdaf34 --- /dev/null +++ b/cstav1/Observer.h @@ -0,0 +1,17 @@ +#ifndef OBSERVER_H__ +#define OBSERVER_H__ +#include "sigslot.h" + +class Observer : public sigslot::has_slots<> +{ + public: + Observer() {}; + virtual ~Observer() {}; + virtual void onClean() = 0; + virtual void onNew(TLMsg *msg) = 0; + virtual void onAdd(TLMsg *msg,Timeline &tls,Timeline &tld) = 0; + virtual void onSelected(TLMsg *msg) = 0; + virtual void onScroll(int x) = 0; +}; + +#endif diff --git a/cstav1/Packet.cpp b/cstav1/Packet.cpp new file mode 100644 index 0000000..9b4a772 --- /dev/null +++ b/cstav1/Packet.cpp @@ -0,0 +1,264 @@ +#include +#include + +#include "Packet.h" +#define __FAVOR_BSD +#if ! defined(__WIN32__) && ! defined(_WINDOWS) +#include "netinet/in.h" +#include "netinet/tcp.h" +#endif +#include "SniffHeader.h" +#define SIZE_ETHERNET 14 + +#include +#include + +//#define PAYLOAD_DEBUG + +Packet::Packet() + : m_managed(false) +{ +} + +Packet::~Packet() +{ + if (m_managed) + { + std::cout<<"Packet::~Packet Release allocated\n"; + free(mp_data); + } +} + + +Packet::Packet(const unsigned char *d,size_t length) + : m_managed(false) +{ +} + + +Packet::Packet(const Header &header,const unsigned char *data) + : m_header(header), + mp_data(const_cast(data)) + ,m_managed(false) +{ +} + +Packet::Packet(const Packet &p) : m_header(p.m_header), mp_data(p.mp_data) + ,m_managed(false) +{ + +} + +Packet & Packet::operator =(const Packet &p) +{ + if (this != &p) + { + m_header = p.m_header; + mp_data = p.mp_data; + } + return *this; +} + +const unsigned char * +Packet::get_payload(long &length) +{ + const struct sniff_ethernet *ethernet; /* The ethernet header */ + const struct sniff_ip *ip; /* The IP header */ + const struct sniff_tcp *tcp; /* The TCP header */ + const char unsigned *payload; /* Packet payload */ + long cooked_header = 0; + u_int size_ip; + u_int size_tcp; + + // OK cast at the proper position + + if ( ((mp_data[2] == 0x03) && (mp_data[3] == 0x04)) + || + ((mp_data[14] == 0x08) && (mp_data[15] == 0x00))) { + cooked_header = 2; +#ifdef PAYLOAD_DEBUG + std::cout<<"Packet::get_payload Cooked header\n"; +#endif + } + ethernet = (struct sniff_ethernet*)(mp_data+cooked_header); + ip = (struct sniff_ip*)(mp_data + SIZE_ETHERNET+cooked_header); + size_ip = IP_HL(ip)*4; + if (size_ip < 20) { + printf(" * Invalid IP header length: %u bytes\n", size_ip); + return NULL; + } + tcp = (struct sniff_tcp*)(mp_data + SIZE_ETHERNET + size_ip+cooked_header); + if (ip->ip_p == 0x06) { + size_tcp = TH_OFF(tcp)*4; + if (size_tcp < 20) { + printf(" * Invalid TCP header length: %u bytes\n", size_tcp); + return NULL; + } + } else if (ip->ip_p == 0x11) { // UDP + size_tcp = sizeof(sniff_udp); + } else { + size_tcp = 0; + printf(" * Invalid unkwnow protocol: %u bytes %02x\n", size_tcp,ip->ip_p); + + } + payload = (u_char *)(mp_data + SIZE_ETHERNET + size_ip + size_tcp+cooked_header); + + int len = payload -mp_data; + length = m_header.len-len; + return payload; +} + +const struct sniff_ip * +Packet::get_ip() const /* The IP header */ +{ + const struct sniff_ethernet *ethernet; /* The ethernet header */ + const struct sniff_ip *ip; /* The IP header */ + const struct sniff_tcp *tcp; /* The TCP header */ + const char unsigned *payload; /* Packet payload */ + long cooked_header = 0; + u_int size_ip; + u_int size_tcp; + + // OK cast at the proper position + + if ( ((mp_data[2] == 0x03) && (mp_data[3] == 0x04)) + || + ((mp_data[14] == 0x08) && (mp_data[15] == 0x00))) { + cooked_header = 2; +#ifdef PAYLOAD_DEBUG + std::cout<<" Cooked header\n"; +#endif + } + ethernet = (struct sniff_ethernet*)(mp_data+cooked_header); + ip = (struct sniff_ip*)(mp_data + SIZE_ETHERNET+cooked_header); + size_ip = IP_HL(ip)*4; + if (size_ip < 20) { + printf(" * Invalid IP header length: %u bytes\n", size_ip); + return NULL; + } + return ip; + +} + +const struct sniff_tcp * +Packet::get_tcp() const /* The TCP header */ +{ + const struct sniff_ethernet *ethernet; /* The ethernet header */ + const struct sniff_ip *ip; /* The IP header */ + const struct sniff_tcp *tcp = NULL; /* The TCP header */ + const char unsigned *payload; /* Packet payload */ + long cooked_header = 0; + u_int size_ip; + u_int size_tcp; + + // OK cast at the proper position + + if ( ((mp_data[2] == 0x03) && (mp_data[3] == 0x04)) + || + ((mp_data[14] == 0x08) && (mp_data[15] == 0x00))) { + cooked_header = 2; +#ifdef PAYLOAD_DEBUG + std::cout<<"Packet::get_tcp Cooked header\n"; +#endif + } + ethernet = (struct sniff_ethernet*)(mp_data+cooked_header); + ip = (struct sniff_ip*)(mp_data + SIZE_ETHERNET+cooked_header); + size_ip = IP_HL(ip)*4; + if (size_ip < 20) { + printf(" * Invalid IP header length: %u bytes\n", size_ip); + return NULL; + } + if (ip->ip_p == 0x06) { + tcp = (struct sniff_tcp*)(mp_data + SIZE_ETHERNET + size_ip+cooked_header); + size_tcp = TH_OFF(tcp)*4; + if (size_tcp < 20) { + printf(" * Invalid TCP header length: %u bytes\n", size_tcp); + return NULL; + } + } + + return tcp; +} + + +const struct sniff_udp * +Packet::get_udp() const /* The TCP header */ +{ + const struct sniff_ethernet *ethernet; /* The ethernet header */ + const struct sniff_ip *ip; /* The IP header */ + const struct sniff_udp *udp = NULL; /* The TCP header */ + const char unsigned *payload; /* Packet payload */ + long cooked_header = 0; + u_int size_ip; + u_int size_udp; + + // OK cast at the proper position + + if ( ((mp_data[2] == 0x03) && (mp_data[3] == 0x04)) + || + ((mp_data[14] == 0x08) && (mp_data[15] == 0x00))) { + cooked_header = 2; +#ifdef PAYLOAD_DEBUG + std::cout<<"Packet::get_udp Cooked header\n"; +#endif + } + ethernet = (struct sniff_ethernet*)(mp_data+cooked_header); + ip = (struct sniff_ip*)(mp_data + SIZE_ETHERNET+cooked_header); + size_ip = IP_HL(ip)*4; + if (size_ip < 20) { + printf(" * Invalid IP header length: %u bytes\n", size_ip); + return NULL; + } + if (ip->ip_p == 0x11) { + udp = (struct sniff_udp*)(mp_data + SIZE_ETHERNET + size_ip+cooked_header); +#if 0 + size_udp = TH_OFF(tcp)*4; + if (size_udp < sizeof(struct_udp)) { + printf(" * Invalid UDP header length: %u bytes\n", size_tcp); + return NULL; + } +#endif + } + + return udp; +} + +void +Packet::manage() +{ + if (m_managed || mp_data == NULL) + return; + unsigned char * dest = (unsigned char *)malloc(m_header.caplen); + memcpy(dest, mp_data,m_header.caplen); + mp_data = dest; + m_managed = true; +} + +std::string +Packet::string_srcdst(void) +{ + const struct sniff_udp *udp = get_udp(); + const struct sniff_tcp *tcp = get_tcp(); + const struct sniff_ip *ip = get_ip(); + unsigned short sport,dport; + + char buf[128]; + + if (udp) { + sport = htons(udp->sport); + dport = htons(udp->dport); + } else if (tcp) + { + sport = htons(tcp->th_sport); + dport = htons(tcp->th_dport); + } + strcpy(buf,inet_ntoa(ip->ip_src)); + strcat(buf,":"); + int len = strlen(buf); + sprintf(buf+len,"%d To %s:%d",sport,inet_ntoa(ip->ip_dst),dport); + + std::string result(buf); + return result; + + +} diff --git a/cstav1/Packet.h b/cstav1/Packet.h new file mode 100644 index 0000000..bce54b1 --- /dev/null +++ b/cstav1/Packet.h @@ -0,0 +1,61 @@ +#ifndef __MPACKET_H__ +#define __MPACKET_H__ +#if defined(WIN32) || defined(_WINDOWS) +#else +// Only for Unix +#define __FAVOR_BSD +#include +#include "netinet/tcp.h" +#include +#endif +#include "SniffHeader.h" + +#include + +class Packet { + public: + + typedef struct pcap_pkthdr Header; + + Packet(); + ~Packet(); + Packet(const Packet &p) ; + Packet(const unsigned char *,size_t length); + Packet(const Header &header,const unsigned char *data); + + Packet & operator =(const Packet &p); + + inline struct timeval get_timeval() const + { return m_header.ts; }; + + inline long get_seconds() const + { return m_header.ts.tv_sec; }; + + inline long get_miliseconds() const + { return m_header.ts.tv_usec; }; + + inline long get_length() const + { return m_header.len; }; + + const struct sniff_ip *get_ip() const; /* The IP header */ + const struct sniff_tcp *get_tcp() const; /* The TCP header */ + const struct sniff_udp *get_udp() const; /* The TCP header */ + + std::string string_srcdst(void); + /** + * Return data only if available + */ + const unsigned char *get_payload(long &len); + + /// + /// @brief keep a local copy of the buffer. + /// + /// By default, the data are those from the pcap librarie. + void manage(); + protected: + Header m_header; + unsigned char *mp_data; + bool m_managed; +}; + +#endif diff --git a/cstav1/Pcap.cpp b/cstav1/Pcap.cpp new file mode 100644 index 0000000..b16f225 --- /dev/null +++ b/cstav1/Pcap.cpp @@ -0,0 +1,73 @@ +#include +#include +#include "Pcap.h" +#include "CstaInsightLog.h" + +char Pcap::s_ebuf[PCAP_ERRBUF_SIZE + 1] = ""; + +Pcap::Pcap(const std::string &file_name) + : m_ok(true) + ,m_mp_pcap_t(NULL) +{ + CI_LOG_DEBUG("Pcap::Pcap with file %s",file_name.c_str()); + if (! (m_mp_pcap_t = pcap_open_offline(file_name.c_str(),s_ebuf)) ) + { + // error + std::cerr<<"Failed open cap file\n"; + m_ok = false; + } +} + +Pcap::~Pcap() +{ + CI_LOG_DEBUG("Pcap::~Pcap"); + if (m_mp_pcap_t) + pcap_close(m_mp_pcap_t); +} + +void +Pcap::set_filter(const std::string &expression) +{ + struct bpf_program bpf; + + int ret = pcap_compile(m_mp_pcap_t,&bpf, + expression.c_str(),false,0); + + if (ret < 0) + { + CI_LOG_ERROR("Pcap::set_filter Failed compile expression : %s",expression.c_str()); + } + if (! (ret < 0 ) && pcap_setfilter(m_mp_pcap_t,&bpf) < 0 ) + { + CI_LOG_ERROR("Pcap::set_filter Failed set filter"); + } + pcap_freecode(&bpf); + + m_filter = expression; +} + +//friend +// +Pcap &operator>>(Pcap &cap , Packet &packet) +{ + static struct pcap_pkthdr *header; + static const u_char *data; + + switch( pcap_next_ex(cap.m_mp_pcap_t, const_cast(&header), + &data ) ) + { + case 1: // ok + packet = Packet(*header,data); + break; + case -1: //error + cap.m_ok = false; + break; + default: // EOF or expires + cap.m_ok = false; + ; + } + return cap; + + +} + diff --git a/cstav1/Pcap.h b/cstav1/Pcap.h new file mode 100644 index 0000000..5b9219f --- /dev/null +++ b/cstav1/Pcap.h @@ -0,0 +1,33 @@ +#ifndef PCAPPP_H__ +#define PCAPPP_H__ + +#include "Packet.h" +#include +#include + + +class Pcap { + public: + Pcap(const std::string &f); + ~Pcap(); + + bool next(Packet &p) + { return (*this>>p);}; + + friend Pcap &operator>>(Pcap &p,Packet &packet); + + + void set_filter(const std::string &expression); + operator bool() const + { + return m_ok; + }; + protected: + static char s_ebuf[]; + pcap_t *m_mp_pcap_t; + bool m_ok; + std::string m_filter; + std::string m_filename; +}; + +#endif diff --git a/cstav1/PrivateEla.cpp b/cstav1/PrivateEla.cpp new file mode 100644 index 0000000..5347743 --- /dev/null +++ b/cstav1/PrivateEla.cpp @@ -0,0 +1,12 @@ +#include + +#include "PrivateEla.h" + +PrivateEla::PrivateEla(const char *) +{ +} + +PrivateEla::~PrivateEla() +{ +} + diff --git a/cstav1/PrivateEla.h b/cstav1/PrivateEla.h new file mode 100644 index 0000000..b9d0273 --- /dev/null +++ b/cstav1/PrivateEla.h @@ -0,0 +1,40 @@ +#ifndef PRIVATE_ELA_H__ +#define PRIVATE_ELA_H__ + + +class PrivateEla { + public: + PrivateEla(const char *=NULL); + ~PrivateEla(); + + struct _Cs { + unsigned short connCall; + unsigned short connNeqt; + unsigned short connType; + }; + + struct Event { + unsigned char pType; // Private type + unsigned short pId; // Private identifier + unsigned long tbd; + unsigned long crid; // Crid + struct _Cs arr[5]; // + char arrS1[25]; // Array of chars + char arrS2[25]; // Array of chars + unsigned char as1Type; + unsigned char as2Type; + char arrL1[25]; // Array of chars + char arrL2[25]; // Array of chars + unsigned char al1Type; + unsigned char al2Type; + unsigned short line; // Private identifier + unsigned short cause; // Private identifier + }; + + protected: + +}; + + + +#endif diff --git a/cstav1/SequenceView.cpp b/cstav1/SequenceView.cpp new file mode 100644 index 0000000..74c0e0f --- /dev/null +++ b/cstav1/SequenceView.cpp @@ -0,0 +1,731 @@ +#include +#include +#include +#include +#include +#include +// Seems to be included before every thing else. +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(_WIN32) || defined(_WINDOWS) +#else +#include +#include +#endif +#include "Pcap.h" + +#include "XMLMessage.h" + +#include "TLMsg.h" +#include +#include +#include +#include + +#include "Model.h" +#include "IconFactory.h" + +SequenceView:: +SequenceView(int x,int y , int h, int w, const char *l) + : Fl_Widget(x,y,h,w,l) + ,m_separator(120), + m_Model(NULL), + m_Editor(NULL), + m_Buffer(NULL), + m_Selected(NULL), + m_Tree(NULL) +{ + int crid = 0; + unsigned short csta_port = 2555; + color(FL_WHITE); + Timeline csta(crid,csta_port,"CSTA srv"); + m_Crids.push_back(csta); +} + +void +SequenceView::add_event(int crid,Packet &p,const char *name,Fl_Tree_Item *_item) +{ + const struct sniff_ip *ip = p.get_ip(); + const struct sniff_tcp *tcp = p.get_tcp(); + int dist = 0; + TLMsg e(p,""); + e.crid = crid; + e.name = name; + e.item = _item; + e.sdistance = 0; + short csta_src = 2555; + bool found = false; + unsigned short dest_port = htons(tcp->th_dport); + unsigned short src_port = htons(tcp->th_sport); + Timeline tl(crid,dest_port,""); + for (CridType_const_iterator it= m_Crids.begin() ; + it != m_Crids.end(); ++it) + { + + if ((*it) == tl){ + found = true; +// std::cout<<"Crid in list\n"; + break; + } + dist++; + } + if (!found) + { + m_Crids.push_back(tl); + } + e.distance = dist; + m_Events.push_back(e); +} + +void +SequenceView::add_invoke(Packet &packet,const char *name, Fl_Tree_Item *_item ) +{ + const struct sniff_ip *ip = packet.get_ip(); + const struct sniff_tcp *tcp = packet.get_tcp(); + bool found = false; + int dist = 0; + int crid = 0; + unsigned short dest_port = htons(tcp->th_dport); + unsigned short src_port = htons(tcp->th_sport); + Timeline tl(crid,dest_port,""); + found = find_timeline(tl,dist); + + if (!found) + m_Crids.push_back(tl); + + // Add a message in the list + TLMsg e(packet,name); + e.crid = ip->ip_src.s_addr; + e.name = name; + e.item = _item; + //e.packet = packet; + //e.packet.manage(); + e.distance = dist; + + Timeline tls(crid,src_port,""); + if ( ! find_timeline(tls,dist)) + m_Crids.push_back(tls); + e.sdistance = dist; + + m_Events.push_back(e); + (m_Events.back()).packet.manage(); + +} + +void +SequenceView::add_result(Packet &packet,const char *name, Fl_Tree_Item *_item ) +{ + const struct sniff_ip *ip = packet.get_ip(); + const struct sniff_tcp *tcp = packet.get_tcp(); + bool found = false; + int dist = 0; + int crid = 0; + unsigned short dest_port = htons(tcp->th_dport); + unsigned short src_port = htons(tcp->th_sport); + Timeline tl(crid,dest_port,""); + found = find_timeline(tl,dist); + + if (!found) + m_Crids.push_back(tl); +#if 1 + // Add a message in the list + TLMsg e(packet,name); + e.crid = ip->ip_src.s_addr; + e.name = name; + e.item = _item; + e.distance = dist; + + Timeline tls(crid,src_port,""); + if ( ! find_timeline(tls,dist)) + m_Crids.push_back(tls); + e.sdistance = dist; + + m_Events.push_back(e); + (m_Events.back()).packet.manage(); +#endif + +} + +bool +SequenceView::find_timeline(const Timeline &tl,int &distance ) +{ + bool found = false; + int dist = 0; + + + for (CridType_const_iterator it= m_Crids.begin() ; + it != m_Crids.end(); ++it) + { + if ((*it) == tl){ + found = true; + break; + } + dist++; + } + distance = dist; + return found; + +} + +void +SequenceView::add_sip(const char *name,Packet &packet, Fl_Tree_Item *_item ) +{ + int dist = 0; + bool found = false; +// std::cout<<"SequenceView::add_sip\n"; + const struct sniff_ip *ip = packet.get_ip(); + + Timeline tl(ip->ip_dst,""); + found = find_timeline(tl,dist); + + if (!found) + m_Crids.push_back(tl); +#if 1 + // Add a message in the list + TLMsg e; + e.tv = packet.get_timeval(); + e.crid = ip->ip_src.s_addr; + e.name = name; + e.item = _item; + e.packet = packet; + //e.packet.manage(); + e.distance = dist; + + Timeline tls(ip->ip_src,""); + if ( ! find_timeline(tls,dist)) + m_Crids.push_back(tls); + e.sdistance = dist; + + m_Events.push_back(e); + (m_Events.back()).packet.manage(); +#endif +} + + +void +SequenceView::clear() +{ + color(FL_WHITE); + m_Crids.erase(m_Crids.begin(),m_Crids.end()); + m_Events.erase(m_Events.begin(),m_Events.end()); + damage(FL_DAMAGE_ALL); + int crid = 0; + unsigned short port= 2555; + Timeline csta(crid,port,"CSTA srv"); + m_Crids.push_back(csta); +} + +void SequenceView::resize(int _x, int _y, int w, int h ) +{ + Fl_Widget::resize(_x,_y,w,h); +} + +void +SequenceView::draw() +{ +#if 0 + if (m_Model) { + Fl_Scrollbar *sb = &dynamic_cast(this->parent())->hscrollbar; + m_Model->scroll_to(sb->value()); + } +#endif + uchar s = damage(); + if (s & FL_DAMAGE_ALL) { + draw2(); + } else { + //draw2(); + } +} + +void +SequenceView::draw1() +{ + int new_x = 0; + int new_y = 0; + int y_base =20; + int space = 19; + int line = 0,column = 0; + + color(FL_WHITE); + + fl_push_clip(x(),y(),w(),h()); + fl_push_matrix(); + fl_translate(x(),y()); + + fl_font(0,10); + fl_color(FL_BLACK); + // Draw crid length + for (CridType_const_iterator it = m_Crids.begin(); + it!= m_Crids.end(); + ++it) + { + std::stringstream scrid; + // draw text ... + fl_draw((*it).name(),x()+130 + column*m_separator,y()-2+y_base); + // beginning of line .... + fl_begin_line(); + fl_vertex(150+column*m_separator,y_base); + fl_vertex(150+column*m_separator,y_base+h()); + fl_end_line(); + column++; + } + new_y = 19+22; + new_x = 150 + column*m_separator + 50; + line = 1; + for (EventType_const_iterator it = m_Events.begin(); + it != m_Events.end(); + ++it) + { + if ((*it).item && (*it).item->is_selected()) + { + fl_color(FL_RED); + } else + fl_color(FL_BLUE); + // Begin arrow line + fl_begin_line(); + fl_vertex(150+(*it).sdistance*m_separator,y_base+space*line); + fl_vertex(150+(*it).distance*m_separator,y_base+space*line); + fl_end_line(); + // Should draw an arrow + int delta; + if ((*it).sdistance > (*it).distance) + { + delta = 5; + } else + delta = -5; + fl_begin_line(); + fl_vertex(150 +delta +(*it).distance*m_separator ,y_base-3+space*line); + fl_vertex(150+(*it).distance*m_separator,y_base+space*line); + fl_vertex(150 + delta +(*it).distance*m_separator,y_base+3+space*line); + fl_end_line(); + new_y+= space; + if ((*it).item && (*it).item->is_selected()) + { + fl_color(FL_RED); + } else + fl_color(FL_BLACK); + // Draw the text + std::string ts; + tvtostring((*it).get_timeval(),ts); + ts = ts ;//+ (*it).name; + fl_draw(ts.c_str(),15+x(),y()-2+space*line+y_base); + ts = (*it).name; + if ((*it).distance > ((*it).sdistance)) + { + fl_draw(ts.c_str(),150+x()+(*it).sdistance*m_separator,y()-2+space*line+y_base); + } else + { + fl_draw(ts.c_str(),150+x()+(*it).distance*m_separator,y()-2+space*line+y_base); + } + line++; + } + + fl_pop_matrix(); + fl_pop_clip(); + if (new_x < w()) + new_x = w(); + if (new_y < h()) + new_y = h(); + size(new_x,new_y); +} + + +void +SequenceView::draw2() +{ + int new_x = 0; + int new_y = 0; + int y_base =20; + int space = 19; + int line = 0,column = 0; + + color(FL_WHITE); + + fl_push_clip(x(),y(),w(),h()); + fl_push_matrix(); + fl_translate(x(),y()); + + fl_font(0,10); + fl_color(FL_BLACK); + // Draw crid length + for (Model::TimelineType_const_iterator it = m_Model->tl_begin(); + it!= m_Model->tl_end(); + ++it) + { + std::stringstream scrid; + // draw text ... + fl_draw((*it).name(),x()+130 + column*m_separator,y()-2+y_base); + // beginning of line .... + fl_begin_line(); + fl_vertex(150+column*m_separator,y_base); + fl_vertex(150+column*m_separator,y_base+h()); + fl_end_line(); + column++; + } + new_y = 19+22; + new_x = 150 + column*m_separator + 50; + line = 1; + for (Model::EventType_const_iterator it = m_Model->evt_begin(); + it != m_Model->evt_end(); + ++it) + { + int id; + // Draw Background box + if (m_Model->have_Call((*it)->m_callid,id)) { + struct col { + unsigned char r; + unsigned char g; + unsigned char b; + } col[] = { + {0xAA,0xAA,0xAA}, + {0xAA,0xFF,0xFF}, + {0xAA,0xFF,0x00}, + {0xFF,0x00,0x88}, + {0x55,0xAA,0x55} + } ; + fl_rectf(x(),y()+space*(line)+5,150+new_x,space,col[id].r,col[id].g,col[id].b) ; + } else { + fl_rectf(x(),y()+space*(line)+5,150+new_x,space,0xFF,0xFF,0xFF) ; + } + if ((*it) == m_Selected) + { + fl_color(FL_RED); + } else + fl_color(FL_BLUE); + // Begin arrow line + fl_begin_line(); + fl_vertex(150+(*it)->sdistance*m_separator,y_base+space*line); + fl_vertex(150+(*it)->distance*m_separator,y_base+space*line); + fl_end_line(); + // Should draw an arrow + int delta; + if ((*it)->sdistance > (*it)->distance) + { + delta = 5; + } else + delta = -5; + fl_begin_line(); + fl_vertex(150 +delta +(*it)->distance*m_separator ,y_base-3+space*line); + fl_vertex(150+(*it)->distance*m_separator,y_base+space*line); + fl_vertex(150 + delta +(*it)->distance*m_separator,y_base+3+space*line); + fl_end_line(); + new_y+= space; + if ((*it)->item && (*it)->item->is_selected()) + { + fl_color(FL_RED); + } else + fl_color(FL_BLACK); + // Draw the text + std::string ts; + tvtostring((*it)->get_timeval(),ts); + ts = ts ;//+ (*it).name; + fl_draw(ts.c_str(),15+x(),y()-2+space*line+y_base); + ts = (*it)->name; + if ((*it)->distance > ((*it)->sdistance)) + { + fl_draw(ts.c_str(),150+x()+(*it)->sdistance*m_separator,y()-2+space*line+y_base); + } else + { + fl_draw(ts.c_str(),150+x()+(*it)->distance*m_separator,y()-2+space*line+y_base); + } + line++; + } + // Redraw lines + column = 0; + fl_color(FL_BLACK); + fl_line_style(FL_DASH); + // Draw crid length + for (Model::TimelineType_const_iterator it = m_Model->tl_begin(); + it!= m_Model->tl_end(); + ++it) + { + // beginning of line .... + fl_begin_line(); + fl_vertex(150+column*m_separator,y_base); + fl_vertex(150+column*m_separator,y_base+h()); + fl_end_line(); + column++; + } + fl_line_style(0); + + fl_pop_matrix(); + fl_pop_clip(); + if (new_x < w()) + new_x = w(); + if (new_y < h()) + new_y = h(); + size(new_x,new_y); +} + +void SequenceView::tvtostring(struct timeval v,std::string &s) +{ + time_t t = v.tv_sec; + char buf[22]; + std::stringstream ss; + struct tm *tm = localtime(&t); + memset(buf,0x00,22); +#ifdef WIN32 + strftime(buf,21,"%y-%m-%d %H:%M:%S",tm); +#else + strftime(buf,21,"%F %H:%M:%S",tm); +#endif + long milliseconds = v.tv_usec /1000; + ss<subscribe(this); +}; + +int SequenceView::handle(int e) +{ + int X = x(); int Y = y(); int W = w(); int H = h(); + int dx = Fl::event_x() - X; + int dy = Fl::event_y() - Y; + switch(e) + { + case FL_NO_EVENT: + break; + case FL_DRAG: + { + //printf("SequenceView::handle drag %d dx=%d\n",e,dx); + return 1; + } + break; + case FL_PUSH: + { + Fl_Scrollbar *sb = &dynamic_cast(this->parent())->scrollbar; + if (sb) { + int y_base = 19; + int lines = 1; + for (Model::EventType_const_iterator it = m_Model->evt_begin(); + it != m_Model->evt_end(); + ++it) + { + if ( (dy > y_base * lines ) && dy < (y_base *(lines + 1)) ) { + //printf("Found : %s\n",(*it)->name.c_str()); + m_Model->select((*it)); + this->parent()->redraw(); + break; + } + if (dy > y_base) { + lines++; + } else + break; + } + } + } + if (callback() && (when() & FL_WHEN_CHANGED)) + do_callback(); + return 1; + break; + case FL_RELEASE: + // printf("SequenceView::handle release %d\n",e); + this->parent()->redraw(); + if (callback() && (when() & FL_WHEN_CHANGED)) + do_callback(); + return 1; + break; + case FL_MOVE: + //printf("SequenceView::handle move %d\n",e); + break; + case FL_ENTER: + case FL_LEAVE: + if (m_Model) { + Fl_Scrollbar *sb = &dynamic_cast(this->parent())->hscrollbar; + m_Model->scroll_to(sb->value()); + } + return 1; + break; + case FL_SHOW: + break; + default: + //printf("SequenceView::handle %d\n",e); + ; + } + return Fl_Widget::handle(e); +} + +void SequenceView::onSelected(TLMsg *s) +{ + m_Selected = s; + m_Editor->scroll(s->line()+1,0); + // Find item in Tree + Fl_Tree_Item *item = m_Tree->first(); + do { + if (item->user_data() == s) { + m_Tree->select_only(item,0); // Don't call callback. infinit loop + break; + } + } while ((item = m_Tree->next(item)) != NULL); + + redraw(); +} + +/** + * The name of tree items must be unique. + */ +static int counter = 0; + +void SequenceView::onClean() +{ + counter = 0; + damage(FL_DAMAGE_ALL); +} + +void SequenceView::onNew(TLMsg *s) +{ + +} + +void SequenceView::onAdd(TLMsg *msg,Timeline &tsl,Timeline &tld) +{ + std::stringstream ss; //Used for output + Fl_Tree_Item * item = NULL; + if (msg) + { +// std::cout<<"SequenceView::onAdd "<name<name.size() > 1) + { + if ( msg->name.size() < 4) + { + m_CurrentTreeItem = item = m_Tree->add("undefined"); + } else + { + ss<name<<" "<add(ss.str().c_str()); + } + int lines = m_Editor->count_lines(0,m_Editor->buffer()->length(),1); + /* + * As said, the string used by add must be unique. + */ + if (item) + { + item->user_data((void *)msg); + } else + { + std::cerr<<"SequenceView::onAdd item is NULL msg.name.size : "<name.size()<line(lines); + ss<<"== "<packet.string_srcdst()<<" =="<msg_type() != TLMsg::SIP) + ss<name<m_content; + m_Editor->insert(ss.str().c_str()); + } + switch (msg->msg_type()) + { + case TLMsg::CSTA_REQUEST: + if (item) + item->usericon(IconFactory::get_Icon("Request_16.png")); + break; + case TLMsg::CSTA_RESPONSE: + if (item) + item->usericon(IconFactory::get_Icon("Response_16.png")); + break; + case TLMsg::CSTA_RESPONSE_ERROR: + if (item) + item->usericon(IconFactory::get_Icon("ResponseError_16.png")); + break; + case TLMsg::CSTA_REJECT: + if (item) + item->usericon(IconFactory::get_Icon("ResponseReject_16.png")); + break; + case TLMsg::CSTA_EVENT: + if (item) + item->usericon(IconFactory::get_Icon("Lighting_16.png")); + break; + case TLMsg::SOAP_REQUEST: + { + if (item) + { + size_t found = 0; + item->usericon(IconFactory::get_Icon("RequestSoap_16.png")); + XMLMessage xmlmsg(m_Tree,item); + xmlmsg.Create(); + + void *p = xmlmsg.GetBuffer(msg->m_content.size()); + if ( (found =msg->m_content.find("m_content.substr(found).c_str(),msg->m_content.size()-found); + xmlmsg.ParseBuffer(msg->m_content.size()-found); + } + + } + break; + } + case TLMsg::SOAP_RESPONSE: + if (item) + { + size_t found = 0; + item->usericon(IconFactory::get_Icon("ResponseSoap_16.png")); + XMLMessage xmlmsg(m_Tree,item); + xmlmsg.Create(); + + void *p = xmlmsg.GetBuffer(msg->m_content.size()); + if ( (found =msg->m_content.find("m_content.substr(found).c_str(),msg->m_content.size()-found); + xmlmsg.ParseBuffer(msg->m_content.size()-found); + } + } + break; + case TLMsg::SIP: + if (item) + { + size_t found = 0; + item->usericon(IconFactory::get_Icon("Sip_16.png")); + if ( (found =msg->m_content.find("m_content.size()); + strncpy((char *)p,msg->m_content.substr(found).c_str(),msg->m_content.size()-found); + xmlmsg.ParseBuffer(msg->m_content.size()-found); + } + } + break; + case TLMsg::ICS_EVENT: + if (item) + { + size_t found = 0; + item->usericon(IconFactory::get_Icon("Lighting_16.png")); + XMLMessage xmlmsg(m_Tree,item); + xmlmsg.Create(); + + void *p = xmlmsg.GetBuffer(msg->m_content.size()); + if ( (found =msg->m_content.find("m_content.substr(found).c_str(),msg->m_content.size()-found); + xmlmsg.ParseBuffer(msg->m_content.size()-found); + } + } + break; + default: + ; + }; + } else + { +// std::cout<<"SequenceView::onAdd"<parent()->redraw(); + m_Tree->parent()->redraw(); +} diff --git a/cstav1/SequenceView.h b/cstav1/SequenceView.h new file mode 100644 index 0000000..a74c1dd --- /dev/null +++ b/cstav1/SequenceView.h @@ -0,0 +1,93 @@ +#ifndef __SEQ_VIEW_H__ +#define __SEQ_VIEW_H__ +#include +#include +#include +#include +#include + +#if defined(__WIN32__) || defined(_WINDOWS) +#include +#endif +#include +#include +#include +#include +#include "Timeline.h" +// Packet information ... +#if defined(__WIN32__) ||defined(_WINDOWS) +#else +#include +#include +#endif +#include "Pcap.h" + +#include "sigslot.h" +#include "TLMsg.h" +#include "Observer.h" +/** + */ + +class Model; + +class SequenceView : public Fl_Widget ,public Observer + //,public sigslot::multi_threaded_local +{ + public: + + typedef std::vector CridType; + typedef std::vector::const_iterator CridType_const_iterator; + typedef std::vector EventType; + typedef std::vector::const_iterator EventType_const_iterator; + + SequenceView(int x,int y , int h, int w, const char *l=NULL); + + void draw(); + void draw1(); // Old way + + void draw2(); // New way + + int handle(int event); + void clear(); + + void resize(int x, int y, int w, int h ); + + void add_event(int crid,Packet &p,const char *name, Fl_Tree_Item *_item = NULL); + void add_invoke(Packet &packet,const char *name, Fl_Tree_Item *_item = NULL); + void add_result(Packet &packet,const char *name, Fl_Tree_Item *_item = NULL); + void add_sip(const char *name,Packet &packet, Fl_Tree_Item *_item = NULL); + + inline void tree(Fl_Tree *t) {m_Tree = t;}; + inline void editor(Fl_Text_Editor *t) {m_Editor = t;}; + + bool find_timeline(const Timeline &tl,int &distance ); + + void model(Model *m); + + void onClean(); + void onNew(TLMsg *); + void onAdd(TLMsg *,Timeline &tsl,Timeline &tld); + void onSelected(TLMsg *); + void onScroll(int x) { }; + protected: + void tvtostring(struct timeval t,std::string &s); + + protected: + CridType m_Crids; + EventType m_Events; + + TLMsg *m_Selected; + long m_separator; + int m_new_x; + int m_new_y; + Fl_Tree *m_Tree; + Fl_Tree_Item *m_CurrentTreeItem; + Fl_Text_Editor *m_Editor; + Fl_Text_Buffer *m_Buffer; + Model *m_Model; +}; + +#endif +// +// +// diff --git a/cstav1/SniffHeader.h b/cstav1/SniffHeader.h new file mode 100644 index 0000000..b4fa55b --- /dev/null +++ b/cstav1/SniffHeader.h @@ -0,0 +1,68 @@ +#ifndef __SNIFF_HEADER_H__ +#define __SNIFF_HEADER_H__ + +/* Ethernet addresses are 6 bytes */ +#define ETHER_ADDR_LEN 6 + + /* Ethernet header */ + struct sniff_ethernet { + u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */ + u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */ + u_short ether_type; /* IP? ARP? RARP? etc */ + }; + + /* IP header */ + struct sniff_ip { + u_char ip_vhl; /* version << 4 | header length >> 2 */ + u_char ip_tos; /* type of service */ + u_short ip_len; /* total length */ + u_short ip_id; /* identification */ + u_short ip_off; /* fragment offset field */ + #define IP_RF 0x8000 /* reserved fragment flag */ + #define IP_DF 0x4000 /* dont fragment flag */ + #define IP_MF 0x2000 /* more fragments flag */ + #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ + }; + #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f) + #define IP_V(ip) (((ip)->ip_vhl) >> 4) + + /* TCP header */ + struct sniff_tcp { + u_short th_sport; /* source port */ + u_short th_dport; /* destination port */ +#ifdef WIN32 + unsigned long th_seq; /* sequence number */ + unsigned long th_ack; /* acknowledgement number */ +#else + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#endif + u_char th_offx2; /* data offset, rsvd */ + #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) + u_char th_flags; + #define TH_FIN 0x01 + #define TH_SYN 0x02 + #define TH_RST 0x04 + #define TH_PUSH 0x08 + #define TH_ACK 0x10 + #define TH_URG 0x20 + #define TH_ECE 0x40 + #define TH_CWR 0x80 + #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) + u_short th_win; /* window */ + u_short th_sum; /* checksum */ + u_short th_urp; /* urgent pointer */ +}; + +struct sniff_udp { + u_short sport; + u_short dport; + u_short length; + u_short checksum; +}; + +#endif diff --git a/cstav1/TLMsg.cpp b/cstav1/TLMsg.cpp new file mode 100644 index 0000000..d86df09 --- /dev/null +++ b/cstav1/TLMsg.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +#if defined(_WINDOWS) +#include +#endif +#include +#include +#include +#include + +#include + +#if ! defined(__WIN32__) && ! defined(_WINDOWS) +#include +#include +#endif + +#include "Pcap.h" +#include "TLMsg.h" + +TLMsg::TLMsg(const Packet &p,const std::string &_name) + : packet(p), name(_name),item(NULL),m_callid(""),m_Type(TLMsg::UNKNOWN) +{ +} + +TLMsg::TLMsg(const TLMsg &t) +{ + name = t.name; + distance = t.distance; + sdistance = t.sdistance; + packet = t.packet; + crid = t.crid; + item = t.item; + m_callid = t.m_callid; + m_Type = t.m_Type; +} + +TLMsg::~TLMsg() +{ + CI_LOG_DEBUG("TLMsg::~TLMsg %s",name.c_str()); +} + +void +TLMsg::set_distance(int source,int dest) +{ + sdistance = source; + distance = dest; +} diff --git a/cstav1/TLMsg.h b/cstav1/TLMsg.h new file mode 100644 index 0000000..0d0a7a1 --- /dev/null +++ b/cstav1/TLMsg.h @@ -0,0 +1,70 @@ +#ifndef TIMELINE_MSG_H__ +#define TIMELINE_MSG_H__ + +/** + * TimelineMsg class represents one line in the sequence diagram. + * + * For now, all attributes are public but they need to be made protected. + * The value tv can directly be extracated from the Packet Class. + * + * + */ +class TLMsg { + public: + + enum eMsgType { + SIP, + CSTA_REQUEST, + CSTA_RESPONSE, + CSTA_EVENT, + CSTA_RESPONSE_ERROR, + CSTA_REJECT, + SOAP_REQUEST, + SOAP_RESPONSE, + ICS_EVENT, + UNKNOWN + }; + inline eMsgType msg_type() { return m_Type;}; + inline void msg_type(eMsgType t) {m_Type = t; }; + + // The Distance in stored in a pair where first is source and second dest. + typedef std::pair Distance; + + TLMsg() : item(NULL) {}; + + TLMsg(const Packet &p,const std::string &_name); + + TLMsg(const TLMsg &t); + ~TLMsg(); + + inline struct timeval get_timeval() const {return packet.get_timeval();}; + + Distance get_distance() const {return Distance(sdistance,distance);}; + + void set_distance(int source,int dest); + // Title settings + inline void title(const std::string &s) {m_title = s;}; + inline const char * title(void) {return m_title.c_str();}; + + inline void line(int l ) {m_line = l;}; + inline int line(void) {return m_line;}; + + inline void call_id(const std::string &s) {m_callid = s;}; + inline std::string call_id() {return m_callid;}; + eMsgType m_Type; + std::string name; + int crid; // Destination of the message. Crid was used because at the begining, only CSTA was concerned + int distance; // Distance from 0 to Crid is not enough for sip messages. + int sdistance; // By default, sdistance is 0 + struct timeval tv; + // What to when sip with source and destination ? + Packet packet; + std::string m_title; // Title of the message will be different from core message + std::string m_callid; // Callid used to color line depending on call + Fl_Tree_Item *item; // This must disapear + int m_line; // Save the position of the text for this line. + std::string m_content; // Content to be displayed +} ; + + +#endif diff --git a/cstav1/TLMsgCsta.h b/cstav1/TLMsgCsta.h new file mode 100644 index 0000000..0aaee72 --- /dev/null +++ b/cstav1/TLMsgCsta.h @@ -0,0 +1,17 @@ +#ifndef TLMSGCSTA_H__ +#define TLMSGCSTA_H__ + +class TLMsgCsta : public TLMsg +{ + public: + TLMsgCsta(); + TLMsgCsta( + long crid, + long eventType, + Remote_Operations_Information_Objects::IOBJECT_TYPE *event_obj); + ~TLMsgCsta(); + + +}; + +#endif diff --git a/cstav1/TLMsgSip.h b/cstav1/TLMsgSip.h new file mode 100644 index 0000000..018692e --- /dev/null +++ b/cstav1/TLMsgSip.h @@ -0,0 +1,13 @@ +#ifndef TLMSGSIP_H__ +#define TLMSGSIP_H__ + +class TLMsgSip : public TLMsg +{ + public: + TLMsgSip(); + TLMsgSip(const TLMsgSip &_m); + ~TLMsgSip(); + protected: +}; + +#endif diff --git a/cstav1/TLMsgXml.h b/cstav1/TLMsgXml.h new file mode 100644 index 0000000..c7a6153 --- /dev/null +++ b/cstav1/TLMsgXml.h @@ -0,0 +1,13 @@ +#ifndef TLMSGXML_H__ +#define TLMSGXML_H__ + + +class TLMsgXml : public TLMsg +{ + public: + TLMsgXml(); + ~TLMsgXml(); + + protected: +}; +#endif diff --git a/cstav1/Timeline.cpp b/cstav1/Timeline.cpp new file mode 100644 index 0000000..9d7b3ef --- /dev/null +++ b/cstav1/Timeline.cpp @@ -0,0 +1,119 @@ +#include +#include + +#ifdef WIN32 +#include +#else +#include +#include +#endif +#include "Timeline.h" + +Timeline::Timeline(int crid, const char *name) + : m_crid(crid), m_port(0),m_name(name),m_type(TL_CRID) +{ + if (m_name.size() < 2) + { + std::stringstream ss; + ss<<"Crid<"<"; + m_name = ss.str(); + } +} + +Timeline::Timeline(int crid, unsigned short port,const char *name) + : m_crid(crid), m_port(port),m_name(name),m_type(TL_CRID_PORT) +{ + if (m_name.size() < 2) + { + std::stringstream ss; + ss<<"Crid<"<{"<("<"; + m_name = ss.str(); + } +} + + +Timeline::Timeline(const Timeline &t) +{ + m_crid = t.m_crid; + m_name = t.m_name; + m_type = t.m_type; + m_port = t.m_port; + m_device = t.m_device; +} + +Timeline::~Timeline() +{ +} + +bool +Timeline::operator ==(const Timeline &_t) const +{ + if (m_type == TL_CRID) + { + return (m_crid == _t.m_crid); + } else if (m_type == TL_CRID_PORT && _t.m_type == TL_CRID) + { + return (m_crid == _t.m_crid); + } else if (m_type == TL_CRID_PORT && _t.m_type == TL_CRID_PORT) + { + return ((m_port == _t.m_port) && + (m_crid == _t.m_crid) + ); + } else if (m_type == TL_CRID_PORT && _t.m_type == TL_PORT) + { + return ((m_port == _t.m_port) + ); + } else if (m_type == TL_PORT && _t.m_type == TL_CRID_PORT) + { + return ((m_port == _t.m_port) + ); + } else if (m_type == TL_IP && _t.m_type == TL_IP) + { + return ((m_crid == _t.m_crid) + ); + } else if (m_type == TL_PORT && _t.m_type == TL_PORT) + { + return ((m_port == _t.m_port) + ); + }else + return false; +} + + +bool +Timeline::operator ==(const struct in_addr &_t) const +{ + return (m_crid == _t.s_addr) && (m_type == TL_IP); +} + +bool +Timeline::operator ==(short _t) const +{ + return (m_port == _t) && ( + (m_type == TL_PORT) + ||(m_type == TL_CRID_PORT)); +} diff --git a/cstav1/Timeline.h b/cstav1/Timeline.h new file mode 100644 index 0000000..0608686 --- /dev/null +++ b/cstav1/Timeline.h @@ -0,0 +1,36 @@ +#ifndef __TIMELINE_H__ +#define __TIMELINE_H__ + +class Timeline { + public: + enum { + TL_CRID, + TL_CRID_PORT, + TL_PORT, // from one IP port to another + TL_IP + }; + Timeline (int crid,const char *name=NULL); + Timeline (int crid,unsigned short port,const char *name=NULL); + Timeline (unsigned short port,const char *name=NULL); + Timeline (struct in_addr crid,const char *name=NULL); + Timeline (const Timeline &t); + virtual ~Timeline(); + + inline const char *name() const {return m_name.c_str();}; + + inline void set_device(std::string &_d) { m_device = _d;}; + inline void get_device(std::string &_d) const { _d = m_device;}; + + bool operator ==(const Timeline &_t) const; + bool operator ==(short _t) const; + bool operator ==(const struct in_addr &_t) const; + + protected: + std::string m_name; + int m_crid; // In case the time lines belongs to csta events + int m_type; + unsigned short m_port; + std::string m_device; // Device number. If available not null. +}; + +#endif diff --git a/cstav1/XMLMessage.h b/cstav1/XMLMessage.h new file mode 100644 index 0000000..ed15355 --- /dev/null +++ b/cstav1/XMLMessage.h @@ -0,0 +1,72 @@ +#ifndef XMLMESSAGES_H__ +#define XMLMESSAGES_H__ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "CExpatImpl.h" +/** + * \brief This class is used to parse ics events and soap requests. + * The parse request will be put in a tree + */ +class XMLMessage : public CExpatImpl +{ + public: + XMLMessage(Fl_Tree *tree,Fl_Tree_Item *item) :m_tree(tree),m_item(item){ + m_stack.push(item); + item->close(); + }; + ~XMLMessage() {}; + + void OnPostCreate() + { + // Enable all the event routines we want + EnableStartElementHandler (); + EnableEndElementHandler (); + // Note: EnableElementHandler will do both start and end + EnableCharacterDataHandler (); + } + + virtual void OnStartElement (const XML_Char *pszName, + const XML_Char **papszAttrs) + { + m_stack.push(m_tree->add(m_stack.top(),pszName)); + return; + } + + // @cmember End element handler + + virtual void OnEndElement (const XML_Char *pszName) + { + m_stack.pop(); + return; + } + + // @cmember Character data handler + + virtual void OnCharacterData (const XML_Char *pszData, int nLength) + { + std::string old(m_stack.top()->label()); + std::string toadd(pszData,nLength); + old+= " "; + old+=toadd; + m_stack.top()->label(old.c_str()); + return; + } + + + protected: + Fl_Tree *m_tree; // The tree were to inserr sub elements + Fl_Tree_Item *m_item; // Base Itesm + std::stack m_stack; +}; +#endif diff --git a/cstav1/cstaspyui.fl b/cstav1/cstaspyui.fl new file mode 100644 index 0000000..93424f5 --- /dev/null +++ b/cstav1/cstaspyui.fl @@ -0,0 +1,688 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0300 +header_name {.h} +code_name {.cxx} +decl {\#include } {public global +} + +decl {\#include } {public global +} + +decl {\#include } {public global +} + +decl {\#include } {private global +} + +decl {\#include } {public global +} + +decl {\#include } {private global +} + +decl {\#include } {public global +} + +declblock {\#if defined(__WIN32__) ||defined (_WINDOWS)} {public after {\#endif} +} { + decl {\#include } {public global + } +} + +decl {\#include "XMLMessage.h"} {public global +} + +decl {\#include "Pcap.h"} {public global +} + +decl {\#include } {private global +} + +decl {\#include } {public local +} + +decl {\#include } {public local +} + +decl {\#include } {public local +} + +decl {\#include "CstaInsightLog.h"} {public global +} + +declblock {\#if defined(__WIN32__) ||defined (_WINDOWS)} {public after {\#endif} +} { + decl {\#include } {public global + } + decl {\#else} {public global + } + decl {\#include } {public global + } + decl {\#include } {public global + } +} + +decl {\#include "rtasn1/asn1.h"} { + comment {// Asn1 stuff} private local +} + +decl {\#include "rtasn1/asn1_codec.h"} {private global +} + +decl {\#include "rtasn1/asn1_codec_ber.h"} {private local +} + +decl {\#include "Rose_Apdu.h"} { + comment {// CSTA stubs} public global +} + +decl {\#include "CSTA_event.h"} {public global +} + +decl {\#include "SequenceView.h"} {public global +} + +decl {\#include "HeaderView.h"} {public global +} + +decl {\#include "Model.h"} { + comment {// Model View Controler files} public global +} + +decl {\#include "Controler.h"} {public global +} + +decl {Fl_File_Chooser *fc;} { + comment {// File Chooser} private local +} + +class MainUI {open +} { + Function {MainUI()} {} { + code {m_Buffer = new Fl_Text_Buffer(1024*16); +m_Model = new Model(); +m_Controler = new Controler(m_Model);} {} + } + Function {make_window()} {open + } { + Fl_Window m_Window { + label {CSTA Insight} open + xywh {815 139 1035 855} type Double resizable + code0 {fc = new Fl_File_Chooser(".","*",Fl_File_Chooser::SINGLE,"Select OmniPCX Office CSTA stream");} visible + } { + Fl_Menu_Bar {} {open + xywh {0 0 1035 22} + } { + Submenu {} { + label {&File} + xywh {0 0 100 20} labelsize 12 + } { + MenuItem {} { + label {&Open} + callback {int i; +int count = 0; +char relative[FL_PATH_MAX]; + +fc->show(); + +while(fc->visible() ) +{ + Fl::wait(); +} + +count = fc->count(); +std::cout<<"Got count = "< 0) +{ + for (i = 0 ; i < count; i++) + { + if (!fc->value(i)) + break; + fl_filename_relative(relative,sizeof(relative),fc->value(i)); + std::cout<<" Selected : "<value(i),".pcap")) + { + char *pos = (char *)strstr(fc->value(i),".pcap"); + m_current_filename = relative; +\#ifndef __WIN32__ + while (*pos != '/') + pos--; +\#endif + pos++; + std::cout<<"Process PCAP file :"<value(i)<root()) + { + tree->add("ROOT"); + } + tree->root_label(pos); + m_Controler->load(relative); +// do_pcap(relative); + } else { + std::cout<<"Unsuported format\\n"; + } + + } +} + +char iPath[100]; + +Fl_Preferences app(Fl_Preferences::USER,"CSTASpy","main"); +Fl_Preferences Cfg(app,m_current_filename.c_str()); +Cfg.get("filter",iPath,m_InputChoice->value(),99); +m_InputChoice->value(iPath); +//Cfg.set("filter",m_InputChoice->value());} + xywh {0 0 100 20} labelsize 12 + } + MenuItem {} { + label {&Close} + callback {tree->clear_children(tree->root()); +m_Controler->close(); +tree->root_label("ROOT"); +m_Sequence->clear(); +tree->redraw(); +m_Sequence->redraw(); +m_Scroll->redraw(); +m_Editor->buffer()->remove(0,m_Editor->buffer()->length());} + xywh {0 0 100 20} labelsize 12 divider + } + MenuItem {} { + label {&Export XMI} + xywh {0 0 100 20} labelsize 12 + } + MenuItem {} { + label {Export Msc} + callback {int i; +int count = 0; +char relative[FL_PATH_MAX]; + +fc->show(); + +while(fc->visible() ) +{ + Fl::wait(); +} + +count = fc->count(); + + +if (count > 0) +{ + for (i = 0 ; i < count; i++) + { + if (!fc->value(i)) + break; + fl_filename_relative(relative,sizeof(relative),fc->value(i)); + std::cout<<" Selected : "<value(i),".pcap")) + { + + char *pos = strstr(relative,".pcap"); + //m_current_filename = relative; +\#ifndef __WIN32__ + //while (*pos != '/') + // pos--; +\#else + std::cout<<"HOHOHOHOHO"<export_msc(relative); + //m_Controler->load(relative); +// do_pcap(relative); + } else { + std::cout<<"Unsuported format\\n"; + } + + } +} + +//Fl_Preferences app(Fl_Preferences::USER,"CSTASpy","main"); +//Fl_Preferences Cfg(app,m_current_filename.c_str()); +//Cfg.get("filter",iPath,m_InputChoice->value(),99); +//m_InputChoice->value(iPath);} + xywh {0 0 100 20} labelsize 12 divider + } + MenuItem {} { + label {&Preferences} + callback {m_Preferences->show();} + xywh {0 0 100 20} labelsize 12 + } + MenuItem {} { + label {&Print} + xywh {0 0 100 20} labelsize 12 divider + } + MenuItem {} { + label {&Quit} + callback {exit(1);} + xywh {0 0 100 20} labelsize 12 + } + } + Submenu {} { + label {&View} open + xywh {0 0 100 20} labelsize 12 + } { + MenuItem {} { + label {Expand Tree} + xywh {0 0 36 21} labelsize 12 + } + MenuItem {} { + label {Collapse Tree} + xywh {0 0 36 21} labelsize 12 + } + } + Submenu {} { + label {&Help} open + xywh {0 0 100 20} labelsize 12 + } { + MenuItem {} { + label {&About} + xywh {0 0 100 20} labelsize 12 + } + } + } + Fl_Group {} {open + xywh {0 22 1035 22} + } { + Fl_Button {} { + label Apply + callback {if (m_current_filename.size() > 3) { + std::string rl(tree->root()->label()); + // First clean inputs. + do_close(); + // call do_pcap with filter. + std::string filter(m_InputChoice->value()); + //do_pcap(m_current_filename.c_str(),m_Filter->value()); +// do_pcap(m_current_filename.c_str(),filter.c_str()); + + m_Controler->load(m_current_filename.c_str(),filter.c_str()); + m_ScrollHeader->redraw(); + tree->root()->label(rl.c_str()); +}} + xywh {401 22 70 22} labelsize 12 + } + Fl_Button {} { + label Clear + callback {if (m_current_filename.size() > 4) +{ + do_close(); + m_ScrollHeader->redraw(); +}} + xywh {469 22 70 22} labelsize 12 + } + Fl_Input_Choice m_InputChoice { + label Filter + callback {char iPath[100]; + +Fl_Preferences app(Fl_Preferences::USER,"CSTASpy","main"); +Fl_Preferences Cfg(app,m_current_filename.c_str()); +//Cfg.get("filter",iPath,m_InputChoice->value(),99); +Cfg.set("filter",m_InputChoice->value());} open + xywh {36 22 365 22} down_box DOWN_FRAME labelsize 12 textsize 12 + } {} + Fl_Box {} { + xywh {543 23 489 21} resizable + } + } + Fl_Tile {} { + callback {CI_LOG_DEBUG("Tile Event"); +//tree->redraw(); +//m_Editor->redraw(); +//m_Sequence->redraw(); + +//m_Tabs->damage(FL_DAMAGE_ALL); +//m_Tabs->value()->redraw()} open selected + xywh {0 45 1035 810} box BORDER_BOX when 1 resizable + } { + Fl_Tree tree { + callback {Fl_Tree_Item *item = tree->callback_item(); + +if (item) +{ + if (tree->callback_reason() == FL_TREE_REASON_SELECTED) + { + m_Controler->select((TLMsg *)item->user_data()); + //m_Editor->scroll((long )item->user_data(),0); + m_Scroll->redraw(); + } else if (tree->callback_reason() == FL_TREE_REASON_DESELECTED) + { + } +} else { + // No Item forget the event +} + +tree->clear_changed();} + xywh {0 45 300 610} selection_color 23 labelsize 10 align 65 + } + Fl_Scroll m_ScrollHeader { + xywh {300 45 735 70} box DOWN_BOX color 7 labelsize 12 + } { + Fl_Box m_Header { + xywh {300 45 735 70} color 7 selection_color 40 + code0 {\#include "HeaderView.h"} + class HeaderView + } + } + Fl_Scroll m_Scroll { + callback {printf("Event : Scroll\\n"); +m_Scroll->clear_changed();} open + xywh {300 115 735 540} box DOWN_BOX color 7 align 65 when 1 + } { + Fl_Box m_Sequence { + label {Sequence view} + callback {printf("Possile if handle method is properly coded\\n");} + xywh {300 115 735 540} color 7 selection_color 55 labelsize 12 when 1 + code0 {\#include "SequenceView.h"} + class SequenceView + } + } + Fl_Group {} {open + xywh {0 655 1035 200} box FLAT_BOX + } { + Fl_Tabs m_Tabs {open + xywh {0 655 1035 200} labelsize 12 align 65 when 1 + } { + Fl_Group {} { + label Traces + xywh {7 680 1030 175} selection_color 41 labelsize 12 resizable + } { + Fl_Text_Editor m_Editor { + callback {//m_Editor->buffer(m_Buffer); +printf("m_Editor what here ?\\n");} + xywh {10 686 1023 165} box BORDER_BOX labelsize 10 textsize 12 resizable + } + } + Fl_Group {} { + label Preferences open + xywh {7 680 1030 175} selection_color 41 labelsize 12 hide + } { + Fl_Scroll {} {open + xywh {0 680 1034 171} + } { + Fl_Group {} { + label Ports open + xywh {20 705 300 140} box ENGRAVED_FRAME color 48 labelsize 12 align 133 + } { + Fl_Input {} { + label {CSTA port :} + xywh {100 725 96 22} labelsize 12 textsize 12 + code0 {o->value("2555");} + } + Fl_Input {} { + label {SIP port :} + xywh {100 751 96 22} labelsize 12 textsize 12 + code0 {o->value("5059");} + } + Fl_Input {} { + label {OTS port :} + xywh {100 777 95 22} labelsize 12 textsize 12 + code0 {o->value("8894");} + } + Fl_Box {} { + xywh {22 818 293 25} resizable + } + } + Fl_Box {} { + label License + xywh {349 705 267 140} box ENGRAVED_FRAME labelsize 12 align 5 + } + Fl_Box {} { + xywh {630 708 29 126} resizable + } + } + } + } + } + } + } + } + Function {make_prefs()} {open + } { + Fl_Window m_Preferences { + label Preferences + xywh {1360 53 370 350} type Double modal visible + } { + Fl_Tabs {} {open + xywh {0 1 370 325} + } { + Fl_Group {} { + label {Gérénal} + xywh {0 25 370 300} labelsize 12 hide + } { + Fl_Group {} { + label Application open + xywh {5 45 357 270} box EMBOSSED_FRAME labelsize 12 align 517 + } { + Fl_File_Input m_IconPath { + label Icon + xywh {42 54 293 32} labelsize 12 textsize 12 + } + } + } + Fl_Group {} { + label {Séquence View} + xywh {0 25 370 300} labelsize 12 hide + } { + Fl_Check_Button {} { + label {Display port number } + xywh {145 33 20 25} down_box DOWN_BOX labelsize 12 align 4 + } + Fl_Spinner {} { + label {Timeline space } + xywh {145 53 50 25} labelsize 12 value 150 + } + } + Fl_Group {} { + label Ports + xywh {0 25 370 300} labelsize 12 hide + } { + Fl_Group {} { + label {Port numbers} open + xywh {11 47 345 275} box ENGRAVED_FRAME labelsize 12 align 5 + } { + Fl_Input {} { + label {CSTA port } + xywh {100 60 70 25} labelsize 12 textsize 12 + code0 {o->value("2555");} + } + Fl_Input {} { + label {OTS port } + xywh {100 88 70 25} labelsize 12 textsize 12 + code0 {o->value("8894");} + } + Fl_Input {} { + label {SIP port } + xywh {100 116 70 25} labelsize 12 textsize 12 + code0 {o->value("5059");} + } + } + } + Fl_Group {} { + label Debug open + xywh {0 25 370 300} labelsize 12 + } { + Fl_Check_Button m_DumpHex { + label {Dump hex in console } + xywh {150 29 67 25} down_box DOWN_BOX labelsize 12 align 4 + } + Fl_Input_Choice m_Asn1DebugLevel { + label {Asn1 Debug Level } open + xywh {150 51 67 25} labelsize 12 textsize 12 + } { + MenuItem {} { + label Critical + callback {asn1::types::debug_level = 4; +m_Asn1DebugLevel->value("Critical");} + xywh {15 15 100 20} + } + MenuItem {} { + label Error + callback {asn1::types::debug_level = 5; +m_Asn1DebugLevel->value("Error");} + xywh {15 15 100 20} + } + MenuItem {} { + label Info + callback {asn1::types::debug_level = 6; +m_Asn1DebugLevel->value("Info");} + xywh {15 15 100 20} + } + MenuItem {} { + label Debug + callback {asn1::types::debug_level = 7; +m_Asn1DebugLevel->value("Debug");} + xywh {15 15 100 20} + } + } + Fl_Input_Choice m_AppDebugLevel { + label {App Debug Level } open + xywh {150 80 67 25} labelsize 12 align 132 textsize 12 + } { + MenuItem {} { + label Critical + callback {cid_level = 4; +m_AppDebugLevel->value("Critical");} + xywh {0 0 100 20} + } + MenuItem {} { + label Error + callback {cid_level = 3; +m_AppDebugLevel->value("Error");} + xywh {0 0 100 20} + } + MenuItem {} { + label Warning + callback {cid_level = 4; +m_AppDebugLevel->value("Warning");} + xywh {0 0 100 20} + } + MenuItem {} { + label Info + callback {cid_level = 5; +m_AppDebugLevel->value("Info");} + xywh {0 0 100 20} + } + MenuItem {} { + label Debug + callback {cid_level = 8; +m_AppDebugLevel->value("Debug");} + xywh {0 0 100 20} + } + } + } + } + Fl_Group {} {open + xywh {2 324 369 26} + } { + Fl_Return_Button {} { + label Ok + callback {writePrefs(); +m_Preferences->hide();} + xywh {239 327 54 22} + } + Fl_Button {} { + label Cancel + callback {m_Preferences->hide();} + xywh {290 327 81 22} + } + } + } + } + Function {readPrefs()} {} { + code {Fl_Preferences app(Fl_Preferences::USER,"CSTASpy","main"); + +Fl_Preferences iconPath(app,"iconPath"); +char ipath[79]; +iconPath.get("path",ipath,"/home/aebersol/Devs/home/home/parser/asn1/cstav1/images/",79); +m_IconPath->value(ipath);} {} + } + Function {writePrefs()} {} { + code {Fl_Preferences app(Fl_Preferences::USER,"CSTASpy","main"); + +Fl_Preferences iconPath(app,"iconPath"); +iconPath.set("path",m_IconPath->value());} {} + } + Function {show(int argc,char **argv)} {open + } { + code {m_Editor->buffer(m_Buffer); +// Only here +m_InputChoice->add(""); +m_InputChoice->add("not(src and dst port 5059 or port 5080)"); +m_InputChoice->add("not(port 5080)"); +m_InputChoice->add("not(src and dst port 5059 or port 5080 or 8894)"); + +asn1::types::debug_level = 6; +m_Asn1DebugLevel->value("Info"); +m_Header->model(m_Model); +m_Sequence->model(m_Model); +m_Sequence->tree(tree); +m_Sequence->editor(m_Editor); +m_Window->show(argc,argv);} {} + } + Function {do_close()} {} { + code {tree->clear_children(tree->root()); +tree->root_label("ROOT"); +m_Sequence->clear(); +tree->redraw(); +m_Sequence->redraw(); +m_Scroll->redraw(); +m_Editor->buffer()->remove(0,m_Editor->buffer()->length()); +m_Controler->close(); +m_Header->damage(FL_DAMAGE_ALL); +m_Header->redraw();} {} + } + decl {Fl_Text_Buffer *m_Buffer;} {protected local + } + decl {std::string m_current_filename} {protected local + } + decl {Model *m_Model;} {protected local + } + decl {Controler *m_Controler;} {protected local + } + Function {callToString(const std::string &ins,std::string &out)} {open + } { + code {int res = 0; +for (std::string::const_iterator it = ins.begin() ; + it != ins.end(); ++it) + res = res << 8 | (unsigned char)(*it); + +std::stringstream ints; ints<type(241); +o->begin(); + Fl_Group *g = new Fl_Group(0,0,550,400); + g->resizable(o); +o->end(); +o->set_non_modal(); +o->clear_border(); +o->resizable(o); + +o->border(false); + +o->show(); +// o->flush(); +do { + Fl::check(); +} while(! o->visible());} {} + } +} + +Function {} { + comment {// Main entry point} +} { + code {MainUI m; +m.make_window(); +m.make_prefs(); +m.readPrefs(); +m.show(argc,argv); +Fl::run();} {} +} diff --git a/cstav1/data/double_appel_csta.pcap b/cstav1/data/double_appel_csta.pcap new file mode 100755 index 0000000000000000000000000000000000000000..3efb82857de9670a423cd267dad1d90d2ab8c41c GIT binary patch literal 8272 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 Z2*{I9Mfy~1uZwhRB8rq;7P@^){om29tBU{t literal 0 HcmV?d00001 diff --git a/cstav1/data/ma_change_filtering_level_filtering_to_screening_csta.pcap b/cstav1/data/ma_change_filtering_level_filtering_to_screening_csta.pcap new file mode 100755 index 0000000000000000000000000000000000000000..54818316dc16bd76afa7bca82cae31eafc446c8f GIT binary patch literal 1248 zcmZ3u>F^Z>CI%J;IQah`$YcyqzOBK)nRE!q4uE2~3JwNW1_mcH76%3gHpiE1Bu%|R znDh6Xv%;*OYlQlnPBlnyv>o~jG=`Cbi!)Z9nKNePb_Sk>Tue+7(M*gcT#QT*^HVy2 zhPps8s`+L)-XQb2*TKx6bC&Zr$ZVh;T@4aEOou)qnGdvsffs7#SD-;oP>gD(i5V-{ z&EH^VLfza2H1|w{07sknFH|!jCZ;I>jq!(KR1+O@e88?;1Tzup$}@0R{(+mw0t$&m z+@LTpU1eNDjUUcJONy<5_?v>M$^8ZU>6WK``9C44`OZ z6bJza>+@OlKxq)>{M`{f+5B<$WbX+rpkVzEObU=_)0O6o`TmOG*22c?OpMG-jG_jO z=R!dVMWKO-aiW178=E#yr&)Kjfk*=r^NU8lfTGN@#FA9UoMa%GQ`@)@qM*5irEwZi z0|Nu|XOLzfwn0vBKt4r)iOJBwkVF$$n3!JywSYs5g;@;9#1a0RGeP0s837Bej%d!` zppcqu{v^FYfQRYgEqG`-bH?gQLrv@lit0l!!e!v_R}29snCBfZ6CvUMBpn|9q9`Uh zGrV5d_yQLG_elx=O^EPcjvD?94CV-DQOY7K{6PtTjhT^wfrpccfsu=efrFb7$b$yo aF+35H1&)w#SnwetfLM|Ld4L$%-z|z$K literal 0 HcmV?d00001 diff --git a/cstav1/data/ma_change_filtering_level_none_to_filtering_csta.pcap b/cstav1/data/ma_change_filtering_level_none_to_filtering_csta.pcap new file mode 100755 index 0000000000000000000000000000000000000000..8f6d3c9b9c763c3a35c879b9781a274e7614d5c7 GIT binary patch literal 34393 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 BZ!`b^ literal 0 HcmV?d00001 diff --git a/cstav1/data/myicoffice_monitor_sip_transfer_call_withoutsip_releasing.pcap b/cstav1/data/myicoffice_monitor_sip_transfer_call_withoutsip_releasing.pcap new file mode 100755 index 0000000000000000000000000000000000000000..75f257b911d9aa67ad97798ce4d240d601f9d115 GIT binary patch literal 122429 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 literal 0 HcmV?d00001 diff --git a/cstav1/data/myicoffice_msip130_make_call_ua.pcap b/cstav1/data/myicoffice_msip130_make_call_ua.pcap new file mode 100755 index 0000000000000000000000000000000000000000..42d802cb1dceb386f6b985ecd662fd79bcf2c0d6 GIT binary patch literal 70092 zcmeHw37k~LwfF6wVVQwJ5EuMha-B~N%JlTTy?4(7L(c#svpEZbOR%T=_Ryg>yL%Q; z%)}%PqCRm=@;;3j%%U%fsA#|iqqsnfFD}W8zu$WeQ)Ir%nw&u=Nj|kt^nue+Lf0pO?0YyVr5thv#yfv6MW;oPit9 z4c>9xDQz4#k!#=#`~Ke@bGSL<->}?sl6~PlCkgAzw;Z$c*iUzL9RKTI4YbWTwe2@E zIIgTz^mmt)R?i-Yg!w)xkqpJ6HRWQZP|izHe=HD+_SBSjb$(S!*8B6q-@ei{k7c`e^i+V>> zl+vRV9Y}_hQvLn?mHk%o9g84{=EcoT9fSr`D4I<9qJD{ea3C2Nxm3BTu5)976}8pT zr09{B#(^I);gC>M-kXSe{IQ6~7xw#7QrHtqB|XVlFcn`Gi^3NfUp$PL9jO&zN%?#p zF0rcCR-4mbh93$dr7HcKwMZ@L8ASti&`WCN2Ybew_xHYTp*@3}S@Px_?(*@Dr?FRH z?>J^>`4;RI$A0?pnQc=K9N4#+bvHn}iyJ@X4ftJ8pQ2(wlmB5q<7{2~u%EsA+;=$6 zfX@a~`IZ-iW6%BFI~%_Jqv;0_K>ow#~)T!Z;tf;r(HlK8sb9{7)F;YGnCT0IsQKTCj|Wu@L&G%ER1FgiW_a!HDteBn@^R94y{ zC1BKg_}D;x;l#qh40kgHz0k6wS>->Hx4&TtVSOuSw22$8|75q8obE^1DYlKPx8ja>R zHTj}Fy}ll3YWQYvvON~C|(hef??=w%4_d3Um_{NcN;reO)i(+ zZ4xVbQ$dr9z&I<;q5mx_U5Fj74m%w1Nd){{y%Ew?9gtC9<)cGzm&d9KS#zibar`62m3n!4rD+hOnai$ zX1Cd4ezb^|ay}J`NU`2jO}Q0j`;4)l)&^kou*owy53@YfGyE&J!fRYRTV8DGWj`mY}~vfm+cj zRGTpu{7rI1eG#cP7WMkVVQ)f$-W;IsNxD8qGw3hDP~I%x# zg~B;ABTem+Kb8oLOc~9Wtn)9=L%y7;9*D?YPtwdCy^)A7v7##;$itDjzGTSX4h;_C zuOkH+Vf;sXwACTJPPYR2$r=bHDD718RPfeW`KE%kZ;_et4JNkbnepx7^<{m7Q;*~3 zU#St>pTSgcFK66v4PZ9WM?V#C)oZRo%m=Itb3=9cmNVXMx)<_uKQ#`{=z9%x;o>=y zi;bvlJUa{14Mj!86#ITR{LG2Xafn_02*U{kFg zr-rmY-i$>q)j2F+&LR?DkCKtyQ|BgO-UKBsJW;J5odw*8U8551h z`xQ(R!OS@=w)952r9@#;#7Wq6L{5qk-*Txw zYE-|Jm6MfOF3%c`E`iOUB{M9#D9h1W@*F~!j|%=svnWiVu$;BH$t)UWBNf#N&|~Nl z7YI1=G_<#f4o>(B*bOb;rLDiaPuu%*-1Qx70qf~73 z4oMxc)2z73zq@rOjCR%v$$y#cg@54{NR_YL<%)ajIsW=QwjYR|0BQYVl7r zL;MyhHhwScrvTOX9gM8WoO1glxN ziu(%nDhpUwj&9QfoB!E_FH6}&q*r0{9GoIW%@HuKguomDwtBj-KS)I?AffuzC>to0 zU)6pfPm-u~l>eqGlZx)q>PW>uct5X>)IoHl7!!6xM*=~2#=BjY;re<(di{rj=}s!_ z-a)H72t0iB!j5z7@gnAe%Ngbyx0Za~x8t3c`nC<9FgRnfasN4ruzR#@?t$XSTrQHlurt}qs zQm+vC2K$_<3cE-Zrf5G$ zFeg0H3bP6r9q`dtq4;c1Ct~g&V3?W)oN*jyJdI&K*NY8!7!^{N8?4H?jJgGdG`B*E zwpn6J8?~C3R}6t7rXW_rMx{oX1pQ(3s&Dqs=4GNM6988csUbgqSULu@Iglhrw zV*2QX6W2WSABeeeKf}}rJe&z&SCsDQKKDluPLFaYt~(wjtZ)p-*yW{H8o34EE9Oq+ zsB|q6C*`Zao(B9_#bzG@Cxb;|hh zvnF5d_+F~`*dhbRO>Xpdwsv_JkPal*-v!fA?grd5kJSG%MyouTVf}|l{Ur^pf1>qo zLiOOs^vS6I)sc@8v*cmw{9#{M^7*q9`!8`_*mu*UD+gyxylN{LtK|m#pR&ETe!+DN zpJy}_r7LeZWR+iq9xBjS_~;2W{@3-_aon6~XFkaYo&M_dt;VOGxvjBfQDbKVpA5xe zCtR4L*;4b^1&7_vcQm3M1~*W{;aETHW0E2je4Te;1@EnE@isJ7@N<_mRPe2BosF$6 z9Tj|AJ9*jOFt4G#f^TWR@W@7*(PAIj)L#rw%RVAB*SU1RLYK#VB9=;m=O?;T(Nr4sE6N2s5MAR3q zh1nbMSuVme)qZwu74M5C`(ZQN7lZ=1hu8^dI@Z#yZ^GHK(s>E+YRO7bRm#^><8t|& zqTAXnx*QgZRrJ|>KC8>(vIK%|pW81&4be2_^TXzHwVoPiJeN?FN&rd7?3%9nHidp* zk43U|2i?J-%Mq|U+=3H!crEUL-|Y-Qvd!mbJwaxVw?n!VcR)pl)e4l@lIqq32bBrKxWy4BxqdR$toEH(Pa23ee}KFu=e_Y!(RW*@k+1XI{j6{4=6qxK#^L#S25OZD+ZGzIiyV~jq;i&o_;XAXxzTi}?o!YZ2XL-aPK%n|T zrChqSO8=-ON`}v7vsvs8u!vG^gci^#NHpsx^pQh7hpC+d7n_f^016`9*sPlF?sb%1g@)AZfo3+iX{TahDo(TL;Db#zepb4{LlfD7|F;2Z*`tEruym`h6m~ zfzqufYcYqa=p`9>m=Ed$z2XZ74&E2_iikEduWU ziK`!;n>Il>nF&G?rmIa5vhiWniAtr*veb5_n6I{b<|AbbRx-*|28S2W;Lv@#Qd^*G z+alV6?zMn9M4yb>_D4QN%#vraau5v;aQc869JXD69OUYTXUhf$T2(MO98^`^Xa@mn z20j^N+17uEWNp_Efep~HK1G$_?`Lbsx`0-7b`{_S=#zoj8QDXs`kt<;pTYpxKx`|= zD3}*PRWIO9TXza{SK&nHu&a($+HE3sR{SS_^Je%ncRhBIdQ4{Dlm`gZ!#$nUW1Qxj z7Xjvd+@u;X@D+E`N3Yrx*Pnb3sy3Irq*iT;g;N4-ZeeE>MpF6;S`94b{x!6ke5*#q zh(=6mIulwmIFi)O2UA-|*W3fivFlM*rwvUmeQ48) z)tGpJx4>ul#x@(X_b{*cWQ{l0i}tcMUuqdIf60p0Lw`;75~&)2hu4uBUvB^m3Rb7X zY2(}B{7&5>uqFvkI1Ay154v5vi?>1om;rq?zHrI|r+au0|Lv5eNor^fz@dfy`fz(V z1X(Kae>aRt+p4~Q98B)hr5Bf!?R`)F(=63q%Wf`}5J=s&+_5&u%WJ(_(Iv6feQX0%9 z>mo)2CoD4>xxWhC!X?Gu5)QyWK*xXNzXnWzzYGS{!EQR|rdjwHI4B4DoCN83^c(&Q z1!hd0KRi`+pc6sBUd^38)&A;>aA@}cciix?M#ITQgHgR+kShjjvfRpL65{%n#gB}S@L;S%o!86KlOJlv$zRA8#j)-(tz49 z%qpK8pO4`6WC^-m*Jma>p(Rd1ZTLN9xuzm`iV3VN+_Ut_Ao$^-dy(LcH?l>Myj*)h zS+4zuLhuK;DB=c(uShS~l4Q9yZqQIH%u?77%|@1Mg5YCY#;|iN2m#}2uEk(1HJq@j zN?8twxOqISp?PUbYfHoB_3h0|n_9sKLA|&u8po9`4uh%b@;K~?Qcg`VU6qehdlq1= z7OY^kN-y=+wc=8*Evc^6iysi~PpN~YDR(V>GB|bl(0anD=NTsD)VfxMQ?SIROT8C& z!`S+On>Spa=9HUpO1;`kb86K|3P+B~T3_$SdF$Iq>Z^EFsp|VfQs2`xwC$$#UAP=D z+v$^0-?@>$BWB6pbY1zBzMEipU|0T!g83=bcL_InT`3GiVH^y_adImy#D151b@vH= zVf#e(1u9uce?ABM^Sj_dCUX?O@F}JGJTz(ikUkky4-MT%TImU0EB#PurSus28({9{ z&Kqt`w^BVbKa^@cAQayR(ve#XMc9e+*dp%ZrnJw@SM@#Tk_PK%WU3nMFW6wMz&N?; zNao*Y)x&(gsz>&c2D^{3QRSQf}{6N_$r`%$G_4^NVbi&TW1gRi*EEAz!7}6N}My zMH^AI^lwQ^N7MwqR6;9#7iuHFqfbUlKQ?qfY3bFBk+h}nbSf>qLBX7ajO4Bw{_gkE zO+CPxdh`<(8S8Tt@$4AYgq5R{+y%2~Zh5$;iFA@)RyS2Ac>+60%QNb_y)=pP>y=wW;SSO_iaSYR97A)lS0GuG82jOK8Rr!cRcVetw zz)k|!tvZ;$z!wdGf0q_G*sl#)G;-7h`ItkH#)%*v%FIbOIcg&5IXA(PL8Jx`%tWI` z%{`LOMaLCQT#>k`j)=PJRnUnIN$zAWu34 zOQ07PL>(dizN(*y3-5a2s9oLMx|VuS;p?mMn2DUoio%%ik?(|}p%k2}!<|J5j*;L& zTY%H1%AnM7u+|A4#uQLaAg^JUIVIJ$H@3`&|1WLr>YU#Sf6$!tos1Iqb%S42DkLQd z6FguEjfA3DIF;yyW55WVPGg@^mqG%u`br(bQV+#a4!}^J0g{qJz8;a_gkWu5SAAnE z1*QpKt^$EXEUu!R{LDo*r8Mb@`x2>;KNJV=IZC-I0Z#Lv6F2ffn@Y$`K}@CE`i4b~ z-Ugb7B#>9?1Jbl15h8s|pMHr%D3KK=ia=wQ;P--|L^4G>ovcaG4C!R@oj@oV5BpZA z^YI!$bp}!*7vHfZRdoaclX8oBed-oR+LV^e(zb|0-)qZZx^8G8U+Iyn+UnE6rLm*4 zt{JT8^sKr~w8IFs3wCgJB-~;-6&x1Ig^-#ak%ch|BU0UB8Dlge$G~YiYR0OT;-rWD zZYzvk5TYO%a1-S z!NHE4;>hp7T-b^(Y(>Kkw`MCEWXxS)E6lSM4MsEAioStai3(fMN4X1bVJo_@6-_)} zM(L~q65^fOd}g%j2%5aOE@twg;cLtK#$B}O3p6{HoW#s%FI&p?zKkcmHgLsFkLJT% zb1h;%U{^3n02%po?zG9qIY1G$cfZ^OUZ8k77ckp)=fm`LA*M0HFlp$3qWuv2;c|?Q zY*K9KFE<07O%(IIALqkda~+}6#xUhm#FxV<;saQByI-NR1u&Z_rVm2*<~HM2M+rYW z6-*KiSmr0xeWJ1l{BnDmpFwb+%#FGB9mM?AYYdZ`B{zKmaV7h)?wn%wei?k4Uv8&# z4*nt^W_66v*}*X7cJGIF{|DB6B9xZf2z*yxMvvwV+=NHB04AE~;nABK~s8_>(YJ zh*g;m;rxo3VCIZfSqR}=2;p1^;XG0ZXJ+nJE_5h_a4v*!hN#-w z5Y8~oJUt$!nVeoJ=T1bi{mEuF6~I)B)67{jr|gPi7|zcX)rE*{GfV~db46Ru&1>k{ zjE0_zm8&Q4IA!6?fqo%I9ZYGMi+}l(l!awnVHr1;WgN(uC${D_^xVjyp=WKu&{H^- zR5+Ey&KZ4;P9;6a8U5h3$PLpcW08A9Lk z2Y5f6eW3<(#^mSIr^8=cUAFhNAudi)W0ipT5PdRGe?Ig8vUcN7n9?Y_B|f3JC4v=7 zX6+ha?IbQX97%g6b~CTU@uPO5Ctiu?C|-%Y&S5^A{~@qDb}dvOC%gAFVH~#60fbHj9GmaV1oGxpA5$Qbm&3Cm~{-3GUjK3!kC*C%(cMoHQcv{m!%nV zF<}gxFBl_Z&Qut4vW_vjlLWw%)p>nb_p}h6BpLlGp4^5!vAw3ye*@6Jmhhy=@Nhmp zNB)7BCHq+yl*i$HFb>^#@Z|U3P%t+D=4y&*bO7c?`eg9=XX}Z#{x;>rq1>(A{g-&| zgUEl+Z(XXv+^{Z+BU^J!2gfYHEC0rDOlPDKf8c;zhra-N&i)tKPx$hWEPS~e`SPD| z3|}5Z$d?Ti^OTbTGv~mJ93Yt2WW|J23|lWzFds(DYy%VAU&q-0#yT*I9s)~ZZpN%9 zp8Xjz>+b$bs(6%x+uu|w@j6uEVak{fs`4#K`I)#Ry{N0;drw{d;hah@$LhvP}F-N5w>OX=mo1#I0U37X}pd~i?j6uV6NRjQG# zQt|Y;ec>u@l>r|Ee1;o$+659hbuKSYi*G!TPc7Tiio`ESFyhl|gP)JXwShIHCjNCi ze*_G<<(+&CiIPq35=D=vYlA8t)&_UusoSlK70eTXA+Kj+2szYuco=ePLq3MACnplO zb4=dLixAXPuSPv}o3dDX9f*JZM9Pp&pw<_iFF*Pl%;sMY3q**N-N-O8Qg)H`*)oV| zt&inA%KZaX0NT8fXAdSgWVw8lfgMpOmjgcP;y03L(4cp!!zpHsu+1VU<_IHn6i1YV z_8U2JXh!^-fEch_96`Us=C=FoF1OF_@LRh5c84VxbozYVqX}1Sv8tmd!Tr!axEd^d zD8sG(QyU{mj=nwmph|K9y)p?Q#vpvE98*bPL6p*do#`k>c_I>JghYaCh9i>4N+KFX zd;|2S8-CJZ_P7W`>~`{GhI+nk=`}damfTH;nH=hQ#gh*ol3{k}<2)kiVXTb;3Ph*`9DJee_z>gtBu>Q1SSy`j+Xmivry0 zIS!N@S!>z>o@M4S9#VE6ibKkx!vaCA3x|~TSHl+$Df`NK)gfikDF}9Ju0zV{Q&?~S z?8~2k^foorwf|GkDA##A8yCrkXTQwJWIWJ@3POD<5>%c4Rg&o0*?<1A$WhlX>%nEL z)v{PPpsEr1NzU;qbxR-BR+4g6mmQm=2S0P28HBH@4g!D8jzBXOX-}3O+%ZaQKX$`c ztw-TW^E}+K^fxa{-aK{EBcOO zFkN; zqdjoD`pQte0#>30H}`^@`$%r?Okpaxxko!$bPf4(lH{8Z)gz1)0xUa}dChnXQi_%XDm(U-fm(VLQn7+bW z=+SaoxP?9(i%aJ6+G=*A{oGgpqlU4#Sx3M%^g1&@`X{-Fo`os%L(DGx8y6*V%rBXC zl$$YMT#EL2Xyufj4beUc>t8F2r`;g2a_Z9OmZEt2$GNQsGWBwH|(IF5Xy>R9l_nb#4y^vwblz!Z|4fZ~f(i)}q z1ao*gT$J2mG>lWb5z`O-B#@W*hY9hM*oV@@|CwyE?tEMOA&R;EY?xKX(??Hy(f^)1 z2{Cu=VVIhxgCLIvsJh&Ai?Qi4?58YxV^2qG9p1+4)L;0Kk_J-dfk?OtEM2}tQcBhI zrh+C{Ivcy?&t(It1G^bfn9@VBC|uGE5CEi#)6c%fT60x)Q4} z>0c&Ae91~64aY!bEYU-HzZpgY>H20CmryS19ZgZXj8TdXBtuH6{{H^Tek=J7?0Sjj z#m!AL%%h225XwFXH@}Zuie*+^8Lufc>L8I|xuD_Juqi`+sc;EB#_n4ob3=~AS)1-y zR8mHhjs7HPQ`U6Q#CGY>-a@awJf7W5uTE1*bN1oU-6#+G=5`36n_EnJDo`pIZ)H+} z>YJZzp1JzYCs9nUEmEYy5|9duiKLlgeiSev$`?L*NyB-EevOzLKWCU4>4jp_sbFqI z(aV*sn}mWAqo~8h0Q3{W@%hN!(~h6e&l!In2a@)?|? z_Nt*xgzVqw$Ud%b2MApx`%(q-VZ`L-4>zRUay-l}r${(KE$(HvoE8I@FLwH4+!Xs2 zc`MvODja3R(W!@2_+qT^dz&@Hp*J*O&c=4iS>dPwF-zo|j@iZWRaYx+H!cNp6MC*> zt1!6T9BhT>oSCn}>pw^0wjE$DFeCi;VLReLZ9SJ4M--B!uvw+b%M7e;?oI}C`}{mG3^V+! z#@g4ixo*IBiSH5gHGfM!;XAY$<=aNxogF{FILmDFB*?divk6}~BbH0}7L735`1j-! zzI!^6xCKhoDb;NA3o_fl@<Wv%q+@7_3C zt_9JzwZ_-ZZLb}16;gKIhPUWBw!eQcKvr0+mb(DHlsSX^$K=n^c%vqw*S zZ8h|H`A!AR)-8RZBNFqblSt77S!s|O(Lcf0OLRE|i(9bSL>qc6B|XX;tat*Lkdn|h zir$ryzKtS%Nd*iRV! zCAc{TMSQJA5G^LbWwHpJg3BXXJyz=lq)0joegb_Mvu3xsXm*x?Qk?9U63{1Q7eJ&} zP9d-T%cHS=*z$*Ma&?{5$(Rq0`SirV(IyR}q~L3|RYWdAN&m!G68LO(heOF_UUJJ# zSIfed*7I9PwREpAcLI#czNAF+&TDNyAFhcb-ln=&n3vpALU_$?h*76ev_J^@CioVp z>ITeUiPdK8@vMuJA6dK{V7DuCSe>467YU3*hv*QkWE`sHW^FafUl@d0JQ?J7=|M+? z1<9XIqvbOoJ&{l{DFwV>Q%SaTqw^q?(Fbd&C)^p7Et%vcUpe0g z7yc-Xjd?Z6BqQ7r1%~StQU9_8jG&c1+qTare4>E7P4mU74Di#~t&M=4b2Ij4AEEma9o-uN|8{h2tN|BHx=Js81#u}a z&U+Oc8zC4GK6=e}+_am!5%bO~vtpuSqheSu{sY0x>3`zYDPRRRlq1v)rAJDkKx!vy zLvrqldBnHstMf^**&PL+6y3%&%w|oogIr!fSBe+MyJl;d-ni4%4=mB8%# zia!K8A8pGi*b9N#3m)qQkM)r})|uHsG0YVLvljxhXLziG*xq3XKgvI3LP#_oT*GND7HVOQ^98^=EFR9GGc!6kO~t{Qs4O`IB`CL_o{sV_X_5I zz?~ik(ukGNt*|0%_kA5vO z`>KX>5p&a-3{x|;f)&2zGKM*RD`5U1!wQd@j+B6tMqk=vQFI6{&`JwFi(oV#qt7DR zL}lY*V*qVG2WKP)B`}*73oeWqAE*QhnH`-t?|GrD?a+KS16MpWxUy270dGB|@OfPv zkxSN`ia+x^R2XUnD_jzS$arG`skWob>uu=hkbM>@lInG}rj$RH0E4@dWRuN#8D{Ei zIkd%;o~40H8>$uawF)ZzR*j`tt`&2(s)+JZT|#ZX)&)RPvB9P_bE`nrrfp)w&hbwD z%`7%Zf)m6EbH=68fd%C=Jpf00+tuCh+*)u+)yisTO%O^I_46lM`$?B|8slOiV z@A9^XCcEyH3P@+LS8VyYv#39*vF&FotI41)nPKTyeK7q_T|#B#&t$jirK;j6f^@

J)F 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 O0000-fw4TXSzA}qpmimiCWDhFi{K>Z%oR_ zi%2s{f*?r?l!7pdFe3=Go4_C=42-TMiZDpLDT<&UgZv3i#HNzX`8T(@Gtc?DP(wqc zdf>Tu-}iZcE}oY-=KuhU?s^4?`KK4JJjXwP5fQ~pcV6jv`guup-KMA$&W(iW)!D~4 z9AFU}%D5^IjLXONhBPBL5t4mG*;=E%u5eXER2=OR@>+<9*~G?E6jy4DmFo8!br;=& zsBYaMGv7D>%!IDB0f1d>y{}m^mDt4Q#wqzii(M>l8|%=U_SHnXhgu!;#=um(UUi=# zqR%YM#yfP}SsowV^ni9Hrczpxdx=fw%v##cG7SzH%#|lq$PULIKhJQu3%KaFYIsaZ zQ0TuJA+MP@=g>Ne@*PPzuT>U;wfGBoZzfVo$KYwtM2yjZq^vOd9;M;PJYKJ_fKpx!!(KU&wPd3D5&BHqqhM-@>PfrlgMqoE38)CCO z5dm=r!Zi4jnWAcQ^rc!{~s5fIo~_ z!Cpp??9;NgLy(rXpEJ%B7BR~U#8!1d@kt2uWWZJP4njO(+d(hloI02!0|MW52+=nf z^f5fZ`l>j;r4j(bPG{=wCK}XemrbQ*BFv%{7OfR#ahVp;2F<(yk85>cB~Pl~)OXzl z0D*JPDa$M?5hDNs04RtcpoE}Rf)G>*8bt?*MZwpvfj^?o^{zAnfB*pKnf3HGAbGvV z`~b#&N2i+(5C8a@z@~?s&(^900N|Xf07f^lJSw{@;5EK~8VsUgU4e7{SIlk6p9H}E r%(Kn5uEp@jiMo|b*MU~w`G4^XMOG(rnm>bP00000NkvXXu0mjfZz^Uq literal 0 HcmV?d00001 diff --git a/cstav1/images/Request_16.png b/cstav1/images/Request_16.png new file mode 100755 index 0000000000000000000000000000000000000000..053d6c49522edd799136d37c6b63193ae1f9f258 GIT binary patch literal 500 zcmVEo?+c zWu={^Y3u|=5Hu(O!A{iD)_?>QQYfTJB>^iz!A{Mdm%XvLd?Zmh$-uzyc=KlW%`PJ% zbP|eN;^5lIaz_H=iQzrQSR3E9z;HMmTs%&lwc?D3z!*~y(?fp=>}1nrLo;xYJ&6`G zH>Eo60RY7GP-L^`QRRTn0|VavCX3C0_wt%Q%nvY{9p4h4z+9n`L!juB0 zY&JP!0zx`@MX`mRvA-MBjX_ZnAr=gYmCj?2@0^dVDhtPw=yDpR?o>csx^MJw)FAbvRY q3_xkcT|edW{nL8gxbML_{mx$`vHjUWJx1{W0000Mv2sH&YX{1FF zAtJ?N4*|(Z@nl8xD8*hXs8Fy(58|m1T3HVUAt7EWwjQE~HrVcJl5ShF$?m3EcRVZ! zW^?O@;qxCef9B15jEJzGzRC3?QWWKktu`&0>aJZFF6jq;^(H{{}6GYS% zYtLV#Ki-^(wBLZox3J(8i9mwDl>-6yAQ8dwf446WAIJTJ{s|aH2OAzXFOQBI0RYJ5 zctI3vTL8e?9N#m>U3i@?__zZh>Fct9-I{``j1QjtnLBSbhl(rQ-<2z#&%QeMB&Jle z9ge4`r|%7T2SVnbGW>^qaZ_u-;GFQEZ2$n4XI)%W<}Us0!z%#RsF`H)__32icS%)2 zss`&;k<-@@o7{!21AMl7j}}KAAWiEOK~+Hw4f?6yIN~K_-}WI~;(H6P&cFP%vHI;9 zHLOn5us)D>nkanYA>}!^Y_fGN=luN#1#im?Nk58$W2dIHwyM~u$Szm2X&wdJ0|1Gq z*_cwzc4=5h+>UQgri`WFxd;Hq$VmV7X!Ou60K8rA9s?AwCDKd5U?iD5_^wi6hAcB0 zAMc;C=k-`l+?1xY`kq@9+5Frb&(_x+tBZ^3Q+poUugU)b@a-QcRj3kS00000NkvXX Hu0mjf0Mim| literal 0 HcmV?d00001 diff --git a/cstav1/images/ResponseReject_16.png b/cstav1/images/ResponseReject_16.png new file mode 100755 index 0000000000000000000000000000000000000000..2dcffc0d668e684d7847d66a13b314831b6c0496 GIT binary patch literal 731 zcmV<10wn#3P)x`k(@n(jXxih|RJHmB_@fE2%&NSGYx86-M?!VSX$$om)D4_AcL@F7&nO z+D#oe@SOkioF9k(c^DDle?qfTV2rV*qWuMt8W>{|V@!w$ur-Nix0a1||E<|-jXgX# z81v!IZEbx-K(dr}FsImMuvEnE4b`iv#GNH2if!l%duM-+HdT)bebi$%C!`-ZvD@dV z4Vp~y$$Gv1Jpi~10;!fu=$x8>_u;9ys&sd77K||v5eqf(@DaItr>*-raDeA*S z!x2PH`VlCzBYvYFp5q22eDWc{fDUP1f7#>lE=|yXz9ug#Kfj!Ob4Yd@vfNiL3+OVg;<8h2z|jRq5m`w<@$;Ci|ZIp#4KQaR=>WFT=w0C9hqv42bq z$RN%^oMU?SJJx0mL6!lqAcWapAkG0ri2xv?(YFH^Wv@qe|CqpZUMECp9?#0NA+Ay2 zul|a;01s2x{*7B;8?T5f2sa4smV zr_;KJOOKAJ`r?||-F9uOq6lQSN58D85sQ}Y)Pub*+Ht=_+fD#;<`zB*1uQ}|R;#vl zcsR=2+Z*Ey16*s6s!gU<1|mXN+V<>~05vNsWA~JnN=CI__7ndlego>AJoa!^KM?=` N002ovPDHLkV1g46KNJ7} literal 0 HcmV?d00001 diff --git a/cstav1/images/ResponseSoap_16.png b/cstav1/images/ResponseSoap_16.png new file mode 100755 index 0000000000000000000000000000000000000000..8d9c1d2e5a137751f1a856eb20a1c46cd521492b GIT binary patch literal 830 zcmV-E1Ht@>P)K~y-6os(NgRACf_*MB^7&dfQEm(ej(F-@^iL`(`V1X@&5 zNP`Bcbis#+3Z?93MyVzB7Fc2wi1`o%k}o0zf`p3D1udd1CaMgsBpK|s$P5$E)+I%RL%_6-I&vo*nGXi z8m6O3rwAeMI5#)hDzd1;aG~K|{lQ~VhREovpTF4!UTit8A$)F(bS9rLPq-hkcgsvM zfjMLi)0^G=$0`q*2_}p&=yYYV2AWz(Lh$6 z;Aki^F$f=v+~+2i4n9yipH7)e%ud+ZvMW&_lAjBG7B9X`%4oJ9yhX zhM5c(Hv*aQ2-kF-n^2o5S!UsY&|Mn0BPBVtlealUI%CC(XTheI>uHtY3OR~LXhxId z4X&P_U*Op?if#bC0~abDM+X^BQ>OyA-44361nO{rxtyRL6(6|GFj5~>ZUrR%PpSsr z_tgX?rsnyqR?^hjp1cY<320REP7p+!w(7jssuva(0RW7#Rep8oaOs%2Xku-?d}vuf zpm;fMRrXgSKzg%s+SePfo;j=)V{Cl-N7Y6i2>{5icm7}f1focA^c2x7e*gdg07*qo IM6N<$f}GE2wg3PC literal 0 HcmV?d00001 diff --git a/cstav1/images/Response_16.png b/cstav1/images/Response_16.png new file mode 100755 index 0000000000000000000000000000000000000000..7e75e466315002145ebffc00999ba37bb5d38e78 GIT binary patch literal 505 zcmV}GCJ2Sl)D$$<5YZA8v1K;@$=ew5?5&i?` zH*tSzD%!dMV=NR2ul?1atzNj;+*s)9=^Sdw;BaOpG&nuEB(fQ72ZJ5W2IH>#1|nkB zC0^|$limG&F`3Pv`0@nBITX)9yRXnZ2kqvdIENv^?L#3L=iK!>I8H2&bPe>+8!2G5 zf&(A`ivSro<`c|lKq~|sAi$Wvv}C{->kWt39f!4BAz+1ol>$b1Fw%pS-&#HV1XgQU zAz);Ql>sXROj##m8W<4K^X2u5c;nLFE|E600000NkvXXu0mjftf$Pi literal 0 HcmV?d00001 diff --git a/cstav1/images/Server_24.png b/cstav1/images/Server_24.png new file mode 100755 index 0000000000000000000000000000000000000000..5e2256281136fce2a878f30198a93cd7d1f36b50 GIT binary patch literal 622 zcmV-!0+IcRP)=z9N7fR0G&?fxz_q&k|Z$zC?X<6BoV>9 zM#NiD6umvPULD;X0F+X-G)*5lj`M0f9xo1gTCJ8J1i{lNiaz}PjLHBaf+A91tyV8? z@=T}GpUnIz48td90}zn_0M_d@wcG9BCSM%KS0eH~48zC8`=zf)L=XVL7?W)_n>*cZ z_a!s`LPSGECchGq@qOPg^SxfLw;2wHvy%XMf<0ujSS;4_`TR38CtB-7M3UWZmuRiG zN~t6Wg8Po+_-7|5s?lgXP)Z>pUR##6t<`EfB1%Q%3II&edsc#6S(a@@ge=RtM#PMn z84;O?=xo5D1eRqfBC_^9;QcHdJTU*1V7Xj=Io5-sxAd4AV@f^8bn+Zj1~}A%{|cx) zfidRCC6LmEqtR$2BHtnP~$MILs^Xzj0 zrJstTeBXaluh*Y7o6QCQ03r$^N?sSN@A9Jbr+=v~8lqG52iLaiBQ70q5&!@I07*qo IM6N<$f?G5Qw*UYD literal 0 HcmV?d00001 diff --git a/cstav1/images/Server_48.png b/cstav1/images/Server_48.png new file mode 100755 index 0000000000000000000000000000000000000000..6cb37e8db775dcb5c38ceb90f76d9f2933ce29b6 GIT binary patch literal 1163 zcmV;61a$j}P)sc9Z@grD&+~O!cC^iziRQI}}1f zda1oxdZ<+d^&$!tJc!6UKB!(Fco4)(ycC;knh1&rqT)LULOu0R+e)Q1G)|}rQUA{B>+nF7L%nT1RmI;x$xw-LJESAt(2jk=8(zb1>wbnui zrIgZ^Whp78b{t1}o~J97iq7S7s$BySk^AUPG%*76^YfobDeZc_{w@5|DFP9RhzJo| z2LPO}0{{RsBQuW_3WfKsdT%2mVB5BXh||pcRz9Dv^rMkZr=QPevn$17@!nP1QSXpT zfkKD`Gq3h5P%f8$)>{9X&1PS{N;^{q001Beg2ytM%q#u2FO^C~X7)3g%!`+8W7Gfu z_@3uw(&_Z${R(VsYX#-HN*LSqmA6!Snb={90$4Sr3%sksG)`$T_ z{7?Ph;9w`4&AxdZ%|fB@{@B>q8?&>sk6sjKEQ#AIp6C5ptyYt%RO;#Lh{j^EcZlfj z^73-DTZ|C{%#7!M+uGVHMIw>cucMpG<&+R&!XAMZ)6>%_ z$8l~UqHZ2Uq?+eKh-Rsp_2c8?&t2DjFbD%ZSA=_ed*2Ho004Xd@THVKGyBZ!1Aymw zUSL_4cXoE>Nhy8b_q|%J=J(PKHHq6vBoeoy(P*;K^Q}Y`LNF0=Vhd3B^Dzms7D=>?f`D6JhAL6WS`W zSS;R;L?X|HrQamfZ57+LKb@GEcsY?syw>3|0{}F()Bi_fEB@bL=8rnYJ?wuqxcMR* dHa7-_&EKk$?*PY%EKC3Z002ovPDHLkV1fjH6o>!- literal 0 HcmV?d00001 diff --git a/cstav1/images/Sip_16.png b/cstav1/images/Sip_16.png new file mode 100755 index 0000000000000000000000000000000000000000..c7c56ed58703f5f0e20ccf68ed109680add3ba4b GIT binary patch literal 754 zcmV<=W0pumN+ zX*LBR1*x0NTm(uIO`?G!Ey6{#C}}Z<{XkG*ib2rNLRv{k5i)|B<2d8roA>5@x5YGK zB1F_(ecbOmhkMUCA2BojrKGJ5BBDQmh+@XZxj2De>u&ULRfEKO(3HMCnX{VP%8d5o zsuMapZ(Y7<7)_NvaiB*Pp?wm2f;sv7_^dI~C;>pw)zjn^N4kWxKAV%L6AFAWqEjAO z1P*GvdnW*tIfox=BC_A4>5;55dQ%aBXuzyKrvQK<_FPz%Cwk{|Ew=!`=ep))ezjVz z4U{vjB>{k-CD*0N@%da!2LJ^1+dEVdsg{UhnoSGgANt#Y;$BN;cXL4?x6h``3;;0f zynwY_e50~ADzKcEm=l)5{@H+esB^1;GP_IiluiKvSn~+VE(1Wo6+fwPxZXrEApt;+ zrg}?6Z7i$~zAn+PR22!B@@0b43kBubYa{K1^!|8hzIM=(lJ_!J{3Dnd%nYBa{b+^y z^mC;=J`>ct>X{kk>ir3?`%(=vBccv{sFcUjQF(Mar1W1c;x-5hb{=zu)H@Ht+TbuV zBc$E^0#Ds8W=2?jH0f8n`%rquzZvsekeJ6zK{Us(>|ZSnQqBf|Jf*Zn`&|cT5{sKL z5)lzmOe3n(1Fjpb9%t`)3tt}>T=3{d-t8f(Q3)(FKVRFLO2wzOoi24w^a;r_bvs&- zQQuroneib2aImzpE;$y05f^9K*)GR literal 0 HcmV?d00001 diff --git a/cstav1/images/VTSip_24.png b/cstav1/images/VTSip_24.png new file mode 100755 index 0000000000000000000000000000000000000000..c8fd25a1194899df1d2dd99cae383813232fb171 GIT binary patch literal 965 zcmV;$13LVPP)H#8y2vV}n>NrkkaiJ5X>H;pjtki|iLAIk zi8Yetk!I$-ZY(i!tkOWU%Z0mm^LXc*a}V#45CYG#q-U!B9Pk|QMCrQjnVp@LpXLnh zbPr}`W@q_ z$U{UwHX4oP;o;#_JRU#J7?S{ib8b0~W0|IDE-o%!SzTTIjdLC+qLW)ca4DC|EjBf` z+uiN+`97bUn|llZ*=$xDA0PiP5C|l;_6-2#W~-{I<@5RX3x&dE0GG4btR{p=x&_++ z^YimRxYuK2WAD1eD_ek84-5=+#bU8@0KNo(TrT$rK$}L#kS8Z6yOPP|#MZLv60W$q znoK4S>bf56q|*_QN~NY1MR}QsHULzF5EUY-5RpMdEf+&WLuNP}e)FjSx~>NkiNsp~ zHiZza(QwXN!c7ok%!tS1J()}2AOO|dvx^oTz$Nne($fViuT7Ye#AZzI6w5x z16h_0A%wv>HzY}F%VK0?q`a`Oa03U-9Rc?aEq}uHBKB(Z4aAf|3`Y**_2_Awh^C?J_l3V- z`nJbC`zEM4s&qR2tKaW`ts`I~S{@w?9faZup*PTvmm){duf!1b?ZJNa0E(Xb(dO*k z5Zks5A~IA}U6*Cq+3unRAOX|I{CK!o#Nii4p|B7FOhIY02(RRW%%vK(-GgS=>vf}C zE*ooWYu_=(PVN|TxU~D5;=cQ%N3~;EsoX-;*NvL9fuO9wc5Jc7>c6wTzRoPmk{gYN z$F^;6tyc3_tJQj`RI-+qmbjuQDiQ5+16pqp5z)B|>8ri*?o_wG2NAD^h)09N9dYf- z^{@HQ-j4x*b4~!@I1T}TEX(BnZrk>Qd_Mp86M!b n7eBgmVS9N0wRU{2|Ihjd9Kvt}R)+fE00000NkvXXu0mjfY!t%U literal 0 HcmV?d00001 diff --git a/cstav1/images/VTSip_48.png b/cstav1/images/VTSip_48.png new file mode 100755 index 0000000000000000000000000000000000000000..d0676f01cfd4d0ee706213d9ddb4399d27d901cd GIT binary patch literal 2194 zcmV;D2yOR?P)@b zfPqkjS>;<-o4vnnr0RNI2?}f;lqa`{1DFWG?_LJ z95~?U>gt-$%vAuY0OT;UO+@L9DF8eGn1~|GtfxL;W+EcN%(nrw0cZ<{!(XxSd;^JTT1Z5>%uK`Ha}rS=04Fow0$?-q zC$?>W(A?a7=YJyL_xqn^=FI>?L}Vb*+Y-Q8X1?TbIC?D0S_xn=08grSiHL057L*8) zgcn34Y}@V@LYy>B^FJ<^tI)RXYG!_hh)ibg2cQDTV&)UUVDO_!3Hbf~b{cUFup!{ z@}%0<*7nn2F!)uftw124*|xpGw(ajEr(<4{@klTjJTn^Sn2VU1R}s-=+qORrhr_2@ zTU(70_C$2((4jz8RaN~cO&CNJ1E2$l5z)}o?RI-MZQ69Fqod;&0Q{*h9654i5WxEY z-ru`-uR9WntS6!s09FAQRbWz!I2Ash?|V&6O~1;@%33xYJ_SDB^TLG-edo`gKX~-$ z(SJ>r;eql%d3pJcQQ+fA$orO>ni|vPa_xN(hDi(fe7+6!_4UQWsxyWMpgWyTELpO| z)zHvTIa!WL3(T1_$CsU*U6WR2P5?eN#q`?R+CD{5_Dq&zQUZRzziz{Z4aG?8H~?TK z7wLqH%jL2vD=TFn5Lo!g1d57^cID>gE>Hey5s_}&whll~iHs(c%p)V}*Q{A{O-kAH zNCfwSJ+N-=p-r00Y$1%qypC+ zjjO&~9{IsD+pc71XZHipnK_klhqA5^B4*pRE`%62JGZp7tnTXSI-Gt+8ZXA2LOERii$iuk_flW7j4$0;b1U7tJ2<0zh^4GMwl-j$p@|_^kIF zG^s(7gd!CP5;%491Dv__H(U<4W3G2T6sf^cNbZ4w0Zxa_^q4_Jx~}Uw5$QEGHGcqb z-|Re6z-g>A-HE?le)sR+prNb@uP%NY1xhj8QiUK1MQCu41K%&%j^|3Yp+udFo3ZOq zr3zQERIXgP^29{p0qDA}>i~2qrCwcKeT#@94Gj&m#}gPag$U>&TfpgX;_2+Ac>VH0 zXu^XRD}IU2Xh(7cR0tCIr1vx=Ip8E06saWYV-C~n_1+x^bky@usxY%23WfAgD5M*P z@rKjs{273kGado=fch6T>akR*VtLNDvAr~ax|#L(hI0mDRuqyX)Z|D21eb6PZKDW=U>|T*S`53FDPDxx}%*48Ml+L8p83rP^5|ha{!9a z67|V)_Tm}iniU;%mo4gXG9DCRxFBd&8k#q=FP~ZVr@1A3EYkL;cj2px^ez?hu+OUKmNw?KRrV3 zp~&c7sIjrJ*mj$BaW%Habed(tl7_IvC3i&mhXd}9lNVA`5)X8-_5To${XaPV3&j<7 UJAM~QZ~y=R07*qoM6N<$g0A@*qyPW_ literal 0 HcmV?d00001 diff --git a/cstav1/images/VT_24.png b/cstav1/images/VT_24.png new file mode 100755 index 0000000000000000000000000000000000000000..3dd2e36d822477f51508a9ca00b8c02389438ada GIT binary patch literal 766 zcmVU1C+qUP4Xp)H1LI{b7 z7=Q}^%sc=9k|YUc{=v*&T-W_nsZ>tR6%>obDFDkv6eFUl<2YXp!zk#wJ}=9%1OP$^ z*Y|zbwr#sst9?8?Jp3kv(1~cFQ^31&xm*jFXWP9MkH_C^Z*TtsfKsV6vb41HI+;vP zb)H)Q>OpFnHnO|B`?6B0>;u>@l}aPboC^bc1UoxBAHwUoxw#i1c%vieW+syv%x1GI z0Nw&Xxm^AUpobB8$ZKnBgSlMpNoUy%fg7Q0=5o2arfH_4IFW)vp-@y+HBUq*02<8P zAfg5lSwz(BVq#*#9vT{Yd?|rxnyGv~zXITtnY*JALUh4_NS0+w*Y(@0tE;q9Ss>Q{{&xu6h!MOs{G-I=~vyT9rL{)!Q;(4A$M3$y$zZFIC&vwxx z7#|;hIyyQ!83m8ZcDrrW>vik+`1rjn%L`#<&qd2-v-dsEJ7wk;0NeL{R|w$?A()xT z_kG!QUBz*nnCE!|tyU}1Y&P3RM@R0#!GTa!RU@LCk%GOwy;s$0^$q|CAqW6`-zNZ2 w6ot;&Pf3!b0)XQ<`(b9^uj&7cEC1pA0Sa_QSI3rS5&!@I07*qoM6N<$f^e2owEzGB literal 0 HcmV?d00001 diff --git a/cstav1/images/VT_48.png b/cstav1/images/VT_48.png new file mode 100755 index 0000000000000000000000000000000000000000..71e0c97a71a839e165ae90018c68e4c6e26a9382 GIT binary patch literal 1536 zcmV+b2LJhqP)(BTV)u>zt7uJC>@c|Ep!ubjL8Usga~6U3xXR3 zoFQI&L)MvoS@xpkq?8cj2YL>91lHH=&jWH1ue0L3efi)7JdKgzPE(D(H8 zdAw*3sa;!28EZ&*l9O}ZbKdiw&*%Mh&Ur~hu$x0w8(_P!Cs6I!6R39V2~<1w1gaf- z0@aQ^fojLD7jW-Hp+rO%E?n^0w%q^#Znryr{rdHU?7+7>RZ`~Ft5@B3@7{e`M0x=9 z0B8~sCZgQJ>Hzov2oWVjL^~HmgosFq$U^|j0G8wN_@4_43+WvbFbtzfMBXN%AtF)$ znnlDCk%vTN=VfOidL$zMBGXL+MC2C{%F9)V2%2Pa^WG+wH!WPN!c7@G1bGQ@cb&%&aIADhscONHOz2N~uNLwpTnJ zPk@>GMC1)3vPI+x055= zsi~01Y?(Xh(MIw=|=O%FQ;KBF&e*f`o zGEGF9nKc0Ih!hgazDJ%qfBN+4zg;fZ%ySViP4mR~`1p$eTmaGlG&5@=(vCged8^XJcZ?zq5#0|zb!0)gYmyx{%^_|3Q6e2gBU-O&EG&VLSnwy*La5#JfWk%ToO-)Ug4j(@JN-2O+ zTN$ll0nn3^liw<(${q`42}B~1j?vN4qeQf6-$%}LS!gQFhj&`ZnZ=r$o1ggo{-kM| z?axfW>-Apl?Ck6;2R=ul>{cNnZQJ(7`O(qQF9E#&OawxqQ0wsUaFFH_z(9qCp+5g=9hgSk#vPDEhi-=}s9gD^E$jFF& z^XAP*M6_<2X3LfZ+-~=~0|NuT>_aOC&H=Yd!6P%U_4@j{9vKxw^WV0sxoGB}yp~k(Y?*g<_B;f9k{G z@DZg{FEgubZ4fh)b1Wj{ELJ&bBBGqU%1JwUl~Nn&?Ai-SCN|P}<=ty(Y5Drfl`Fhu mf!z?hesy|JpxUwP1^xqheE{x~F%3ch0000 +#include +#include +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +#include "Rose_Apdu.h" +#include "CSTA_event.h" + +#include "Rose_Apdu.hpp" +#include "CSTA_event.hpp" +/** + +CSTAEventReportArgument ::= SEQUENCE { + crossRefIdentifier MonitorCorssRefID + eventSpecificInfo EventSpecificInfo +} + * +ServiceInitiatedEventInfo ::= SEQUENCE { + initatedConnection ConnectionID, + localConnectionInfo LocalConnectionState OPTIONAL + cause EventCause OPTIONAL + } + * +ConnectionID ::= [APPLICATION 11] CHOICE { + call [2] IMPLICIT OCTET STRING OPTIONAL, + device CHOICE { + staticID DeviceID, + dynamicID [3] IMPLICIT OCTET STRING + } +} + +CallID ::= OCTET STRING +LocalDeviceID ::= CHOICE [ + staticID DeviceID + dynamicID [3] IMPLICIT OCTET STRING +} + +DeviceID ::= SEQUENCE { + deviceIdentifier CHOICE { + } +} + */ + +int test_decode() +{ + /* This sequence is for Alcatel CSTA which is not compatible with the ecma + * 285 description. Just forget it. Events are described diferently*/ + const unsigned char d[] ={ 0x30,0x46, + 0x55,0x04,0x00,0x00,0x00,0x04, + 0x80,0x01,0x0d, // For alcated, this Event Type 13 + //Context Specific - Primitive - Id=0 tag. Len 1 - value 0d 13 what is this ? + 0x30,0x1d, /* ServiceInitiatedEvent SEQUENCE len 0x1d 29*/ + 0x6b,0x0a, /* ConnectionID tag APPL 11 len 10 CHOICE*/ + 0x82,0x02,0x00,0x76, /* This should be both of ConnectionID*/ + 0x83,0x04,0x00, 0x03,0x00,0x00, /* supposed to be dynamic ID*/ + /** */ + /* I d'ont know what this is */ + 0x4e,0x01,0x01, /* State initated */ + 0x0a,0x01, 0x16, /* Event Cause newCall*/ + 0x63,0x05,0x84,0x03,0x31,0x30,0x32, + 0x62,0x02,0x87,0X00, + 0x7d,0x1c, /* private date [APPLICATION 24 ] implicit */ + 0x06,0x06,0x2b,0x0c,0x89,0x36,0x83, 0x74,/* manufacturer OBJECT ID 1.3.12.1206.500 */ + 0x04,0x12,0x03,0x01,0x00,0x00,0x0c,0x49,0x43,0x54,0x4f,0x55,0x43,0x48,0x5f, + 0x4e , 0x4f,0x4e,0x45,0x00 + }; + + CSTA_event::CSTAEventReportArgument report; + asn1::streams::ber ctx; + memcpy(ctx.buffer(),d,74); + //report.codec(ctx,report,asn1::CODEC_DECODE); + report.decode(ctx); + std::cout<<"Go type info="< 1) { + // Try to decode a stream .... + std::ifstream is; + is.open(argv[1],std::ios::binary); + int len = 0; + char bl[2]; + + memset(bl,0x00,3); + while (is.read(bl,2) && is.good()) + { + len = bl[1] | bl[0]<<8; + std::cout<<" Read header "<<(unsigned short)bl[0]<<"-"<<(unsigned short)bl[1]<<" should decode len="<>3) == len ) + { + std::cout<<"\n\n\tYES COMPLETELY DECODED\n"; + switch (pdu.get_kind()) + { + case Rose_Apdu::RoseAPDU::typeof_invoke: + std::cout<<"\tGot invoke ID="<(_o); + // Get OBJECT-TYPE + CSTA_event::CSTAEventReportArgument report; + event->get_ArgumentType(report); + std::cout<<"Go type info="<(_o1); + + } + } else { + std::cout< +#include + +#define SIGSLOT_USE_POSIX_THREADS +#define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local + +#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS)) +# define _SIGSLOT_SINGLE_THREADED +#elif defined(WIN32) +# define _SIGSLOT_HAS_WIN32_THREADS +# include +#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS) +# define _SIGSLOT_HAS_POSIX_THREADS +# include +#else +# define _SIGSLOT_SINGLE_THREADED +#endif + +#ifndef SIGSLOT_DEFAULT_MT_POLICY +# ifdef _SIGSLOT_SINGLE_THREADED +# define SIGSLOT_DEFAULT_MT_POLICY single_threaded +# else +# define SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local +# endif +#endif + + +namespace sigslot { + + class single_threaded + { + public: + single_threaded() + { + ; + } + + virtual ~single_threaded() + { + ; + } + + virtual void lock() + { + ; + } + + virtual void unlock() + { + ; + } + }; + +#ifdef _SIGSLOT_HAS_WIN32_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + static bool isinitialised = false; + + if(!isinitialised) + { + InitializeCriticalSection(get_critsec()); + isinitialised = true; + } + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + EnterCriticalSection(get_critsec()); + } + + virtual void unlock() + { + LeaveCriticalSection(get_critsec()); + } + + private: + CRITICAL_SECTION* get_critsec() + { + static CRITICAL_SECTION g_critsec; + return &g_critsec; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + InitializeCriticalSection(&m_critsec); + } + + multi_threaded_local(const multi_threaded_local&) + { + InitializeCriticalSection(&m_critsec); + } + + virtual ~multi_threaded_local() + { + DeleteCriticalSection(&m_critsec); + } + + virtual void lock() + { + EnterCriticalSection(&m_critsec); + } + + virtual void unlock() + { + LeaveCriticalSection(&m_critsec); + } + + private: + CRITICAL_SECTION m_critsec; + }; +#endif // _SIGSLOT_HAS_WIN32_THREADS + +#ifdef _SIGSLOT_HAS_POSIX_THREADS + // The multi threading policies only get compiled in if they are enabled. + class multi_threaded_global + { + public: + multi_threaded_global() + { + pthread_mutex_init(get_mutex(), NULL); + } + + multi_threaded_global(const multi_threaded_global&) + { + ; + } + + virtual ~multi_threaded_global() + { + ; + } + + virtual void lock() + { + pthread_mutex_lock(get_mutex()); + } + + virtual void unlock() + { + pthread_mutex_unlock(get_mutex()); + } + + private: + pthread_mutex_t* get_mutex() + { + static pthread_mutex_t g_mutex; + return &g_mutex; + } + }; + + class multi_threaded_local + { + public: + multi_threaded_local() + { + pthread_mutex_init(&m_mutex, NULL); + } + + multi_threaded_local(const multi_threaded_local&) + { + pthread_mutex_init(&m_mutex, NULL); + } + + virtual ~multi_threaded_local() + { + pthread_mutex_destroy(&m_mutex); + } + + virtual void lock() + { + pthread_mutex_lock(&m_mutex); + } + + virtual void unlock() + { + pthread_mutex_unlock(&m_mutex); + } + + private: + pthread_mutex_t m_mutex; + }; +#endif // _SIGSLOT_HAS_POSIX_THREADS + + template + class lock_block + { + public: + mt_policy *m_mutex; + + lock_block(mt_policy *mtx) + : m_mutex(mtx) + { + m_mutex->lock(); + } + + ~lock_block() + { + m_mutex->unlock(); + } + }; + + template + class has_slots; + + template + class _connection_base0 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit() = 0; + virtual _connection_base0* clone() = 0; + virtual _connection_base0* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base1 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type) = 0; + virtual _connection_base1* clone() = 0; + virtual _connection_base1* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base2 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type) = 0; + virtual _connection_base2* clone() = 0; + virtual _connection_base2* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base3 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type) = 0; + virtual _connection_base3* clone() = 0; + virtual _connection_base3* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base4 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0; + virtual _connection_base4* clone() = 0; + virtual _connection_base4* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base5 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type) = 0; + virtual _connection_base5* clone() = 0; + virtual _connection_base5* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base6 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type) = 0; + virtual _connection_base6* clone() = 0; + virtual _connection_base6* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base7 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type) = 0; + virtual _connection_base7* clone() = 0; + virtual _connection_base7* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _connection_base8 + { + public: + virtual has_slots* getdest() const = 0; + virtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, + arg6_type, arg7_type, arg8_type) = 0; + virtual _connection_base8* clone() = 0; + virtual _connection_base8* duplicate(has_slots* pnewdest) = 0; + }; + + template + class _signal_base : public mt_policy + { + public: + virtual void slot_disconnect(has_slots* pslot) = 0; + virtual void slot_duplicate(const has_slots* poldslot, has_slots* pnewslot) = 0; + }; + + template + class has_slots : public mt_policy + { + private: + typedef typename std::set<_signal_base *> sender_set; + typedef typename sender_set::const_iterator const_iterator; + + public: + has_slots() + { + ; + } + + has_slots(const has_slots& hs) + : mt_policy(hs) + { + lock_block lock(this); + const_iterator it = hs.m_senders.begin(); + const_iterator itEnd = hs.m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_duplicate(&hs, this); + m_senders.insert(*it); + ++it; + } + } + + void signal_connect(_signal_base* sender) + { + lock_block lock(this); + m_senders.insert(sender); + } + + void signal_disconnect(_signal_base* sender) + { + lock_block lock(this); + m_senders.erase(sender); + } + + virtual ~has_slots() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_senders.begin(); + const_iterator itEnd = m_senders.end(); + + while(it != itEnd) + { + (*it)->slot_disconnect(this); + ++it; + } + + m_senders.erase(m_senders.begin(), m_senders.end()); + } + + private: + sender_set m_senders; + }; + + template + class _signal_base0 : public _signal_base + { + public: + typedef typename std::list<_connection_base0 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + _signal_base0() + { + ; + } + + _signal_base0(const _signal_base0& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + ~_signal_base0() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base1 : public _signal_base + { + public: + typedef typename std::list<_connection_base1 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base1() + { + ; + } + + _signal_base1(const _signal_base1& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base1() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base2 : public _signal_base + { + public: + typedef typename std::list<_connection_base2 *> + connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base2() + { + ; + } + + _signal_base2(const _signal_base2& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base2() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + template + class _signal_base3 : public _signal_base + { + public: + typedef typename std::list<_connection_base3 *> + connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base3() + { + ; + } + + _signal_base3(const _signal_base3& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base3() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base4 : public _signal_base + { + public: + typedef typename std::list<_connection_base4 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base4() + { + ; + } + + _signal_base4(const _signal_base4& s) + : _signal_base(s) + { + lock_block lock(this); + const_iterator it = s.m_connected_slots.begin(); + const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base4() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + const_iterator it = m_connected_slots.begin(); + const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + iterator it = m_connected_slots.begin(); + iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + +#if 0 + template + class _signal_base5 : public _signal_base + { + public: + typedef typename std::list<_connection_base5 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base5() + { + ; + } + + _signal_base5(const _signal_base5& s) + : _signal_base(s) + { + lock_block lock(this); + connections_list::const_iterator it = s.m_connected_slots.begin(); + connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base5() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + connections_list::const_iterator it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base6 : public _signal_base + { + public: + typedef typename std::list<_connection_base6 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base6() + { + ; + } + + _signal_base6(const _signal_base6& s) + : _signal_base(s) + { + lock_block lock(this); + connections_list::const_iterator it = s.m_connected_slots.begin(); + connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base6() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + connections_list::const_iterator it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base7 : public _signal_base + { + public: + typedef typename std::list<_connection_base7 *> connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base7() + { + ; + } + + _signal_base7(const _signal_base7& s) + : _signal_base(s) + { + lock_block lock(this); + connections_list::const_iterator it = s.m_connected_slots.begin(); + connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base7() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + connections_list::const_iterator it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + + template + class _signal_base8 : public _signal_base + { + public: + typedef typename std::list<_connection_base8 *> + connections_list; + typedef typename connections_list::const_iterator const_iterator; + typedef typename connections_list::iterator iterator; + + _signal_base8() + { + ; + } + + _signal_base8(const _signal_base8& s) + : _signal_base(s) + { + lock_block lock(this); + connections_list::const_iterator it = s.m_connected_slots.begin(); + connections_list::const_iterator itEnd = s.m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_connect(this); + m_connected_slots.push_back((*it)->clone()); + + ++it; + } + } + + void slot_duplicate(const has_slots* oldtarget, has_slots* newtarget) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == oldtarget) + { + m_connected_slots.push_back((*it)->duplicate(newtarget)); + } + + ++it; + } + } + + ~_signal_base8() + { + disconnect_all(); + } + + void disconnect_all() + { + lock_block lock(this); + connections_list::const_iterator it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + (*it)->getdest()->signal_disconnect(this); + delete *it; + + ++it; + } + + m_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end()); + } + + void disconnect(has_slots* pclass) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + if((*it)->getdest() == pclass) + { + delete *it; + m_connected_slots.erase(it); + pclass->signal_disconnect(this); + return; + } + + ++it; + } + } + + void slot_disconnect(has_slots* pslot) + { + lock_block lock(this); + connections_list::iterator it = m_connected_slots.begin(); + connections_list::iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + connections_list::iterator itNext = it; + ++itNext; + + if((*it)->getdest() == pslot) + { + m_connected_slots.erase(it); + // delete *it; + } + + it = itNext; + } + } + + protected: + connections_list m_connected_slots; + }; + +#endif + + template + class _connection0 : public _connection_base0 + { + public: + _connection0() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection0(dest_type* pobject, void (dest_type::*pmemfun)()) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base0* clone() + { + return new _connection0(*this); + } + + virtual _connection_base0* duplicate(has_slots* pnewdest) + { + return new _connection0((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit() + { + (m_pobject->*m_pmemfun)(); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(); + }; + + template + class _connection1 : public _connection_base1 + { + public: + _connection1() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base1* clone() + { + return new _connection1(*this); + } + + virtual _connection_base1* duplicate(has_slots* pnewdest) + { + return new _connection1((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1) + { + (m_pobject->*m_pmemfun)(a1); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type); + }; + + template + class _connection2 : public _connection_base2 + { + public: + _connection2() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base2* clone() + { + return new _connection2(*this); + } + + virtual _connection_base2* duplicate(has_slots* pnewdest) + { + return new _connection2((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2) + { + (m_pobject->*m_pmemfun)(a1, a2); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type); + }; + + template + class _connection3 : public _connection_base3 + { + public: + _connection3() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base3* clone() + { + return new _connection3(*this); + } + + virtual _connection_base3* duplicate(has_slots* pnewdest) + { + return new _connection3((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + (m_pobject->*m_pmemfun)(a1, a2, a3); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type); + }; + + template + class _connection4 : public _connection_base4 + { + public: + _connection4() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base4* clone() + { + return new _connection4(*this); + } + + virtual _connection_base4* duplicate(has_slots* pnewdest) + { + return new _connection4((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, + arg4_type a4) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, + arg4_type); + }; + + template + class _connection5 : public _connection_base5 + { + public: + _connection5() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base5* clone() + { + return new _connection5(*this); + } + + virtual _connection_base5* duplicate(has_slots* pnewdest) + { + return new _connection5((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type); + }; + + template + class _connection6 : public _connection_base6 + { + public: + _connection6() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base6* clone() + { + return new _connection6(*this); + } + + virtual _connection_base6* duplicate(has_slots* pnewdest) + { + return new _connection6((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type); + }; + + template + class _connection7 : public _connection_base7 + { + public: + _connection7() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base7* clone() + { + return new _connection7(*this); + } + + virtual _connection_base7* duplicate(has_slots* pnewdest) + { + return new _connection7((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type); + }; + + template + class _connection8 : public _connection_base8 + { + public: + _connection8() + { + m_pobject = NULL; + m_pmemfun = NULL; + } + + _connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + m_pobject = pobject; + m_pmemfun = pmemfun; + } + + virtual _connection_base8* clone() + { + return new _connection8(*this); + } + + virtual _connection_base8* duplicate(has_slots* pnewdest) + { + return new _connection8((dest_type *)pnewdest, m_pmemfun); + } + + virtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + (m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + virtual has_slots* getdest() const + { + return m_pobject; + } + + private: + dest_type* m_pobject; + void (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type, + arg5_type, arg6_type, arg7_type, arg8_type); + }; + + template + class signal0 : public _signal_base0 + { + public: + signal0() + { + ; + } + + signal0(const signal0& s) + : _signal_base0(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)()) + { + lock_block lock(this); + _connection0* conn = + new _connection0(pclass, pmemfun); + _signal_base0::m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit() + { + lock_block lock(this); + typename _signal_base0::const_iterator itNext, it = this->m_connected_slots.begin(); + //::sigslot::_signal_base0::const_iterator itNext, it = m_connected_slots.begin(); + typename _signal_base0::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + + void operator()() + { + lock_block lock(this); + typename _signal_base0::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base0::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(); + + it = itNext; + } + } + }; + + template + class signal1 : public _signal_base1 + { + public: + signal1() + { + ; + } + + signal1(const signal1& s) + : _signal_base1(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type)) + { + lock_block lock(this); + _connection1* conn = + new _connection1(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1) + { + lock_block lock(this); + typename _signal_base1::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base1::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + + void operator()(arg1_type a1) + { + lock_block lock(this); + typename _signal_base1::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base1::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1); + + it = itNext; + } + } + }; + + template + class signal2 : public _signal_base2 + { + public: + signal2() + { + ; + } + + signal2(const signal2& s) + : _signal_base2(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type)) + { + lock_block lock(this); + _connection2* conn = new + _connection2(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + typename _signal_base2::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base2::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2) + { + lock_block lock(this); + typename _signal_base2::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base2::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2); + + it = itNext; + } + } + }; + + template + class signal3 : public _signal_base3 + { + public: + signal3() + { + ; + } + + signal3(const signal3& s) + : _signal_base3(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type)) + { + lock_block lock(this); + _connection3* conn = + new _connection3(pclass, + pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + typename _signal_base3::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base3::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3) + { + lock_block lock(this); + typename _signal_base3::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base3::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3); + + it = itNext; + } + } + }; + + template + class signal4 : public _signal_base4 + { + public: + signal4() + { + ; + } + + signal4(const signal4& s) + : _signal_base4(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type)) + { + lock_block lock(this); + _connection4* + conn = new _connection4(pclass, pmemfun); + this->m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + typename _signal_base4::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base4::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) + { + lock_block lock(this); + typename _signal_base4::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base4::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4); + + it = itNext; + } + } + }; + +#if 0 + template + class signal5 : public _signal_base5 + { + public: + signal5() + { + ; + } + + signal5(const signal5& s) + : _signal_base5(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type)) + { + lock_block lock(this); + _connection5* conn = new _connection5(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + typename _signal_base0::const_iterator itNext, it = this->m_connected_slots.begin(); + typename _signal_base0::const_iterator itEnd = this->m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5) + { + lock_block lock(this); + connections_list::const_iterator itNext, it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5); + + it = itNext; + } + } + }; + + + template + class signal6 : public _signal_base6 + { + public: + signal6() + { + ; + } + + signal6(const signal6& s) + : _signal_base6(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type)) + { + lock_block lock(this); + _connection6* conn = + new _connection6(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + connections_list::const_iterator itNext, it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6) + { + lock_block lock(this); + connections_list::const_iterator itNext, it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6); + + it = itNext; + } + } + }; + + template + class signal7 : public _signal_base7 + { + public: + signal7() + { + ; + } + + signal7(const signal7& s) + : _signal_base7(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type)) + { + lock_block lock(this); + _connection7* conn = + new _connection7(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + connections_list::const_iterator itNext, it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7) + { + lock_block lock(this); + connections_list::const_iterator itNext, it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7); + + it = itNext; + } + } + }; + + template + class signal8 : public _signal_base8 + { + public: + signal8() + { + ; + } + + signal8(const signal8& s) + : _signal_base8(s) + { + ; + } + + template + void connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type, + arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, + arg7_type, arg8_type)) + { + lock_block lock(this); + _connection8* conn = + new _connection8(pclass, pmemfun); + m_connected_slots.push_back(conn); + pclass->signal_connect(this); + } + + void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + connections_list::const_iterator itNext, it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + + void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, + arg5_type a5, arg6_type a6, arg7_type a7, arg8_type a8) + { + lock_block lock(this); + connections_list::const_iterator itNext, it = m_connected_slots.begin(); + connections_list::const_iterator itEnd = m_connected_slots.end(); + + while(it != itEnd) + { + itNext = it; + ++itNext; + + (*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8); + + it = itNext; + } + } + }; +#endif +}; // namespace sigslot + +#endif // SIGSLOT_H__ + diff --git a/gsm/CMakeLists.txt b/gsm/CMakeLists.txt new file mode 100644 index 0000000..443238f --- /dev/null +++ b/gsm/CMakeLists.txt @@ -0,0 +1,99 @@ +PROJECT(gsm-rrc) + +#EXEC_PROGRAM(cat ARGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt OUTPUT_VARIABLE +# CSTAMODULES) + +FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt GSMMODULES) + +FOREACH(ITEM ${GSMMODULES}) + STRING(REGEX REPLACE "-" "_" HITEM ${ITEM}) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h GENERATED) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp GENERATED) + SET(GSMRRCSRC ${GSMRRCSRC} ${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp) + SET(GSMRRCHDR ${CSTAV1HDR} ${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp" + ) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h" + ) + +ENDFOREACH(ITEM) + +SET(GSM_PARSER_INC -I ${asn1-data-models_SOURCE_DIR}/gsm/) +#SET(GSM_PARSER_OPT ${GSM_PARSER_INC} -fConstant-definitions.asn1) +SET(GSM_PARSER_OPT ${GSM_PARSER_INC} -fpdu_cd.asn1) +#SET(GSM_PARSER_OPT1 ${GSM_PARSER_OPT} -fInformationElements.asn1) +SET(GSM_PARSER_OPT1 ${GSM_PARSER_OPT} -fpdu_ie.asn1) +SET(GSM_PARSER_OPT2 ${GSM_PARSER_OPT1} -fpdu.asn1) +SET(GSM_PARSER_OPT4 ${GSM_PARSER_OPT2} -frrc.asn1) +#SET(GSM_PARSER_OPT3 ${GSM_PARSER_OPT2} -fInternode-definitions.asn1) +SET(GSM_PARSER_OPT3 ${GSM_PARSER_OPT2} -fpdu_ind.asn1) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +IF(WITH_GSM) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Constant-definitions.cpp + ${CMAKE_CURRENT_BINARY_DIR}/Constant_definitions.h + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + ARGS ${GSM_PARSER_OPT} -o Constant-definitions + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build ConstantDefinitions.h and .cpp" +) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/InformationElements.cpp + ${CMAKE_CURRENT_BINARY_DIR}/InformationElements.h + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + ARGS ${GSM_PARSER_OPT1} -o InformationElements + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build InformationElements.h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/PDU_definitions.h + ${CMAKE_CURRENT_BINARY_DIR}/PDU-definitions.cpp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + ARGS ${GSM_PARSER_OPT2} -o PDU-definitions + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build PDU-definitions.h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Internode-definitions.cpp + ${CMAKE_CURRENT_BINARY_DIR}/Internode_definitions.h + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + ARGS ${GSM_PARSER_OPT3} -o Internode-definitions + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build Internode-definitions.h and .cpp" + ) + + + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Class_definitions.h + ${CMAKE_CURRENT_BINARY_DIR}/Class-definitions.cpp + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + ARGS ${GSM_PARSER_OPT4} -o Class-definitions + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build Class-definitions.h and .cpp" + ) + +ADD_LIBRARY(gsmrrc + ${GSMRRCSRC} + ) + +#ADD_EXECUTABLE(test_cstav1 +# main.cpp +# ) + +#TARGET_LINK_LIBRARIES(test_cstav1 cstav1 asn1) +ENDIF(WITH_GSM) diff --git a/gsm/modules.txt b/gsm/modules.txt new file mode 100644 index 0000000..b1d1673 --- /dev/null +++ b/gsm/modules.txt @@ -0,0 +1,5 @@ +Constant-definitions +InformationElements +Class-definitions +Internode-definitions +PDU-definitions diff --git a/gsmmap/CMakeLists.txt b/gsmmap/CMakeLists.txt new file mode 100644 index 0000000..2584a61 --- /dev/null +++ b/gsmmap/CMakeLists.txt @@ -0,0 +1,50 @@ +PROJECT(gsmmap) + + +#EXEC_PROGRAM(cat ARGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt OUTPUT_VARIABLE +# CSTAMODULES) +SET(GSMMAPDIR ${CMAKE_SOURCE_DIR}/../../../data-models/asn1/gsmmpa CACHE + STRING "GSMMAP ASN1 Source DIR") +FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt GSMMAPMODULES) + +FOREACH(ITEM ${GSMMAPMODULES}) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.h GENERATED) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp GENERATED) + SET(GSMMAPSRC ${GSMRRCSRC} ${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp) + SET(GSMMAPHDR ${CSTAV1HDR} ${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.h) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp" + ) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.h" + ) + +ENDFOREACH(ITEM) + + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/DummyMap.cpp + COMMAND cat + ${GSMMAPDIR}/GSMMAP.asn1 + ARGS | ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build InformationElements.h and .cpp" + ) + + + +ADD_LIBRARY(gsmmmap + ${GSMMAPSRC} + ) + +#ADD_EXECUTABLE(test_cstav1 +# main.cpp +# ) + +#TARGET_LINK_LIBRARIES(test_cstav1 cstav1 asn1) diff --git a/gsmmap/module.txt b/gsmmap/module.txt new file mode 100644 index 0000000..887d1b6 --- /dev/null +++ b/gsmmap/module.txt @@ -0,0 +1,4 @@ +DummyMAP +MAP-CommonDataTypes +MAP-ExtensionDataTypes +MAP-CH-DataTypes diff --git a/h248/CMakeLists.txt b/h248/CMakeLists.txt new file mode 100644 index 0000000..bbd6d95 --- /dev/null +++ b/h248/CMakeLists.txt @@ -0,0 +1,156 @@ +PROJECT(h248) + +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${rules_SOURCE_DIR}/") + +OPTION(H248_ASN1_NESTED "Generated H248 nested code or not" ON) +OPTION(H248_ASN1_COMMENT "Generate H248 with comment in source" OFF) + +FIND_PACKAGE(PCAP REQUIRED) +INCLUDE_DIRECTORIES(${PCAP_INCLUDE_DIRS}) + +FIND_PACKAGE(Sqlite3) +FIND_PACKAGE(Fcgi) +#EXEC_PROGRAM(cat ARGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt OUTPUT_VARIABLE +# CSTAMODULES) + +FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/modules.txt H248MODULES) + +FOREACH(ITEM ${H248MODULES}) + STRING(REGEX REPLACE "-" "_" HITEM ${ITEM}) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h GENERATED) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp GENERATED) + SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.lds GENERATED) + SET(H248SRC ${H248SRC} ${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp) + SET(H248HDR ${H248HDR} ${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h) + SET(H248LDS ${H248LDS} ${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.lds) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.cpp" + ) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${HITEM}.h" + ) +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${ITEM}.lds" + ) + +ENDFOREACH(ITEM) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/MEDIA-GATEWAY-CONTROL.cpp COMPILE_FLAGS "-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER") +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/main.cpp COMPILE_FLAGS "-DASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +# +# +# +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + COMMAND cat + ${asn1-data-models_SOURCE_DIR}/cstav1/Remote-Operations-Information-Objects.asn1 + ARGS | ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build ROIO .h and .cpp" + ) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote_Operations_Information_Objects.h + GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp + GENERATED) + +SET_DIRECTORY_PROPERTIES(PROPERTIES + ADDITIONAL_MAKE_CLEAN_FILES + "${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.h ${CMAKE_CURRENT_BINARY_DIR}/Remote-Operations-Information-Objects.cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${H248SRC} + ${H248HDR} + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + ARGS -n ${H248_ASN1_NESTED} -c ${H248_ASN1_COMMENT} + -I ${asn1-data-models_SOURCE_DIR}/h323/ -f h248v3.asn1 -o MEDIA-GATEWAY-CONTROL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build H248 V3 library .h and .cpp" + ) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${H248LDS} + COMMAND ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + ARGS -n ${H248_ASN1_NESTED} -c ${H248_ASN1_COMMENT} + -I ${asn1-data-models_SOURCE_DIR}/h323/ -l lds -f h248v3.asn1 -o MEDIA-GATEWAY-CONTROL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../asn1p + COMMENT "Build H248 V3 library lds" + ) + + + +ADD_LIBRARY(h248 + ${H248SRC} + ${H248LDS} + ) + +ADD_EXECUTABLE(test_h248 + main.cpp + ) + +TARGET_LINK_LIBRARIES(test_h248 h248 asn1) + + +IF(APPLE) + #SET_TARGET_PROPERTIES(cstaspy PROPERTIES LINKER_FLAGS "-framework Cocoa") +#Missing and don't know why +#TARGET_LINK_LIBRARIES(cstaspy /usr/local/lib/libfltk_png.a) +ENDIF(APPLE) + +IF(UNIX AND NOT APPLE) + #TARGET_LINK_LIBRARIES(cstaspy Ui X11 Xft Xinerama fltk_images) +ENDIF() + +IF(WIN32) + #TARGET_LINK_LIBRARIES(cstaspy Ui ws2_32) +ENDIF() + +#TARGET_LINK_LIBRARIES(cstaspy ${FLTK_LIBRARIES}) +#TARGET_LINK_LIBRARIES(cstaspy cstav1) +#TARGET_LINK_LIBRARIES(cstaspy asn1) +#TARGET_LINK_LIBRARIES(cstaspy ${PCAP_LIBRARIES}) + +# +# Install stuff +# +#INSTALL(TARGETS cstaspy DESTINATION bin) + +# +# Ok start working with Packaging stuff +# +INCLUDE(InstallRequiredSystemLibraries) + +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Graphical user interface to visualize +csta phase 2 and sip messages from pcap files") +SET(CPACK_PACKAGE_VENDOR "Aeb") +#SET(CPACK_PACKAGE_DESCRIPTION_FILE "") +#SET(CPACK_RESOURCE_FILE_LICENSE "") +SET(CPACK_PACKAGE_VERSION_MAJOR "1") +SET(CPACK_PACKAGE_VERSION_MINOR "0") +SET(CPACK_PACKAGE_VERSION_PATCH "0") + +SET(CPACK_PACKAGE_FILE_NAME "CstaSpyInstaller") +SET(CPACK_PACKAGE_NAME "CstaSpy") + +IF(WIN32) + SET(CPACK_GENERATOR "NSIS") +ENDIF() + +IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) + SET(CPACK_GENERATOR "RPM") +ENDIF() +#SET(CPACK_PACKAGE_EXECUTABLES "cstaspy") +#SET(CPACK_PACKAGE_EXECUTABLES "cstaspy" "CSTA Spy") +INCLUDE(CPack) diff --git a/h248/main.cpp b/h248/main.cpp new file mode 100644 index 0000000..ae30c33 --- /dev/null +++ b/h248/main.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +#include "MEDIA_GATEWAY_CONTROL.h" + +using namespace MEDIA_GATEWAY_CONTROL; + +void test_message() { + asn1::streams::ber ctx; + asn1::streams::ber ctx1; + ::asn1::types::debug_level = 8; + IP4Address ip4; + Message m; + m.version = 2; + ip4.address = std::string("0345"); + ip4.portNumber = asn1::intrusive_ptr(new INTEGER(asn1::prim::types::Integer(1045))); + //m.mId.ip4Address = ip4; + //m.mId.kind_ = Mid::typeof_ip4Address; + //m.mId.set_tag(asn1::tag(asn1::types::CONTEXT_SPECIFIC,Mid::typeof_ip4Address)); + m.mId.set_tag(asn1::tag(asn1::types::CONTEXT_SPECIFIC,0)); + //m.mId.set_ip4Address ( ip4 ); + m.mId.get_ip4Address() = ip4 ; + std::cout< +#include +#include +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +#include "Ledger_Apdu.h" +#include "Ledger_retrieve.hpp" +#include "Ledger_lifecycle.hpp" +#include "Ledger_Book_Keeping.hpp" + +/** + + */ + +void test() +{ + Ledger_Book_Keeping::postTransaction p; + Ledger_Book_Keeping::PostTransactionArgument arg; + Ledger_definitions::Date d; + Ledger_definitions::Entry e1,e2; + Ledger_definitions::AccountId a; + std::string s("Test entry"); + asn1::prim::types::String s1("Jones"); + asn1::prim::types::UTCTime tx("1307120000Z"); + d.is_set = true; + d.time = asn1::prim::types::UTCTime(std::string("1212050000Z")); + p.get_ArgumentType(arg); + + a = s1; + e1.acc_id = a; + e1.entry_date = d; + e1.description= s1; + e1.op = Ledger_definitions::DebitOrCredit::credit; + std::cout<<"Date:"< 1) { + // Try to decode a stream .... + std::ifstream is; + is.open(argv[1],std::ios::binary); + int len = 0; + char bl[2]; + } + std::cout<<"Hello world"< +#include +#include +#include "asn1_generator.h" + +#include "asn1_gen_auto_tag.h" + +namespace asn1 +{ +/** + * Default Cosntructor + */ +gen_auto_tag::gen_auto_tag(asn1::module *n) : asn1::generator(n) +{} + +gen_auto_tag::gen_auto_tag(asn1::module *n,asn1::module::modules_type &m) + : asn1::generator(n,m) +{ +} + + +void +gen_auto_tag::gen_typeref(std::ostream &os,typeref *type) +{ + GEN_LOG_DEBUG("type %s\n",type->name().c_str()); +} + +void +gen_auto_tag::gen_seq(std::ostream &os,std::string &scope,asn1::sequence *type,bool priv) +{ + asn1::node *n= type->identifier(); + asn1::node::iterator lit; + asn1::constructed *params = n->parameters(); + int i = 0; + + os<cpp_name()<<" {\n"; + // default constructor + // I should probaly push optionnal attributes and OBEJECTS in a stack and add a initializer here. + for (asn1::node::iterator it = type->begin(); it != type->end() ; it++,i++) + { + asn1::field *f = dynamic_cast(*it); + asn1::node *attr_type = f->get_type(); + //TODO: is this correct ? + if (f->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + os<type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + std::string s = scope+"\t"; + attr_type->tag(tag); + gen_seq(os,s,attr_type->as_sequence()); + } + break; + case asn1::type::ASN1_SET: + { + std::string s = scope+"\t"; + attr_type->tag(tag); + gen_set(os,s,attr_type->as_set()); + } + break; + case asn1::type::ASN1_CHOICE: + { + std::string s = scope+"\t"; + tag.m_mode = asn1::node::tag_type::TM_EXPLICIT; + attr_type->tag(tag); + gen_choice(os,s,attr_type->as_choice()); + } + break; + default: + attr_type->tag(tag); + ; + } + } + + } // end for + os<identifier(); + asn1::node::iterator lit; + asn1::node *params = n->parameters(); + int i = 0; + /* + * Try to handler sequence of sequence + */ +#if 0 + if ( type == NULL) + { + os<as_set(); + } +#endif + + os<cpp_name()<<" {\n"; + // default constructor + // I should probaly push optionnal attributes and OBEJECTS in a stack and add a initializer here. + for ( asn1::node::iterator it = type->begin() + ; it != type->end() ; it++,i++) + { + asn1::field *f = dynamic_cast(*it); + asn1::node *attr_type = f->get_type(); + if ((*it)->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + os<type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + std::string s = scope+"\t"; + attr_type->tag(tag); + gen_seq(os,s,attr_type->as_sequence()); + } + break; + case asn1::type::ASN1_SET: + { + std::string s = scope+"\t"; + attr_type->tag(tag); + gen_set(os,s,attr_type->as_set()); + } + break; + case asn1::type::ASN1_CHOICE: + { + std::string s = scope+"\t"; + tag.m_mode = asn1::node::tag_type::TM_EXPLICIT; + attr_type->tag(tag); + gen_choice(os,s,attr_type->as_choice()); + } + break; + default: + attr_type->tag(tag); + ; + } + } + + } // end for + os<identifier(); + asn1::node::iterator it; + int i = 0; + + it = type->begin(); + asn1::node::iterator lit = type->begin(); + os<cpp_name()<<" {\n"; + // Parameter stuff here + // switch case + for (; lit != type->end() ; ++lit,i++) + { + asn1::field *f = dynamic_cast(*lit); + asn1::node *attr_type = f->get_type(); + if ((*lit)->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + os<cpp_name()<<" ["<name(); + os<type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + std::string s = scope+"\t"; + attr_type->tag(tag); + gen_seq(os,s,attr_type->as_sequence()); + } + break; + case asn1::type::ASN1_SET: + { + std::string s = scope+"\t"; + attr_type->tag(tag); + gen_set(os,s,attr_type->as_set()); + } + break; + case asn1::type::ASN1_CHOICE: + { + std::string s = scope+"\t"; + tag.m_mode = asn1::node::tag_type::TM_EXPLICIT; + attr_type->tag(tag); + gen_choice(os,s,attr_type->as_choice()); + } + break; + default: + attr_type->tag(tag); + ; + } // End switch + } + } //end for +} + + +void gen_auto_tag::gen_typedef(std::ostream &os,asn1::typenode *type) +{ + + if (type != NULL) + switch (type->type_id()()) + { + case asn1::type::ASN1_REFERENCE: + { + std::cout<<"__FUNCTION__"<<" ERROR "<cpp_name()<tag().m_value != -1) + { + if (type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT) + { + } + } + + } + break; + case asn1::type::ASN1_INTEGER: + { + } + break; + case asn1::type::ASN1_SEQUENCE: + { + std::string scope(""); + gen_seq(os,scope,type->as_sequence()); + return ; + } + break; + case asn1::type::ASN1_SEQUENCE_OF: + { + asn1::node *ns = NULL; + asn1::typenode *seqof_type = type->get_eltype(); + if (type_in_imports(seqof_type,&ns) ) { + } else { + switch (seqof_type->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + std::string scope("\t"); + seqof_type->name(type->identifier_cpp_name()+"_type"); + gen_seq(os,scope,seqof_type->as_sequence()); + } + break; + case asn1::type::ASN1_CHOICE: + case asn1::type::ASN1_SET: + default: + ; + } + } + } + break; + case asn1::type::ASN1_SET: + { + std::string scope("\t"); + gen_set(os,scope,type->as_set()); + return ; + } + break; + case asn1::type::ASN1_SET_OF: + { + } + break; + case asn1::type::ASN1_CHOICE: + { + std::string scope("\t"); + gen_choice(os,scope,type->as_choice()); + return; + } + break; + default: + ; + }; + + +} + + + + +/** + * + */ +void gen_auto_tag::gen_module(std::ostream &os,asn1::module *n) +{ + asn1::import_list *imports = n->imports(); + // Add include for external dependencies + asn1::node::tag_type t = n->tag(); + + if (imports != NULL) + { + for (asn1::node::iterator it = imports->begin(); it!= imports->end(); it++) + { + /**/ + // Loop over items and check if OPERATION is imported + } + + } + + + n->sort_childs(); + asn1::node::iterator it = (n)->begin(); + + if (t.m_mode == asn1::node::tag_type::TM_AUTOMATIC) + { + for (; it != (n)->end() ; it++) + { + asn1::assignment *a = (*it)->as_assignment(); + std::cout<<"gen_auto_tag::"<<__FUNCTION__<<" process "<<(*it)->name(); + std::cout.flush(); + if (a->get_type() != NULL) + { + if ( (*it)->is_generated()) + { + std::cout<<" ALREADY PROCESSED "<meta_id()() ) + { + case asn1::meta::VALUE: + { + } + break; + case asn1::meta::VALUESET: + { + } + break; + case asn1::meta::TYPE: + { + gen_typedef(os,a->get_type()); + } + break; + case asn1::meta::TYPEREF: + { + gen_typeref(os,a->get_type()->as_typeref()); + } + break; + case asn1::meta::OBJECT: + { + // gen_object(os,*it); + } + break; + case asn1::meta::OBJECTCLASS: + { + std::cout<<"gen_uto_tag::"<<__FUNCTION__<<"gen object_class OBJECT CLASS "<<(*it)->cpp_name()<name()<set_generated(true); + // No coloration for this + //(*it)->set_color(asn1::node::CL_RED); + } else + { + std::cout<<" no type "<<(*it)->name(); + } + std::cout<name().c_str()); + } +} + + +} diff --git a/libgen/asn1_gen_auto_tag.h b/libgen/asn1_gen_auto_tag.h new file mode 100644 index 0000000..f1e29bd --- /dev/null +++ b/libgen/asn1_gen_auto_tag.h @@ -0,0 +1,46 @@ +#ifndef ASN1_GENERATOR_AUTO_TAG_H__ +#define ASN1_GENERATOR_AUTO_TAG_H__ +#include +#include "asn1_generator.h" + +namespace asn1 +{ + +class gen_auto_tag : public asn1::generator +{ + public: + gen_auto_tag(module *n = NULL) ; + + gen_auto_tag(module *root_m,asn1::module::modules_type &m_) ; + + virtual ~gen_auto_tag() {}; + + // Tells if a the structure should be in the form of templale + // or not + + virtual void gen_const(std::ostream &os,node *) {} ; + + virtual void gen_typedef(std::ostream &os,typenode *) ; + + virtual void gen_typeref(std::ostream &os,typeref *) ; + + virtual void gen_object(std::ostream &os,node *) {}; + + virtual void gen_module(std::ostream &os,module *) ; + + void gen_seq(std::ostream &os,std::string &scope,asn1::sequence *n,bool priv = false); + + void gen_set(std::ostream &os,std::string &scope,asn1::set *n,bool priv = false); + + void gen_choice(std::ostream &os,std::string &scope,asn1::choice *n,bool priv = false); + + /* Usefull object functions */ + protected: +}; + +} + +/* + * vim:et:sw=2:ts=2 + */ +#endif diff --git a/libgen/asn1_gen_codec_cpp.cpp b/libgen/asn1_gen_codec_cpp.cpp new file mode 100644 index 0000000..73d42dd --- /dev/null +++ b/libgen/asn1_gen_codec_cpp.cpp @@ -0,0 +1,1517 @@ +#include +#include +#include +#include +#include +#include + +#include "asn1_gen_config.h" +#include +#include +#include + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_DIRECT_H +#include +#endif + + +#include "asn1_generator.h" + + +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +// helper classes to split +#include "asn1_generator_helper.h" +#include "cpp/cgcpp_helper.h" +#include "cpp/cgh_construct.h" +#include "cpp/cgcpph_sequence.h" +#include "cpp/cgcpph_set.h" +#include "cpp/cgcpph_choice.h" +#include "cpp/cgcpph_primitive.h" +#include "cpp/cgcpph_enumerated.h" +#include "cpp/cgcpph_octetstring.h" +#include "cpp/cgcpph_bitstring.h" +#include "cpp/cgcpph_integer.h" +#include "cpp/cgcpph_typeref.h" +#include "cpp/cgh_object.h" +#include "cpp/cgcpph_object.h" +#include "cpp/cgcpph_import.h" +#include "cpp/cgcpph_boolean.h" +#include "cpp/cgcpph_oid.h" +#include "cpp/cgcpph_string.h" +#include "cpp/cgcpph_sequenceof.h" +#include "cpp/cgcpph_setof.h" +#include "adt/asn1_visitor.h" + + +generate_codec_cpp::generate_codec_cpp(asn1::module *n,asn1::module::modules_type &m,gen_constraints &c) + : generate_cpp(n,m),m_gen_constraints(c) +{ + +} +/** + * generate template instantiation in .hpp file + * + */ +struct gen_include_hpp +{ + gen_include_hpp(std::ostream &os,generate_codec_cpp &g) + : m_os(os), m_Gen(g) + { + } + + void operator ()(asn1::module *n) + { + if (!std::string("Remote-Operations-Useful-Definitions") + .compare(n->name())) + { + m_os<<"#include \""<cpp_name()<<".h\"\n"; + } + m_os<<"#include \""<cpp_name()<<".hpp\"\n"; + } + protected: + std::ostream &m_os; + generate_codec_cpp &m_Gen; +}; + +class do_gencpp_assignment : public assignment_visitor +{ + protected: + generate_codec_cpp &m_gen; + std::ostream &m_os; + std::fstream &m_sep_os; /* separe file for each assignment */ + std::fstream &m_log; + public: + do_gencpp_assignment( generate_codec_cpp &_h + , std::ostream &os + , std::fstream &sos + ) + : m_os(os),m_gen(_h),m_log(_h.logger()) + , m_sep_os(sos) + {}; + // Main processing function per assignment + void operator ()(asn1::node *n) + { + asn1::typenode *type = n->as_assignment()->get_type(); + std::string path = n->cpp_name()+".cpp"; + GEN_LOG_DEBUG( "Process item=%s meta=%d\n" + , n->name().c_str() + , n->meta_id()()); + if ( ! type) + return; + + if ( n->is_generated()) + { + GEN_LOG_DEBUG("%s already generated\n",n->name().c_str()); + return; + } + if (m_gen.with_split_cpp()) + { + m_gen.open_assignment_stream(m_sep_os,n->as_assignment()); + m_gen.gen_include_header(m_sep_os); + } + visit(n->as_assignment()); + if (m_sep_os.is_open()) + m_sep_os.close(); + + n->set_color(asn1::node::CL_RED); + } +#define ASSIGNMENT(Ty,Code) \ + void visit_##Ty(asn1::Ty##_assignment *a) Code + + ASSIGNMENT(typeref,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "meta of %s is TYPEREF parameterized: %d\n" + , a->name().c_str(),params); + if (m_sep_os.is_open()) + { + m_gen.gen_typeref(m_sep_os,a->get_type()->as_typeref()); + } else + m_gen.gen_typeref(m_os,a->get_type()->as_typeref()); + }) + ASSIGNMENT(type,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "meta of %s is TYPE parameterized: %d\n" + , a->name().c_str(),params); + if (m_sep_os.is_open()) + { + m_gen.gen_typedef(m_sep_os,a->get_type()); + } else + m_gen.gen_typedef(m_os,a->get_type()); + }) + ASSIGNMENT(value,{ + GEN_LOG_DEBUG("meta of %s is VALUE\n",a->name().c_str()); + m_gen.gen_const(m_os,a->get_type()); + }) + ASSIGNMENT(valueset,{ + GEN_LOG_DEBUG( "meta of %s is VALUESET do nothing ?\n" + , a->name().c_str()); + m_gen.gen_const(m_os,a->get_type()); + }) + ASSIGNMENT(object,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "meta of %s is OBJECT parameterized: %d\n" + , a->name().c_str(),params); + if (m_sep_os.is_open()) + { + m_gen.gen_object(m_sep_os,a); + } else + m_gen.gen_object(m_os,a); + }) + ASSIGNMENT(objectclass,{ + }) + ASSIGNMENT(objectset,{ + GEN_LOG_DEBUG("meta of %s is OBJECT SET\n",a->name().c_str()); + m_gen.gen_objectset(m_os,*a->get_objectset()); + }) + ASSIGNMENT(objectfield,{}) + +}; + + +/** + * Create directory for cpp files. + * current dir"/" module cpp_name + */ +bool +generate_codec_cpp::make_module_dir(asn1::module *_module) +{ + struct stat st; + + if (stat(m_module_path.c_str(),&st) == -1) { +#ifdef WIN32 + _mkdir(m_module_path.c_str()); +#else + mkdir(m_module_path.c_str(),0777); +#endif + } + return true; +} + + +bool +generate_codec_cpp::open_assignment_stream(std::fstream &_stream,asn1::assignment *_a) +{ + std::string f (m_module_path); + f+= "/" + _a->cpp_name()+".cpp"; + _stream.open(f.c_str(),std::fstream::out); + return _stream.is_open(); +} + + +void +generate_codec_cpp::generate_constraints(std::ostream &os) +{ + gen_constraints::constraintSetIterator it = m_gen_constraints.begin(); + os<<"static asn1::types::constraint_desc gConstraints[] = {\n"; + os<<"\t { asn1::types::un_constrained ,0 ,0 }\n"; + for (; it != m_gen_constraints.end() + ; ++it) + { + asn1::constraint &_constraint(*(*it).m_constraint); + + switch ( _constraint.type()) + { + case asn1::constraint::CT_SIZE: + { + asn1::ctype_size *cts = _constraint.as_constraint_size(); + assert((cts != NULL) && "cts is NULL not good"); + if (asn1::celt_value *cv = cts->get_value()) + { + assert(cv->get_valuetype() && "get_valuetype returned NULL"); + os<<"\t, { asn1::types::partial_constrained ,"<get_valuetype()->value_long()<<" ,0 }\n"; + } else if (asn1::constraint_range *cr = cts->get_range()) + { + long _min,_max; + if (! cr->get_min_max(_min,_max)) + { + std::cerr<<"generate_constraints size get_min_max error !!! "<name()<get_min_max(_min,_max)) + { + std::cerr<<"generate_constraints get_min_max error !!! "<name()<imports(); + os<<"//\n// Automatic c++ generated code by asn1p copyright @ Andre EBERSOLD 2018 - 2022\n"; + os<<"// using namespace "<cpp_name()<<""<begin() + ; it!= imports->end(); it++) + { + asn1::import *import = dynamic_cast( *it); + if (import) + { + cgcpph_import imp_gen(*this,os,*import); + imp_gen.generate(); + // Keep modules with objects + asn1::module *mi = m_resolver.module(import->identifier()->name()); + if (mi && mi->has_objects()) + { + modules_with_objects.push_back(mi); + } else + { + os<<"// Module "<name()<<" no objects"<cpp_name()<<".h\""<has_objects()) + os<<"#include \""<cpp_name()<<".hpp\""<imports(); +#ifdef WIN32 + char *cd = _getcwd(NULL,0); +#else + char *cd = getcwd(NULL,0); +#endif + std::string cdir(cd); + m_module_path = cdir+"/"+m_module->cpp_name(); + delete cd; + + GEN_LOG_DEBUG("MODULE %s path=%s\n" + , n->name().c_str() + , m_module_path.c_str() + ); + std::cout<<"gen_codec_cpp module "<name()<cpp_name()<<"_codec.hpp\""<cpp_name()<<" {\n"<sort_childs(); + // Go through assignments and generate + std::fstream sos; + do_gencpp_assignment dogen(*this,os,sos); + + std::for_each( n->begin() + , n->end() + , dogen + ); + + os<<"}"<(type); + assert(type->identifier() != NULL); + os<<"// gen_typeref "<name()<(type); + cgcpph_octet_string o_gen(*this,os,o); + o_gen.generate(); + } + break; + case asn1::type::ASN1_NULL: + { + asn1::primitive &i = dynamic_cast(type); + cgcpph_primitive p_gen(*this,os,i); + p_gen.generate(); + } + break; + case asn1::type::ASN1_STRING: + case asn1::type::ASN1_STRING_UniversalString: + break; + case asn1::type::ASN1_STRING_UTF8String : + case asn1::type::ASN1_STRING_GeneralString: + case asn1::type::ASN1_STRING_T61String: + case asn1::type::ASN1_STRING_VideotexString: + case asn1::type::ASN1_STRING_ObjectDescriptor: + break; + case asn1::type::ASN1_STRING_GraphicString: + case asn1::type::ASN1_STRING_BMPString: + case asn1::type::ASN1_STRING_IA5String: + case asn1::type::ASN1_STRING_VisibleString: + case asn1::type::ASN1_STRING_ISO646String: /* aka VisibleString */ + case asn1::type::ASN1_STRING_PrintableString: + case asn1::type::ASN1_STRING_NumericString: + case asn1::type::ASN1_STRING_TeletexString: + { + asn1::primitive &i = dynamic_cast(type); + cgcpph_string i_gen(*this,os,i); + i_gen.generate(); + } + break; + //case asn1::type::ASN1_UNIVERSAL: { } break; + case asn1::type::ASN1_INTEGER: + { + asn1::integer &i = dynamic_cast(type); + cgcpph_integer i_gen(*this,os,i); + i_gen.generate(); + } + break; + case asn1::type::ASN1_BIT_STRING: + { + asn1::bit_string &bs = dynamic_cast(type); + gen_bitstring(os,"",bs,false); + } + break; + case asn1::type::ASN1_BOOLEAN: + { + asn1::boolean &i = dynamic_cast(type); + cgcpph_boolean i_gen(*this,os,i); + i_gen.generate(); + } + break; + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + asn1::object_identifier &i = dynamic_cast(type); + cgcpph_oid i_gen(*this,os,i); + i_gen.generate(); + } + break; + default: + GEN_LOG_ERROR("type %s default case BAD path=%s\n" + , type.name().c_str() + , m_module_path.c_str() + ); + ; + }; +} + +/** + * gen_typedef + * + */ +void generate_codec_cpp::gen_typedef(std::ostream &os,asn1::typenode *type) +{ + + if (type->identifier() != NULL) + { + GEN_LOG_DEBUG( "identifier_name=%s type_id=%d\n" + , type->identifier_name().c_str() + , type->type_id()()); + } else { + GEN_LOG_WARN( "ANONYMOUS name=%s type_id=%d\n" + , type->name().c_str() + , type->type_id()()); + } + switch (type->type_id()()) + { + case asn1::type::INVALID: + { + std::cerr<<"ERROR UNDEFINED TYPE "<name(); + std::cerr<<" ident:"<identifier_name()<as_typeref()); + } + break; + case asn1::type::ASN1_NULL: + case asn1::type::ASN1_BIT_STRING: + case asn1::type::ASN1_OCTET_STRING: + case asn1::type::ASN1_STRING: + case asn1::type::ASN1_STRING_VisibleString: + case asn1::type::ASN1_STRING_ISO646String: /* aka VisibleString */ + case asn1::type::ASN1_STRING_UniversalString: + case asn1::type::ASN1_STRING_BMPString: + case asn1::type::ASN1_STRING_UTF8String : + case asn1::type::ASN1_STRING_GeneralString: + case asn1::type::ASN1_STRING_GraphicString: + case asn1::type::ASN1_STRING_T61String: + case asn1::type::ASN1_STRING_VideotexString: + case asn1::type::ASN1_STRING_ObjectDescriptor: + case asn1::type::ASN1_STRING_IA5String: + case asn1::type::ASN1_STRING_PrintableString: + case asn1::type::ASN1_STRING_NumericString: + case asn1::type::ASN1_STRING_TeletexString: + //case asn1::type::ASN1_UNIVERSAL: + case asn1::type::ASN1_INTEGER: + case asn1::type::ASN1_BOOLEAN: + case asn1::type::ASN1_REAL: + case asn1::type::ASN1_OBJECT_IDENTIFIER: + case asn1::type::ASN1_RELATIVE_OID: + { + gen_primitive(os,*type); + } + break; + case asn1::type::ASN1_SEQUENCE: + { + asn1::node *params = type->parameters(); + GEN_LOG_DEBUG("identifier_name=%s type_id=%d params=%d \n" + ,type->identifier_name().c_str() + ,type->type_id()() + ,(params == NULL)?0:1 + ); + + std::string scope(""); + if (params == NULL) { + gen_seq(os,scope,type,false); + } else { + GEN_LOG_WARN("%s has parameters don't generate implementation \n" + ,type->identifier_name().c_str()); + } + + } + break; + case asn1::type::ASN1_SEQUENCE_OF: + { + asn1::typenode *seqof_type = type->get_eltype(); + std::cout.flush(); + if ( seqof_type->type_id()() == asn1::type::ASN1_SEQUENCE + || seqof_type->type_id()() == asn1::type::ASN1_CHOICE + ) + { + // Generate codec for (private class) + // which does not exists in this case + if (with_source_comment()) + os<<"//private /*SEQUENCE_OF "<cpp_name()<<" */"<as_typenode()); + } + std::string scope(""); + cgcpph_sequenceof gseqof(*this,os,*dynamic_cast(type)); + gseqof.generate(); + } + break; + case asn1::type::ASN1_SET: + { + asn1::set *settype = type->as_set(); + std::string scope(""); + gen_set(os,scope,settype); + } + break; + case asn1::type::ASN1_SET_OF: + { + asn1::typenode *setof_type = type->get_eltype(); + if (with_source_comment()) + os<<"//typedef /*SET_OF*/ "<identifier_cpp_name()<identifier_name().c_str() + ,type->type_id()() + ,type->is_private() + ); + if ( setof_type->type_id()() == asn1::type::ASN1_SEQUENCE + || setof_type->type_id()() == asn1::type::ASN1_CHOICE + ) + { + GEN_LOG_DEBUG("SET OF type id_name=%s type_id=%d is_priv=%d \n" + ,setof_type->identifier_name().c_str() + ,setof_type->type_id()() + ,setof_type->is_private() + ); + // Generate codec for (private class) + // which does not exists in this case + if (with_source_comment()) + os<<"//private /*SET_OF "<cpp_name()<<" is private: "<is_private()<<"*/"<(type)); + gensetof.generate(); + } + break; + case asn1::type::ASN1_CHOICE: + { + std::string scope(""); + gen_choice(os,scope,type); + } + break; + case asn1::type::ASN1_ENUMERATED: + { + std::string scope(""); + gen_enumerated(os,scope,type); + } + break; + case asn1::type::ASN1_ANY: + break; + default: + GEN_LOG_ERROR("UNHANDLED type id_name=%s type_id=%d is_priv=%d \n" + ,type->identifier_name().c_str() + ,type->type_id()() + ,type->is_private() + ); + //exit(0); + }; + os<<"\n"; + +} + + +/** + * + */ +void +generate_codec_cpp:: +gen_attribute_constrained_nencode( std::ostream &os + , const std::string &scope + , const std::string &indent + , asn1::field *attribute) +{ + asn1::typenode *attribute_type = (attribute)->get_type(); + asn1::constraint *c = *(attribute_type->constraint_begin()); + if (c->type() == asn1::constraint::CA_CRC) { + asn1::constraint::const_iterator it = c->begin(); + asn1::constraint *val = *it; ++it; + asn1::constraint *at = *it; + if (with_source_comment()) + { + os<value()->cpp_name(); + os<<" @ "<value()->cpp_name()<<" Type="<cpp_name()<<"\n"; + } + + if (attribute_type->as_typeref() && attribute_type->as_typeref()->is_complex()) + { + asn1::node *imp = NULL; + asn1::reference *r = attribute_type->as_typeref()->get_reference(); + std::string lr = r->back().m_identifier; + lr[0]='_'; + std::string lname(r->front().m_identifier); + std::string cls; + cls.resize(lname.size()); + std::transform(lname.begin(),lname.end(),cls.begin(),asn1::op_substitute); + // Check if pointer exists + os<cpp_name()<<".is_nul() )\n"; + os<front().m_identifier,&imp)) + { + os<cpp_name()<<"->encode"<cpp_name()<<"->"; + os<<"encode"<cpp_name()<<" is NULL\");\n"; + os<value()->cpp_name()<<"[i]->"; + os<<"encode(ctx); /* constrained CA CRC*/"<type() == asn1::constraint::CT_SIZE) + { + os<cpp_name() <<" size constrained to be checked\");\n"; + os<<""<cpp_name(); + os<<".encode(ctx); /* constrained*/"<type() == asn1::constraint::EL_RANGE) + { + os<cpp_name() <<" range constrained to be checked\");\n"; + os<<""<cpp_name(); + os<<".encode(ctx); /* constrained*/"<cpp_name() <<" other constrained to be checked\");\n"; + os<<""<cpp_name(); + os<<".encode(ctx); /* constrained*/"<get_type(); + asn1::constraint *c = *(attribute_type->constraint_begin()); + if (c->type() == asn1::constraint::CA_CRC) + { + std::cerr<<"generate_codec_cpp::"<<__FUNCTION__<<" WARN "<name()<<" has CRC"<begin(); + asn1::celt_type *val = (*it)->as_celt_type(); + asn1::typeref *vtr = val->get_type(); + ++it; + asn1::constraint *at = *it; + assert(val && "gen_attribute_constraint_ndecode should needs evolution"); + std::string setname; + if ( vtr->is_imported(setname)) + { + setname = asn1::cpp_name(setname); + setname.append("::"); + setname.append(vtr->cpp_name()); + } else + setname = vtr->cpp_name(); + os<value()->cpp_name()<<"\n"; + os<value() Then get the type to figure out + // which attribute in object to use. + { + asn1::constructed *ccontainer = attribute->get_parent() + ->as_constructed(); + asn1::node::iterator itt = + std::find_if( ccontainer->begin() + , ccontainer->end() + , asn1::find_node(at->value()->name())); + assert(itt != ccontainer->end()); + asn1::field *f = dynamic_cast(*itt); + asn1::typeref *at_ref = dynamic_cast(f->get_type()); + // Not always true + std::cerr<<"generate_codec_cpp::"<<__FUNCTION__<<" at_ref "<name(); + std::cerr<<" Simple: "<is_simple()<get_objectclass(); + // This is wierd, I don't think the resolver is required here. + // I only need the last field + std::cerr<<"generate_codec_cpp::"<<__FUNCTION__<<" at_ref "<name(); + std::cerr<"<value()->cpp_name()<<"))\n"; + os<as_typeref() && attribute_type->as_typeref()->is_complex()) + { + asn1::reference *r = attribute_type->as_typeref()->get_reference(); + std::string lr = r->back().m_identifier; + lr[0]='_'; + os<cpp_name()<<" = "; + os<"<<"clone();\n"; + os<cpp_name()<<"->decode"<value()->cpp_name()<<"[i]->"<<"codec(ctx,"<<(attribute)->cpp_name()<<",CODEC_DECODE); /* constrained CA CRC*/"<cpp_name()<<" Not FOUND\");\n"; + os<cpp_name()<<".decode(ctx);"; + os<<"/* constrained "<type()<<" */"<type_id()() ) + { + case asn1::type::ASN1_REFERENCE: + { + asn1::typeref *tref = dynamic_cast(attr_type); + asn1::node *real_type = m_resolver.resolve(*tref); + // New way to handle reference + // gen_composite_attribute_ref(os,scope,attr_type); + if (tref->is_complex() && !tref->is_external()) + { + os<<"std::setw(indent+"<type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_TF: + os<<"\tif ( ! s."<printf(os); /**/\n"; + os<<"\t}\n"; + os<<"\tos<printf(os);\n"; + os<<"\t}\n"; + os<<"\tos<as_sequence(); + assert(type != NULL); + asn1::node *ident = type->identifier(); + asn1::node::iterator lit = (type)->begin(); + GEN_LOG_DEBUG("gen_seq: \n"); + assert(type->type_id()() == asn1::type::ASN1_SEQUENCE); + // try new helper + // New way to handle and isolate sequence code generation + asn1::sequence *seq = dynamic_cast(type); + assert(seq != NULL); + assert(ident != NULL); + GEN_LOG_ERROR("gen_seq: %s\n",ident->cpp_name().c_str()); + assert(seq->is_private() == priv); + // compute strutName + struct_name(type,structName); + + if (ident) + { + GEN_LOG_DEBUG("scope=%s ident= %s type=%s parameters=%d\n",scope.c_str(), + ident->cpp_name().c_str(), + type->cpp_name().c_str(), + ( ident->parameters() == NULL)?0:1 + ); + } + os<<"//generate_codec_cpp::"<<__FUNCTION__<<" "<cpp_name().c_str(),scope.c_str(),priv); + + os<<"//"<<__FUNCTION__<<" "<cpp_name()<<" type_id="<type_id()(); + os<<" ident="<identifier_cpp_name()<(type); + assert(set != NULL); + // This is the right test that should be performed + assert(dynamic_cast(type) != NULL); + + cgcpph_set set_gen(*this,os,*set); + set_gen.generate(scope); +} + +/** + * Dead code below. + */ +void generate_codec_cpp::gen_set_of(std::ostream &os,asn1::node *type) +{ + assert(0); +} + +/** + * const object set is an elemnt_set_spec + * which are contraints + * + */ +void generate_codec_cpp::gen_objectset(std::ostream &os,asn1::objectset &objs) +{ + GEN_LOG_ERROR( "generate_codec_cpp:%s %s type=%s\n" + , __FUNCTION__ + , objs.name().c_str() + , objs.type_id().name()); + asn1::typeref *tref = objs.get_classref(); + std::string otype = tref->get_reference()->name(); + asn1::node *ns; + os<<"\n// "<<__FUNCTION__<<" start "<type()) + { + case asn1::constraint::EL_VALUE: + { + std::string type_name((*values)->value()->name()); + asn1::node::iterator ref = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(type_name)); + if (ref != m_module->end()) + { + asn1::node *ntype = *ref; + std::cerr<<"generate_codec_cpp::"<<__FUNCTION__<<" "<name()<parameters()) + { + std::cerr<<"generate_codec_cpp::"<<__FUNCTION__<<" "; + std::cerr<name()<<" has parameters"<name()<<" has parameters NO GEN YET"<as_assignment()); + } + } + break; + default: + ; + }; + } + } else { + GEN_LOG_ERROR( "generate_codec_cpp:%s EMPTY v %s type=%s\n" + , __FUNCTION__ + , objs.name().c_str() + , objs.type_id().name()); + } + if (objs.get_assignment()->parameters()) + { + std::cerr<<"generate_codec_cpp::"<<__FUNCTION__<<" "<cpp_name()<<"::I"<get_reference()->cpp_name()<<" *"<get_reference()->cpp_name()<<" *"<type() == asn1::constraint::CA_UNI) + { + asn1::constraint *first = (*objs.constraint_begin()); + asn1::constraint::const_iterator values = first->begin(); + for (; values != first->end(); ++values) + { + if (values != first->begin()) + os<<","; + switch( (*values)->type()) + { + case asn1::constraint::EL_VALUE: + { + asn1::node *ns; + if (type_in_imports((*values)->value()->name(),&ns)) { + os<<" new "<cpp_name()<<"::"<<(*values)->value()->cpp_name()<<"()\n"; + } else + os<<" new "<<(*values)->value()->cpp_name()<<"()\n"; + } + break; + default: + ; + }; + os<<"\t"; + } + os<<", NULL\n"; + } + os<<"};"; +} + +/** + * const encoding and decoding + * + */ +void generate_codec_cpp::gen_const( std::ostream &os + , asn1::node *type) +{ + if (with_source_comment()) + os<<"// generate_codec_cpp::"<<__FUNCTION__<<"\n"; + + switch(type->type_id()()) + { + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + if (with_source_comment()) + os<<"// const OID "<<" "<identifier_cpp_name(); + } + break; + case asn1::type::ASN1_VALUESET: + { + GEN_LOG_ERROR("generate_codec_cpp: %s type=%s\n",type->name().c_str(),type->type_id().name()); + std::cerr<<__FUNCTION__<<" "<name()<identifier() ) { + os<<"//const "<cpp_name()<<"\t\t= "<identifier_cpp_name()<<";"; + } else { + os<<"//const "<cpp_name()<<"\t\t= ? no identifier"<<";"; + } + ; + } + os<identifier(); + asn1::node *real_type = + m_resolver.resolve(dynamic_cast(*type)); + if (dynamic_cast(type)) + { + os<<"// ValueSet ref "<name()<cpp_name()<<"::"<cpp_name()<<"()\n"; + + switch (real_type->type_id()()) + { + case asn1::type::ASN1_CHOICE: + { + os<<"{\n}\n"; + } + break; + case asn1::type::ASN1_BOOLEAN: + os<<"{\n}\n"; + break; + case asn1::type::ASN1_INTEGER: + os<<"{\n}\n"; + break; + default: + std::cerr<<"gen_const_reference not handled type"<get_type(); + + // New way + asn1::node *real_type = + m_resolver.resolve(dynamic_cast(*type)); + if (real_type != NULL) + { + asn1::object *obj = dynamic_cast(type->get_eltype()); + asn1::classdef *cdef = dynamic_cast(real_type); + assert( obj != NULL); + assert( cdef != NULL); + + cgcpph_object obj_gen(*this,os,*obj,*cdef); + if ( ! n->is_generated()) + obj_gen.generate(); + + } else + { + std::cerr<<"OBJECT CLASS not found "<name()<set_generated(true); + + n->set_color(asn1::node::CL_RED); + +} + + +void +generate_codec_cpp::gen_enumerated(std::ostream &os,const std::string &scope,asn1::node *type ) +{ + std::string lname; + assert(type->type_id()() == asn1::type::ASN1_ENUMERATED ); + + asn1::enumerated *enumerated = dynamic_cast(type); + assert(enumerated != NULL); + + cgcpph_enumerated set_gen(*this,os,*enumerated); + set_gen.generate(scope); + +} + +// +// +// +void generate_codec_cpp::gen_template_params( std::ostream &os + , asn1::constructed *params) +{ + asn1::node::node_list nl; + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} + +// +// +// +void generate_codec_cpp::gen_template_signature(std::ostream &os,asn1::node *type) +{ + asn1::node::node_list nl; + asn1::node *ident = NULL; + asn1::constructed *params = NULL; + assert(type != NULL); + + ident = type->identifier(); + if (ident == NULL) + { + os<<"// no ident not a template"<parameters() && is_template(ident->parameters()) ) + { + params = ident->parameters(); + os<<"template "; + } else { + return ; + } + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; + os<identifier(); + if (ident == NULL) + { + return; + } + if (ident && ident->parameters() && is_template(ident->parameters()) ) + { + params = ident->parameters(); + } else { + return ; + } + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<">"; +} + +/** + * + */ +void generate_codec_cpp::gen_private( std::ostream &os + , const std::string &scope + , asn1::constructed *_type) +{ + asn1::constructed *type = _type->as_constructed(); + std::string structName; + asn1::node::iterator attr_it; + + assert( (type != NULL ) + && + ( (type->type_id()() == asn1::type::ASN1_CHOICE) + || (type->type_id()() == asn1::type::ASN1_SET) + || (type->type_id()() == asn1::type::ASN1_SEQUENCE) + ) + ); + + struct_name(type,structName); + + for ( attr_it = type->begin() + ; attr_it != type->end() + ; ++attr_it) + { + asn1::field *f = dynamic_cast(*attr_it); + asn1::typenode *attr_type = f->get_type(); + // Extension markers don't have a type + // assert( attr_type != NULL); + if (attr_type != NULL) + { + switch (attr_type->type_id()()) + { + case asn1::type::ASN1_SEQUENCE_OF: + case asn1::type::ASN1_SET_OF: + { + asn1::node *softype = attr_type->get_eltype(); + GEN_LOG_DEBUG("call private seq of %s\n",(*attr_it)->cpp_name().c_str()); + if (softype->type_id()() >= asn1::type::ASN1_SEQUENCE && + softype->type_id()() <= asn1::type::ASN1_SET_OF) + { + gen_private_attribute(os,scope,attr_type->get_eltype()); + } + } + break; + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_SET: + case asn1::type::ASN1_ENUMERATED: + case asn1::type::ASN1_CHOICE: + if (type->identifier() != NULL) + { + GEN_LOG_DEBUG("call private seq of %s\n",(*attr_it)->cpp_name().c_str()); + gen_private_attribute(os,scope,attr_type); + } else { + GEN_LOG_ERROR("did not call private seq of %s\n",(*attr_it)->cpp_name().c_str()); + assert(0); + } + break; + defatult: + GEN_LOG_DEBUG("default not call private seq of %s\n",(*attr_it)->cpp_name().c_str()); + ; + } + } + + } +} + + +/** + * + * called for each attribute in sequence , choice or set. + * n can be of any type .... + * I'm missing the function that loops over the attributes. + * This function should be called gen private attribute + */ +void generate_codec_cpp::gen_private_attribute( std::ostream &os + , const std::string &scope + , asn1::typenode *n) +{ + asn1::node *params = NULL; + assert(n!=NULL); + if (n) + { + params = n->parameters(); + GEN_LOG_DEBUG(" scope=%s node=%s params: %d typeid=%d\n", + scope.c_str() + ,n->cpp_name().c_str() + ,(params==NULL)?0:1 + ,n->type_id()() + ); + os<<"//generate_codec_cpp::"<<__FUNCTION__<<" "<cpp_name()<type_id()()) + { + case asn1::type::ASN1_CHOICE: + gen_choice(os,scope,n,true); + break; + case asn1::type::ASN1_SEQUENCE: + gen_seq(os,scope,n,true); + break; + case asn1::type::ASN1_SET: + gen_set(os,scope,n->as_set()); + break; + case asn1::type::ASN1_SET_OF: + case asn1::type::ASN1_SEQUENCE_OF: + { + asn1::typenode *type = n; + asn1::typenode *subtype = type->get_eltype(); + assert(subtype != NULL); + os<<"// gen_private_attribute type SEQUENCE_OF ... \n"; + if (type->has_constraints()) + { + os<<"// I have constraints\n"; + } + switch (subtype->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + os<<"// gen_private_attribute type SEQUENCE_OF ... launch gen_seq \n"; + gen_seq(os,scope,subtype,true); + os<<"\n//end\n"; + break; + case asn1::type::ASN1_CHOICE: + os<<"// gen_private_attribute type SEQUENCE_OF ... launch gen_choice \n"; + gen_choice(os,scope,subtype,true); + os<<"\n//end\n"; + break; + default: + os<<"// gen_private_attribute type SEQ or SET OF ... type to be code \n"; + ; + } + } + break; + case asn1::type::ASN1_ENUMERATED : + gen_enumerated(os,scope,n); + break; + default: + GEN_LOG_DEBUG("Did not do anything for %s%s type_id=%d\n",scope.c_str(),n->cpp_name().c_str(),n->type_id()()); + ; + } +} + + +void +generate_codec_cpp::struct_name(asn1::node *type,std::string &structName) +{ + assert(type != NULL); + + if (type->is_private()) + { + structName = type->cpp_name(); + } else + { + structName = type->identifier_cpp_name(); + } +} +/* + * vim:et sw=2 ts=2 list: + */ diff --git a/libgen/asn1_gen_codec_cpp.h b/libgen/asn1_gen_codec_cpp.h new file mode 100644 index 0000000..8ad7160 --- /dev/null +++ b/libgen/asn1_gen_codec_cpp.h @@ -0,0 +1,158 @@ +#ifndef GEN_CODEC_CPP_H__ +#define GEN_CODEC_CPP_H__ +#include +#include +#include + +#include "libparser/asn1_parser_listener.h" +#include "asn1_gen_constraints.h" + + +/** + * + */ +class generate_codec_cpp : public generate_cpp +{ + protected: + generate_codec_cpp(const generate_codec_cpp &c) : + generate_cpp(c) + , m_gen_constraints(c.m_gen_constraints) + { std::cout<<"copy generate_codec_cpp\n"; } + public: + + generate_codec_cpp(asn1::module *n,gen_constraints &c) : generate_cpp(n) , m_gen_constraints(c) {}; + generate_codec_cpp(asn1::module *n,asn1::module::modules_type &m,gen_constraints &c); + + /**/ + void gen_attribute_constrained_ndecode( std::ostream &os + , const std::string &scope + , const std::string &indent + , asn1::field *attr); + + void gen_attribute_constrained_nencode( std::ostream &os + , const std::string &scope + , const std::string &indent + ,asn1::field *attr); + + /** + * + */ + void gen_decode_set(std::ostream &os,asn1::node *attribute); + + /** + * + */ + void gen_const(std::ostream &os,asn1::node *n); + /** + * + */ + void gen_objectset(std::ostream &os,asn1::objectset &n); + /** + * + */ + void gen_const_reference(std::ostream &os,asn1::node *n); + + /** + * + */ + void gen_enumerated(std::ostream &os,const std::string &scope,asn1::node *enum_node); + + // + // + // + void gen_typedef(std::ostream &os,asn1::typenode *n); + void gen_typeref(std::ostream &os,asn1::typeref *n); + /** + * generate structure for primitive typedefs Type ::= INTGER + * because integer is under constructed. That's a bit wierd + */ + void gen_primitive(std::ostream &os,asn1::typenode &n); + + void + gen_composite_attribute_printf( std::ostream &os + , const std::string &scope + , asn1::field &attribute + , asn1::node *params=NULL); + void gen_composite_attribute_ref(std::ostream &os + , const std::string &scope + , asn1::field *attribute + , asn1::node *params = NULL); + + void gen_template_params(std::ostream &os,asn1::constructed *type); + void gen_template_signature(std::ostream &os,asn1::node *type); + void gen_template_signature_class(std::ostream &os,asn1::node *type); + /** + * + */ + void gen_seq(std::ostream &os,const std::string &scope,asn1::node *n,bool priv=false); + + // Choice + + void gen_choice(std::ostream &os,const std::string &scope,asn1::node *n,bool priv = false); + + /** + * + */ + void gen_set( std::ostream &os + , const std::string &scope + , asn1::set *n); + + void gen_set_of(std::ostream &os,asn1::node *n); + /** + * SEQUENCE,CHOICE,SET might contain private SEQUENCE CHOICE or SET. + * I need to generate special codecs for these structures + * therefore gen_private node is either SEQ, SET, CHOICE container + * that loops over each attribute + * + */ + void gen_private( std::ostream &os + , const std::string &scope + , asn1::constructed *n); + /** + * called within gen_private + */ + void gen_private_attribute( std::ostream &os + , const std::string &scope + , asn1::typenode *n); + // bit string + void gen_bitstring( std::ostream &os + , const std::string &scope + , asn1::bit_string &n,bool priv=false); + /* + * Ros generation Code + */ + void gen_object(std::ostream &os,asn1::assignment *n); + + void gen_module(std::ostream &os,asn1::module *n); + /** + * + */ + void gen_include_header(std::ostream &os); + // Will be used by helper classes + void struct_name(asn1::node *type,std::string &structName); + /** + * _a (IN) : assignment + * _stream (INOUT): opened stream based on m_module_path and assignment cpp_name + * return true if stream is open + */ + bool open_assignment_stream(std::fstream &_stream,asn1::assignment *_a); + /** + * + */ + inline const std::string &get_module_path() const + { return m_module_path; } + protected: + void generate_constraints(std::ostream &os); + /** + * Create current dir + module cpp_name dir. + */ + bool make_module_dir(asn1::module *_module); + protected: + std::string m_module_path; + gen_constraints &m_gen_constraints; +}; + +/** + * vim:et:sw=2:ts=2 + */ +#endif diff --git a/libgen/asn1_gen_config.h.in b/libgen/asn1_gen_config.h.in new file mode 100644 index 0000000..b7e0ab5 --- /dev/null +++ b/libgen/asn1_gen_config.h.in @@ -0,0 +1,9 @@ +#cmakedefine HAVE_UNISTD_H +#cmakedefine HAVE_STDLIB_H +#cmakedefine HAVE_PTHREAD_H +#cmakedefine HAVE_DIRECT_H +#cmakedefine HAVE_STDINT_H +/* system function check*/ +#cmakedefine HAVE_GETCWD +#cmakedefine HAVE_MKDIR + diff --git a/libgen/asn1_gen_constraints.cpp b/libgen/asn1_gen_constraints.cpp new file mode 100644 index 0000000..46bb9f0 --- /dev/null +++ b/libgen/asn1_gen_constraints.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +#include "asn1_node.h" +#include "asn1_module.h" +#include "asn1_generator.h" + +#include "libparser/asn1_parser_listener.h" +#include "asn1_gen_constraints.h" + + +gen_constraints::gen_constraints() +{ + ; +} + +gen_constraints::~gen_constraints() +{ + std::cout<<"gen_constraints::~gen_contraints"<first<<" has "<second.size(); + std::cout<<" constraints"<second.begin(); + cit != mit->second.end(); + ++cit) + { + std::cout<<"\t"<m_count<<" "<m_constraint->name()< ret; + + local_constraint lc(c); + m_constraints.insert(lc); + ret = m_map[m_current_module].insert(lc); + if (ret.second == false) + { + it = ret.first; + (*it).m_count++; + } +} + +void +gen_constraints::onModule(asn1::module *m) +{ + m_current_module = m->name(); +} diff --git a/libgen/asn1_gen_constraints.h b/libgen/asn1_gen_constraints.h new file mode 100644 index 0000000..77bcf52 --- /dev/null +++ b/libgen/asn1_gen_constraints.h @@ -0,0 +1,75 @@ +#ifndef ASN1_GEN_CONSTRAINTS_H +#define ASN1_GEN_CONSTRAINTS_H + +/** + * @brief Constraint collector class + * Collect all constrains to generate a unique constraint table. + */ +class gen_constraints : public asn1::parser_listener +{ + public: + /** + * + * + */ + struct local_constraint + { + public: + local_constraint(asn1::constraint *c = NULL) : m_count(1), m_constraint(c) {}; + + bool operator ==(local_constraint &lc) + { + return !m_constraint->name().compare(lc.m_constraint->name()); + } + + bool operator ==(asn1::constraint &lc) + { + return !m_constraint->name().compare(lc.name()); + } + + bool operator <(const local_constraint &lc) const + { + return m_constraint->name().compare(lc.m_constraint->name()) > 0 ; + } + + void inc() { m_count++; } ; + asn1::constraint *m_constraint; + mutable long m_count; + }; + // + typedef std::set constraintSet; + typedef constraintSet::iterator constraintSetIterator; + typedef constraintSet::const_iterator const_constraintSetIterator; + + typedef std::map moduleMap; + typedef moduleMap::iterator moduleMapIterator; + + // Default constructor + gen_constraints(); + // Destructor + ~gen_constraints(); + + void onConstraint(asn1::constraint *c); + + void onModule(asn1::module *m); + // + inline constraintSetIterator begin() + { return m_constraints.begin() ; } + // + inline constraintSetIterator end() + { return m_constraints.end() ; } + + // + inline const_constraintSetIterator begin() const + { return m_constraints.begin() ; } + // + inline const_constraintSetIterator end() const + { return m_constraints.end() ; } + + protected: + std::string m_current_module; + constraintSet m_constraints; + moduleMap m_map; +}; + +#endif /*ASN1_GEN_CONSTRAINTS_H*/ diff --git a/libgen/asn1_gen_cpp.cpp b/libgen/asn1_gen_cpp.cpp new file mode 100644 index 0000000..68c7830 --- /dev/null +++ b/libgen/asn1_gen_cpp.cpp @@ -0,0 +1,572 @@ +#include +#include +#include +#include +#include + +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" + + +codecstreams::codecstreams() +{ +} +// +void +codecstreams::open(const std::string &name,bool jer,bool per,bool oer) +{ + std::string filename = name + "_codec.hpp"; + m_os_codec_hpp.open(filename.c_str(),std::fstream::out); + m_os_codec_hpp<<"// Generated do not modifie"<as_constructed(); + asn1::node::node_list nl; + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} + + +void generate_cpp::gen_composite_attribute_ref( std::ostream &os + , const std::string &scope + , asn1::field *attribute + , asn1::node *_params ) +{ + asn1::constructed *params = _params->as_constructed(); + asn1::typeref *attr_type = dynamic_cast(attribute->get_type()); + assert( attr_type != NULL); + asn1::reference *ref = attr_type->get_reference(); + + assert(ref != NULL); + + if ( ref && (ref->size() > 1)) + { + gen_comp_attr_complex_ref(os,scope,*attr_type,params); + } else + { + gen_comp_attr_simple_ref(os,scope,*attr_type,params); + } +} + +/** + * + */ +void +generate_cpp::gen_comp_attr_ref_tplt(std::ostream &os + , asn1::typeref *attr_type + , asn1::node *real_type + , asn1::node *params) +{ + // check if attribute has parameters + if(attr_type->act_parameters() != NULL + && (real_type) + && is_template(real_type->identifier()->parameters()) + ) + { + os << "<"; + for(asn1::node::iterator it = attr_type->act_parameters()->begin(); + it != attr_type->act_parameters()->end(); ++it) + { + asn1::node* ns1 = NULL; + if(it != attr_type->act_parameters()->begin()) + os << ","; + // check namespace + if(type_in_imports((*it)->name(), &ns1)) { + os << ns1->cpp_name() << "::" << (*it)->cpp_name(); + } else + os << (*it)->cpp_name(); + } + os << ">"; + } +} + +/** + * Simple reference attribute. No object or complex reference + * + */ +void +generate_cpp::gen_comp_attr_simple_ref(std::ostream &os + , const std::string &scope + , asn1::typeref &_ref + , asn1::node *_params) +{ + asn1::constructed *params = _params->as_constructed(); + asn1::typeref *attr_type = &_ref; + asn1::node *attribute = _ref.identifier(); + asn1::reference *ref = _ref.get_reference(); + asn1::node::iterator refm = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(ref->name())); + asn1::node *real_type = m_resolver.resolve(*attr_type); + + if (refm != m_module->end()) + { + // Here Type in current module I have the type definition. I should add + if ( ((*refm)->get_color() == 2) + || attribute->flags().is_optional() + || ! attribute->get_parent()->identifier()->name().compare(_ref.name()) + ) + os<<"ASN1_ATTRIBUTE_OPTIONAL("; + + os<cpp_name(); + + gen_comp_attr_ref_tplt(os,attr_type,real_type,params); + + if ( ((*refm)->get_color() == 2 ) + || attribute->flags().is_optional() + || ! attribute->get_parent()->identifier()->name().compare(_ref.name()) + ) + os<<" )"; + if (with_source_comment()) + { + os<<" /*NR c="<<(*refm)->get_color(); + os<<" opt="<flags().is_optional(); + os<<" param="<name(),&ns) ) + { + asn1::reference::component_const_iterator compit = ref->begin(); + // Simple external Reference + if (attribute->flags().is_optional() ) + { + os<<"ASN1_ATTRIBUTE_OPTIONAL("<cpp_name()<<"::"<cpp_name()<<")"; + if (with_source_comment()) + os<<"/*NR 2 optional="<flags().is_optional()<<" */ "; + } else + { + os<cpp_name()<<"::"<cpp_name(); + if (with_source_comment()) + os<<" /*NR 2 optional="<flags().is_optional()<<" */ "; + } + // check if attribute has parameters + + gen_comp_attr_ref_tplt(os,attr_type,real_type,params); + + } else if (params) // reference in parameters of definition + { + // Wierd case + bool found = false; + for ( asn1::node::iterator it = params->begin() + ; it != params->end(); ++it) + { + if (ref->name().compare((*it)->name())== 0) + { + os<<" "<<(*it)->cpp_name(); + found = true; + } + if (!found) { + GEN_LOG_ERROR("Parameter %s\n",(*it)->name().c_str()); + os<<" ERRORNOTPARAMS "; + } + + } + + } else + { + os<<" ERROR "; + } + } +} + +/** + * + */ +void +generate_cpp::gen_comp_attr_complex_ref(std::ostream &os + , const std::string &scope + , asn1::typeref &_ref + , asn1::node *params) +{ + asn1::typeref *attr_type = &_ref; + asn1::node *attribute = _ref.identifier(); + asn1::node *real_type = m_resolver.resolve(*attr_type); + asn1::node::node_list nl; + if (real_type) + { + real_type->path2module(nl); + asn1::module *t_module = m_module; + if (!nl.empty()) + { + t_module = dynamic_cast(nl.front()->get_parent()); + } else + { + } + + if (t_module && ! t_module->name().compare(m_module->name())) + { + std::string scope(""); + gen_attr_field_type(os,scope,real_type); + } else if (t_module) + { + // Type in other module + //os<<" /* t_module "<name()<<" */ "; + std::string scope(""); + scope = t_module->cpp_name() +"::"; + if (_ref.is_external()) + { + os<identifier()->cpp_name() ; + }else + gen_attr_field_type(os,scope,real_type); + } else + { // Error + assert(0); + } + } +} +/** + * @brief Build the name of the type when is choice or sequence. + */ +void generate_cpp::private_attribute_type(asn1::node *type,std::string &structName) +{ + asn1::node::node_list lst; + assert(type != NULL); + assert(type->get_parent() != NULL); + std::string ss = type->cpp_name()+"_t"; + type->path2module(lst); + + for (asn1::node::const_iterator nit = lst.begin() + ; nit != lst.end() + ; ++nit ) + { + if ( (*nit)->is_private() ) + { + std::string tmp = (*nit)->cpp_name() + "_"; + ss.insert(0,tmp); + } else + { + std::string tmp = (*nit)->identifier()->cpp_name() + "_"; + ss.insert(0,tmp); + } + } + structName = ss; +} + +/** +* @brief +* Generate field type attribute depending on scope +* If field is not in current module, +* scope = modle_cpp_name +"::" +*/ +void +generate_cpp::gen_attr_field_type( std::ostream &os + , std::string &scope + , asn1::node *field_type + ) +{ + // Type in current module + // Wow attribute found in class Now I can decide what to do + switch( field_type->type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_TF: + os<<"asn1::intrusive_ptr<"; + os<get_parent()->identifier_cpp_name()<<"> "; + if (with_source_comment()) + { + os<<"/* CF "; + os<get_parent()->identifier_cpp_name(); + os<<" TF "<name(); + //" optional="; os<flags().is_optional(); + os<<" */ "; + } + break; + case asn1::type::ASN1_CLASSFIELD_FTVF: + { + asn1::classfield_ftvf *f = dynamic_cast(field_type); + asn1::typenode *rnode = f->get_type(); + os<<""<cpp_name(); + if (with_source_comment()) + { + os<<" /* CF FTVF "<name(); + //os<<" optional:"<flags().is_optional(); + os<<" */ "; + } + } + break; + case asn1::type::ASN1_REFERENCE: + case asn1::type::ASN1_INTEGER: + case asn1::type::ASN1_CHOICE: + case asn1::type::ASN1_OBJECT_IDENTIFIER: + os<cpp_name()<<" /* "<name()<<"*/"; + break; + default: + os<<"/* tyid="<type_id()(); + os<<" Field "<name()<<"*/"; + break; + } +} + + +/** + * + * This function should be used to compute the names of the structures with and without scope. + * In order to facilitate nested / unnested + * -> ASN1_ENUMERATED returns either cpp_name or indentifier_cpp_name if private or not + * -> ASN1_NULL returns Null + * -> ASN1_SEQUENCE_OF + * -> ASN1_SET_OF + * -> ASN1_CHOICE + * -> ASN1_SET + * -> ASN1_SEQUENCE + * TOBE COMPLETED + * -> ASN1_REFERNCE + * default not working properly + */ +bool generate_cpp::type2cppstring( asn1::typenode *type + , std::string &strtype + , const std::string &scope) +{ + asn1::node *ns; + + assert(type != NULL); + + if (type == NULL) + { + GEN_LOG_ERROR("type2cppstring failes type is nul \n"); + return false; + } + switch (type->type_id()() ) + { + case asn1::type::ASN1_SEQUENCE_OF: + { + asn1::node *seqof_type = type->get_eltype(); + if (type_in_imports(seqof_type,&ns )) { + strtype = type->cpp_name()+"<"+ns->cpp_name()+"::"+seqof_type->cpp_name()+">"; + } else { + switch (seqof_type->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + asn1::node::node_list lst; + std::string ss; + type->path2module(lst); + for (asn1::node::const_iterator nit = lst.begin() + ; nit != lst.end() + ; ++nit ) + { + if ( (*nit)->is_private() ) + { + ss += (*nit)->cpp_name() + "::"; + } else + ss += (*nit)->identifier()->cpp_name() + "::"; + } + //TODO compute namespace if type is private or else clang complains + strtype="SEQUENCE_OFcpp_name()+"> "; + } + break; + default: + if (asn1::typeref *tref = seqof_type->as_typeref()) + { + strtype="SEQUENCE_OFget_reference()->cpp_name()+"> "; + } else + { + if (seqof_type->is_private()) + { + strtype="SEQUENCE_OFget_parent()->identifier()->cpp_name()+"::"; + strtype+=seqof_type->cpp_name()+"> "; + } else + strtype="SEQUENCE_OFcpp_name()+"> "; + } + } + } + } + break; + case asn1::type::ASN1_SET_OF: + { + asn1::node *setof_type = type->get_eltype(); + if (type_in_imports(setof_type,&ns )) + { + strtype = type->cpp_name()+"<"+ns->cpp_name()+"::"+setof_type->cpp_name()+">"; + } else + { + switch (setof_type->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + strtype="SET_OF<"+scope+setof_type->cpp_name()+"> "; + } + break; + default: + if ( + asn1::typeref *tref = + dynamic_cast(setof_type) + //setof_type->get_reference() + ) + { + if (tref->is_objectclass()) + { + asn1::node *rt = m_resolver.resolve(*tref); + if (rt->type_node()) + { + strtype = rt->type_node()->cpp_name(); + return true; + } + } + else if (tref->is_simple()) + { + asn1::node *rt = m_resolver.resolve(*tref); + strtype="SET_OFget_parent()->cpp_name(); + strtype +="::" +tref->get_reference()->cpp_name()+"> "; + return true; + } + strtype="SET_OFget_reference()->cpp_name()+"> "; + } else + { + strtype="SET_OFcpp_name()+"> "; + } + } + } + } + break; + case asn1::type::ASN1_NULL: + strtype= "Null"; + break; + case asn1::type::ASN1_ENUMERATED: + case asn1::type::ASN1_SET: + // THIS NEEDS TO BE VALIDATED + if (type->is_private()) + { + private_attribute_type(type->identifier(),strtype); + } else + strtype = type->identifier_cpp_name(); + break; + case asn1::type::ASN1_SELECTION: + { + strtype = "INTEGER"; + return true; + } + break; +#if defined(_WINDOWS) + case asn1::type::ASN1_BOOLEAN: + { + strtype = std::string("asn1::") + type->cpp_name(); + return true; + } +#endif + break; + case asn1::type::ASN1_REFERENCE: + { + asn1::typeref *tref = dynamic_cast(type); + if (tref->is_objectclass()) + { + asn1::node *rt = m_resolver.resolve(*tref); + if (rt->type_node()) + { + strtype = rt->type_node()->cpp_name(); + return true; + } + if (!rt) + { + std::cerr<<"type2cppstring "<name()<<" Failed"<as_typenode(); + } + } + //break; + default: + if (type_in_imports(type->name(),&ns )) + { + strtype = ns->cpp_name()+ "::"+type->cpp_name(); + } else + { + strtype = type->cpp_name(); + } + } + + return true; +} + +/* + * vim: et sw=2 ts=2 list + */ diff --git a/libgen/asn1_gen_cpp.h b/libgen/asn1_gen_cpp.h new file mode 100644 index 0000000..a6f8bdd --- /dev/null +++ b/libgen/asn1_gen_cpp.h @@ -0,0 +1,131 @@ +#ifndef ASN1_GEN_CPP_H__ +#define ASN1_GEN_CPP_H__ + + +/** + * Generate code in deferent files for simplicity + * os_codec_hpp _codec.hpp + * os_codec_cpp _codec.cpp + * os_jer _codec_jer.cpp + * os_per _codec_per.cpp + * os_oer _codec_oer.cpp + * When created, also create the associated streams + */ +struct codecstreams +{ + protected: + codecstreams(const codecstreams &c) + { std::cout<<"codecstreams copy\n";} + ; + public: + codecstreams() ; + void open(const std::string &name,bool jer,bool per,bool oer) ; + void close() ; + ~codecstreams(); + std::fstream m_os_codec_hpp; + std::fstream m_os_codec_cpp; + std::fstream m_os_jer; + std::fstream m_os_per; + std::fstream m_os_oer; +}; +/** + * Common generation function that can be used in header and cpp files has well + * + * Forseen usage : + * - attribute_ref resolution + * - value_from object + * - constraints + * - template signatures + */ +class generate_cpp : public asn1::generator +{ + protected: + generate_cpp(const generate_cpp &g) + : asn1::generator(g) + { + std::cout<<"copy generate_cpp "< +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include +#include +#include +#if defined(__APPLE__) || (GCC_VERSION > 40800) +#include +#include +#endif +#if defined(_WIN32) +#include +#include +#include +#define getcwd _getcwd +#define mkdir _mkdir +#endif +#include "asn1_resolver.h" +#include "asn1_generator_helper.h" +#include "cpp/cghpp_helper.h" +#include "cpp/cgh_hconstruct.h" +#include "cpp/cghpph_primitive.h" +#include "cpp/cghpph_bitstring.h" +#include "cpp/cghpph_octetstring.h" +#include "cpp/cghpph_classdef.h" +#include "cpp/cghpph_enumerated.h" +#include "cpp/cghpph_integer.h" +#include "cpp/cghpph_sequence.h" +#include "cpp/cghpph_sequenceof.h" +#include "cpp/cghpph_setof.h" +#include "cpp/cghpph_choice.h" +#include "cpp/cghpph_set.h" +#include "cpp/cghpph_typeref.h" +#include "cpp/cgh_object.h" +#include "cpp/cghpph_object.h" +#include "cpp/cghpph_import.h" +#include "cpp/cghpph_string.h" +#include "cpp/cghpph_boolean.h" +#include "cpp/cghpph_oid.h" +#include "asn1_visitor.h" + +/** + * generate template instantiation in .hpp file + * + */ +struct gen_tplt +{ + gen_tplt(std::ostream &os,generate_header &g) + : m_os(os), m_Gen(g) + { + } + + void operator ()(asn1::node *n) + { + asn1::typenode *type = n->as_assignment()->get_type(); + + assert(type->type_id()() == asn1::type::ASN1_REFERENCE); + asn1::node *real_type = + m_Gen.resolver().resolve(dynamic_cast(*type)); + if (real_type != NULL) + { + asn1::object *obj = dynamic_cast(type->get_eltype()); + asn1::classdef *cdef = dynamic_cast(real_type); + assert( obj != NULL); + assert( cdef != NULL); + + cghpph_object obj_gen(m_Gen,m_os,*obj,*cdef); + obj_gen.generate_hpp(); + } else + { + std::cerr<<"gen_tplt::OBJECT CLASS not found "<name()<type_id()()) + { + case asn1::type::ASN1_SEQUENCE_OF: + case asn1::type::ASN1_SET_OF: + { +#ifdef DEBUG + GEN_LOG_DEBUG("find sequence of or set of %s\n",n->name().c_str()); +#endif + asn1::node *type = n->as_typenode()->get_eltype(); + assert( (n->identifier() != NULL) && (type != NULL)); + if ( ! type->is_primitive() ) + type->name(n->identifier()->cpp_name()+std::string("_type")); + + if (asn1::typeref *tref = type->as_typeref()) + { + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(tref->get_reference()->name())); + } else { + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(type->name())); + } + // might be true if it's a private sequence or choice + if (it == m_module->end()) + { + os<<"//generate_header::"<<__FUNCTION__; + os<<" WARNING Found sequence of or set of:"; + os<name()<<" private element \n"; + gen_missing(os,type); + + } + + } + break; + case asn1::type::ASN1_ENUMERATED: + { + assert(n->identifier() != NULL); + asn1::node * attribute = n->identifier(); + n->name(attribute->cpp_name()+"_t"); + os<<"//gen_missing not nested ENUM "<name(); + os<<" "<name()<cpp_name()+"_t"); + + os<<";\n"; + // TODO MAY BE SET it to m_module->end(); + // There is nothing to generated behind enumerated + it = std::find_if(m_module->begin(),m_module->end(),asn1::find_node(n->name())); + } + break; + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_CHOICE: + case asn1::type::ASN1_SET: + { + asn1::constructed *cons = dynamic_cast(n); + asn1::node::iterator lit = cons->begin(); + assert(0); + GEN_LOG_DEBUG("gen_missing::found sequence or choice, set %s\n" + ,n->name().c_str()); + // Loop over the children and lookup for missing + for (; lit != cons->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if ( asn1::typenode *tn = f->get_type()) + { + gen_missing(os,tn); + } + } + } + return; + break; + case asn1::type::ASN1_NULL: + return; + case asn1::type::ASN1_REFERENCE: + { + asn1::typeref *tref = n->as_typeref(); + // Try to check references + if (tref->act_parameters() != NULL) + { + asn1::constructed *params = tref->act_parameters(); + GEN_LOG_DEBUG("%s have parameters\n",tref->name().c_str()); + //os<<"//generate_header::"<<__FUNCTION__<<" "<name()<<" Have parameters\n"; + for( asn1::node::iterator p = params->begin() + ; p != params->end() + ; ++p) + { + GEN_LOG_DEBUG( "%s have parameter : %s\n" + , tref->name().c_str() + , (*p)->name().c_str()); + it = std::find_if( m_module->begin() + , m_module->end() + , asn1::find_node((*p)->name())); + + if (it != m_module->end()) + { + // yes in h323 + //assert(0 && " is this used ?"); + gen_missing(os,(*it)); + } + } + } + // + if (tref->get_reference()) + { + GEN_LOG_DEBUG( "Ref %s color=%d\n" + , tref->get_reference()->name().c_str() + , n->get_color()); + if (std::string("TYPE-IDENTIFIER::&Type").compare(tref->get_reference()->name()) == 0) + { + std::cerr<<"TYPE-IDENTIFIER types shall OCTET STREAMS or open Types. I'm going too far here"<constraint_begin(); + if ((*c)->type() == asn1::constraint::EL_TYPE) + { + asn1::node *ctype = (*c)->value(); + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(ctype->name())); + } + } else + { + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(tref->get_reference()->name())); + if ( it == m_module->end() ) + { + GEN_LOG_WARN( "Reference %s not found use lookup ?\n" + , tref->get_reference()->name().c_str()); + } else + { + GEN_LOG_INFO("Reference %s found in current module. node %s\n" + ,tref->get_reference()->name().c_str() + , (*it)->name().c_str()); + } + } + } else + { + it = std::find_if( m_module->begin() + , m_module->end() + , asn1::find_node(n->name())); + } + } + break; + case asn1::type::ASN1_BOOLEAN: // Do nothing for primary types + it = std::find_if( m_module->begin() + , m_module->end() + , asn1::find_node(n->name())); + break; + default: + //os<<"//generate_header::"<<__FUNCTION__<<" WAR def case Ref "<name()<<" type="<type_id()()<<"not found\n"; + it = std::find_if( m_module->begin() + , m_module->end() + , asn1::find_node(n->name())); + } + // Found a element to be generated + if ( it != m_module->end()) + { + asn1::assignment *ltype = (*it)->as_assignment(); + if ( (ltype->is_generated() != true)) + { + if (ltype->get_color() == asn1::node::CL_GREEN) + { + ltype->set_generated(true); + GEN_LOG_DEBUG( "do gen missing for %s color=%d\n" + , ltype->name().c_str() + , ltype->get_color()); + switch(ltype->get_type()->type_id()()) + { + case asn1::type::ASN1_REFERENCE: + gen_typeref(os,ltype->get_type()->as_typeref()); + break; + default: + { + gen_typedef(os,ltype->get_type()->as_typenode()); + } + } + ltype->set_color(asn1::node::CL_RED); + } else if (ltype->get_color() == asn1::node::CL_ORANGE) + { + GEN_LOG_WARN( "gen_missing type %s of color=%d\n" + , ltype->name().c_str() + , ltype->get_color()); + if (ltype->get_type()->type_id()() == asn1::type::ASN1_SEQUENCE || + ltype->get_type()->type_id()() == asn1::type::ASN1_CHOICE + ) + os<<"struct "<cpp_name()<<";"<set_color(asn1::node::CL_REENTRANT); + }else + { + GEN_LOG_DEBUG( "gen_missing type %s of color=%d\n" + , ltype->name().c_str() + , ltype->get_color()); + ltype->set_color(asn1::node::CL_REENTRANT); + } + } + } +} + +/** + * This is only valid for OID where we use 7 bits for each octet. + */ +void generate_header::encode_integer(long value,std::vector &v) +{ + long integer = value; + long intsize = 4; + long mask = 0x1FF <<23; // Shift 8 *3 - 1 ? 0xFF800000 +#ifdef DEBUG + GEN_LOG_DEBUG("encode %ld\n",value); +#endif + while ( (((integer & mask) == 0) || ((integer & mask) == mask)) + && (intsize > 1)) { + intsize--; + integer <<=7; +#ifdef DEBUG + GEN_LOG_DEBUG("is: integer = %ld\n",integer); +#endif + } +#ifdef DEBUG + GEN_LOG_DEBUG("integer size = %ld\n",intsize); +#endif + mask = (0x7f << ((intsize-1)*7)); + long decal = (intsize -1)*7; + while ((value & mask ) != 0) + { + long treat = ((value & mask)>>decal); + v.push_back (( treat & 0x7F) |0x80 ); +#ifdef DEBUG + std::cout<<"\tpushed :"; + std::cout<identifier()->name().c_str()); +#endif + asn1::object_identifier::arcsType v; + tp->arcs(v); + os<<"\tinline "<identifier()->cpp_name()<<"(int s="<as_assignment()->get_type(); + + assert( n->meta_id()() == asn1::meta::VALUE + || n->meta_id()() == asn1::meta::VALUESET + ); + switch(type->type_id()()) + { + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + os<<"struct "<identifier_cpp_name(); + os<<"\t : public OBJECT_IDENTIFIER\n{\n"; + gen_oid_value(os,type->as_object_identifier()); + os<<"\n};\n"; + } + break; + case asn1::type::ASN1_OBJECTSET: + { + asn1::objectset *objs = dynamic_cast(type); + assert(0); // Is this called ! No only is CPP + GEN_LOG_DEBUG("in OBJECTSET type=%s ident name=%s:\n" + ,type->name().c_str() + ,type->identifier_name().c_str()); + } + break; + case asn1::type::ASN1_VALUESET: + { + GEN_LOG_DEBUG("in VALUESET type=%s ident name=%s:\n" + ,type->name().c_str() + ,type->identifier_name().c_str()); + assert(0); // Is this called ? No Only in CPP + } + break; + case asn1::type::ASN1_INTEGER: + { + GEN_LOG_DEBUG( "value integer %s\n" + , type->identifier_name().c_str()); + os<<"#define "<identifier_cpp_name(); + os<<"\t "<value()->cpp_name()<<""; + } + break; + case asn1::type::ASN1_REFERENCE: + GEN_LOG_DEBUG( "value reference %s\n" + , type->identifier_name().c_str()); + gen_missing(os,type); + + os<<"struct "<identifier()->cpp_name()<<" : public "; + os<cpp_name()<<"\n{\n"; + os<<"\t"<identifier()->cpp_name()<<"();\n"; + os<<"};"; + break; + default: + { + asn1::value *v = n->value(); + GEN_LOG_DEBUG("default case %s\n",type->identifier_name().c_str()); + assert(v != NULL); + switch (v->type) + { + case asn1::value::VT_INTEGER: + os<<"const "<cpp_name()<<" "<identifier_cpp_name()<<"\t\t= "; + os<cpp_name(); + os<<";"; + break; + case asn1::value::VT_COLON: + default: + ; + } + } + } + os<(type); + assert( (type->type_id()() == asn1::type::ASN1_ENUMERATED) && (e != NULL)); + + cghpph_enumerated egen(*this,os,*e); + egen.generate(); +} + +// +// gen_typeref +// +void generate_header::gen_typeref(std::ostream &os,asn1::typeref *type) +{ + std::string type_name; + bool resolved = false; + asn1::node *real_type = NULL; + asn1::typeref *ref = dynamic_cast(type); + // Pre requisit + assert( (type != NULL) && (type->type_id()() == asn1::type::ASN1_REFERENCE)); + assert( type->get_reference() != NULL); + assert( ref != NULL); + + if (with_source_comment()) + { + GEN_LOG_DEBUG( "type identifier=%s type_id=%d\n" + , type->identifier_name().c_str() + , type->type_id()()); + os<<"//generate_header::"<<__FUNCTION__; + os<<" "<identifier_name()<<" id="<type_id()()<<" "; + + if (type->has_constraints()) + { + asn1::constraint *c = *(type->constraint_begin()); + if (c) + os<name(); + } + + GEN_LOG_DEBUG("type is %s \n",type->name().c_str()); + + if (type->parameters() != NULL) + { + GEN_LOG_DEBUG("type %s has parameters \n",type->name().c_str()); + os<<" parameterized "; + } + os<<"\n"; + } + + type_name = type->cpp_name(); + asn1::resolver resolver(*m_module,m_modules); + + if ( (real_type = ref->get_real_type()) == NULL) + real_type = resolver.resolve(*ref); + + if (real_type != NULL && real_type->type_node()) + { + GEN_LOG_DEBUG("gen_typeref found Reference %s of type : %s color : %d\n" + , real_type->name().c_str() + , real_type->type_node()->name().c_str() + , real_type->get_color() + ); + } + // TODO Don't understand + // PkIx does not compile. Because the referenced type is not yet declared. + // As I play with typedefs and classes I'm no easely able to figure out what to + // do. An Idea is to generated the referenced type first if it's not generated + // Where is the Color ? + gen_missing(os,type); + asn1::node *ns = NULL; + os<<"//\n//"<identifier_name()<<"\n//\n"; + + cghpph_typeref gen_ref(*this,os,*ref); + gen_ref.generate(); +} + +/** + * + */ +void generate_header::gen_typedef_integer( std::ostream &os + , asn1::node *type) +{ + asn1::integer *i = dynamic_cast(type); + + assert( (type->type_id()() == asn1::type::ASN1_INTEGER) && (i != NULL)); + + cghpph_integer igen(*this,os,*i); + igen.generate(); +} + +// +// +void +generate_header::gen_sequence_of( std::ostream &os + , asn1::sequence_of &_seqof) +{ + asn1::node *ns = NULL; + asn1::typenode *seqof_type = _seqof.get_eltype(); + + if (seqof_type->get_parent() == NULL) + { + GEN_LOG_ERROR("gen_sequence_of type->get_parent() is NULL\n"); + } + assert(seqof_type->get_parent() != NULL); + + gen_missing(os,seqof_type); + + if (type_in_imports(seqof_type,&ns) ) + { + cghpph_sequenceof genso(*this,os,_seqof); + genso.generate(); + } else + { + switch (seqof_type->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + assert(0 && "gen_seq_of type should be reference not sequence"); + } + break; + case asn1::type::ASN1_CHOICE: + { + assert(0 && "gen_seq_of type should be reference not choice"); + } + break; + case asn1::type::ASN1_ENUMERATED: + { + assert(0 && "gen_seq_of type should be reference not enumr"); + } + break; + default: + cghpph_sequenceof genso(*this,os,_seqof); + genso.generate(); + } + } +} + +// +// +void +generate_header::gen_set_of(std::ostream &os,asn1::set_of &_seqof) +{ + asn1::node *ns = NULL; + asn1::typenode *seqof_type = _seqof.get_eltype(); + + gen_missing(os,seqof_type); + std::cout<<"gen_set_of "<<_seqof.identifier_cpp_name()<<" "<cpp_name()<type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + assert(0 && "gen_set_of type should be reference not sequence"); + } + break; + case asn1::type::ASN1_CHOICE: + { + assert(0 && "gen_set_of type should be reference not choice"); + } + break; + case asn1::type::ASN1_ENUMERATED: + { + assert(0 && "gen_set_of type should be reference not enum"); + } + break; + default: + cghpph_setof gensetof(*this,os,_seqof); + gensetof.generate(); + } + } +} + + +// +// +// +void generate_header::gen_typedef( std::ostream &os + , asn1::typenode *type) +{ + assert(type != NULL); + // Text cosmetic + GEN_LOG_DEBUG( "type %s ident=%s\n" + , type->name().c_str() + , type->identifier_name().c_str()); + if (with_source_comment() ) + { + os<<"// gen_typedef : "<identifier_name(); + os<<" id="<type_id()()<<" color="<get_color(); + if (type->has_constraints()) + { + asn1::constraint *c = *(type->constraint_begin()); + if (c) + os <name(); + + } + if ( type->identifier() && type->identifier()->parameters()) + { + os<<" parameterized "; + } + os<<"\n"; + } + // start the real work + if (type != NULL) + switch (type->type_id()()) + { + case asn1::type::ASN1_REFERENCE: + { + GEN_LOG_ERROR("type %s is reference\n",type->name().c_str()); + assert(0); + } + break; + case asn1::type::ASN1_INTEGER: + { + gen_typedef_integer(os,type); + return ; + } + break; + case asn1::type::ASN1_SEQUENCE: + { + asn1::sequence *seq = dynamic_cast(type); + if (with_source_comment()) + { + os<<"// start SEQUENCE GENERATION "; + os<identifier()->name()<<"\n"; + } + std::string scope(""); + // Genenerate missing before generating structure + asn1::node::iterator lit = seq->begin(); + for (; lit != seq->end() ; ++lit) + { + asn1::field *f = dynamic_cast(*lit); + asn1::typenode *attr_type = f->get_type() ; + if ( attr_type != NULL) + { + gen_missing(os,attr_type); + } else if (asn1::extension_field *ef = dynamic_cast(f) ) + { + os<<"// SEQUENCE GENERATION has extension field"<name()<<" Does not have type node cannot call gen_missing"<identifier()->name()<<"\n"; + os<<"\n"<(*type)); + return ; + break; + case asn1::type::ASN1_SET: + { + asn1::set *col = dynamic_cast(type); + asn1::node::iterator lit = col->begin(); + for (; lit != col->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if ( asn1::typenode *tn = f->get_type() ) { + gen_missing(os,tn); + } + } + gen_set(os,type); + os<<";\n"; + return ; + } + break; + case asn1::type::ASN1_SET_OF: + { + gen_set_of(os,dynamic_cast(*type)); + return; + } + break; + case asn1::type::ASN1_CHOICE: + { + asn1::choice *choix = dynamic_cast(type); + asn1::node::iterator lit = choix->begin(); + for (; lit != choix->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if ( asn1::typenode *tn = f->get_type() ) { + gen_missing(os,tn); + } + } + gen_choice(os,choix); + os<<";\n"; + return; + } + break; + case asn1::type::ASN1_ENUMERATED: + { + gen_enumerated(os,(type),type->identifier_cpp_name()); + os<<";\n"; + return; + } + break; + ; + case asn1::type::ASN1_BIT_STRING: + { + asn1::bit_string *bs = dynamic_cast(type); + assert(bs != NULL); + gen_bitstring(os,*bs); + return ; + } + break; + case asn1::type::ASN1_OCTET_STRING: + { + asn1::octet_string *o = dynamic_cast(type); + + assert( (type->type_id()() == asn1::type::ASN1_OCTET_STRING) + && (o != NULL)); + + cghpph_octet_string ogen(*this,os,*o); + ogen.generate(); + return ; + } + case asn1::type::ASN1_BOOLEAN: + { + asn1::boolean *o = dynamic_cast(type); + + assert( (type->type_id()() == asn1::type::ASN1_BOOLEAN) + && (o != NULL)); + + cghpph_boolean ogen(*this,os,*o); + ogen.generate(); + return ; + } + + case asn1::type::ASN1_NULL: + { + asn1::primitive *o = dynamic_cast(type); + GEN_LOG_ERROR("type %s NULL is reference\n",type->name().c_str()); + + assert( (o != NULL)); + std::cerr<<__FUNCTION__<<" GENERATE "<identifier()->cpp_name(); + std::cerr<<" type::ASN1_NULL"<name().c_str()); + return ; + } + + + case asn1::type::ASN1_STRING_BMPString: + case asn1::type::ASN1_STRING_IA5String: + case asn1::type::ASN1_STRING_VisibleString: + case asn1::type::ASN1_STRING_GraphicString: + case asn1::type::ASN1_STRING_ISO646String: /* aka VisibleString */ + case asn1::type::ASN1_STRING_PrintableString: + case asn1::type::ASN1_STRING_NumericString: + case asn1::type::ASN1_STRING_TeletexString: + { + asn1::primitive *o = dynamic_cast(type); + + assert( (o != NULL)); + + cghpph_string ogen(*this,os,*o); + ogen.generate(); + return ; + } + + break; + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + asn1::object_identifier *o = + dynamic_cast(type); + + assert( (o != NULL)); + + cghpph_oid ogen(*this,os,*o); + ogen.generate(); + return ; + } + + break; + case asn1::type::ASN1_STRING: + case asn1::type::ASN1_STRING_UniversalString: + case asn1::type::ASN1_STRING_UTF8String : + case asn1::type::ASN1_STRING_GeneralString: + case asn1::type::ASN1_STRING_T61String: + case asn1::type::ASN1_STRING_VideotexString: + case asn1::type::ASN1_STRING_ObjectDescriptor: + //case asn1::type::ASN1_UNIVERSAL: + default: + { + std::string cppType; + if ( ! type2cppstring(type,cppType)) + { + std::cerr<<"Failed get cpp type for "<name()<identifier_name()<<"\n//\n"; + os<<"typedef "; + if (type_in_imports(type,&ns) ) { + os<<"\t"<cpp_name()<<"::"; + os<cpp_name()<<" "; + } else { + if (type->tagged()) + { + os<<"asn1::types::"; + if (type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT) + { + os<<"IMPLICIT<"; + } else + os<<"EXPLICIT<"; + os<tag().m_class<<","<tag().m_value<<","; + if (type_in_imports(type,&ns) ) { + os<<"\t"<cpp_name()<<"::"; + os<cpp_name()<<"> "; + } else + os<<" /**/ "<cpp_name()<<"> "; + } else + { + if (with_source_comment()) + os<<" /*gtdef*/ "; + os<identifier_cpp_name()<<";\n\n"; + +} + +/** + * + */ +void generate_header::gen_seq( std::ostream &os + , std::string &scope + , asn1::sequence *type) +{ + asn1::node * ident = type->identifier(); + + assert(type->type_id()() == asn1::type::ASN1_SEQUENCE); + + // New way to handle and isolate sequence code generation + asn1::sequence *seq = dynamic_cast(type); + assert(seq != NULL); + + cghpph_sequence seq_gen(*this,os,*seq); + seq_gen.generate(); +} + + +// +// +// +void generate_header::gen_template_params(std::ostream &os,asn1::node *_params) +{ + asn1::constructed *params = dynamic_cast(_params); + asn1::node::node_list nl; + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin() + , nl.end() + , asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} +// +// +// +void generate_header::gen_template_signature( std::ostream &os + , asn1::node *_params) +{ + asn1::constructed *params = dynamic_cast(_params); + asn1::node::node_list nl; + + assert(params != NULL); + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin() + ,nl.end() + ,asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} + +/** + * + * + */ +void generate_header::struct_name(asn1::node *type,std::string &structName) +{ + if (type->identifier() == NULL) + { + structName = type->cpp_name(); + } else + { + if (type->is_private()) + { + std::cerr<<"struct_name : "<identifier()->cpp_name()<identifier()->cpp_name().c_str()); + assert(type->identifier()->get_parent() != NULL); + private_attribute_type(type->identifier(),structName); + } else + structName = type->identifier()->cpp_name(); + } +} + +/** + * + * + */ +void generate_header::gen_choice( std::ostream &os + , asn1::choice *type + , asn1::node *pparams) +{ + std::string scope(""); + std::string structName; + asn1::node::iterator it; + + assert(type != NULL); + assert(type->get_parent() != NULL); + struct_name(type,structName); + + m_Stack.push_back(structName); + + cghpph_choice choice_gen(*this,os,*type); + choice_gen.generate(); + + m_Stack.pop_back(); +} + +/** + * TODO: Remove + */ +void +generate_header::gen_composite_attribute_ref(std::ostream &os + , std::string &scope + , asn1::field *attribute + , asn1::node *params) +{ + generate_cpp::gen_composite_attribute_ref(os,scope,attribute,params); +} + +/** + * + * What means attributes ? + * TODO 2017/05/17 review this function it's too complicated. + * + */ +void +generate_header::gen_composite_attribute(std::ostream &os + , std::string &scope + , asn1::field &attribute + , asn1::node *params + , bool attributes) +{ + asn1::typenode *attr_type = attribute.get_type(); + if (attr_type != NULL) + { + std::string structName = attribute.cpp_name() +"_t"; + private_attribute_type(&attribute,structName); + switch (attr_type->type_id()()) + { + case asn1::type::ASN1_ENUMERATED: + { + if (attributes) + { + if (attribute.flags().is_optional() ) + { + os<<"\n\tASN1_ATTRIBUTE_OPTIONAL( struct "; + os<name(structName); + gen_set(os,attr_type); + if (attributes) + { + os<<"\t\t"<name(structName); + if (attributes) + { + if (attribute.flags().is_optional() ) + { + os<<"\n\tASN1_ATTRIBUTE_OPTIONAL( struct "; + os<cpp_name()<<" )\t"; + os<<"\t\t"<name(structName); + if ( ! attributes) + { + return; + } + if (attribute.flags().is_optional() ) + { + os<<";\n\tASN1_ATTRIBUTE_OPTIONAL( struct "; + os<cpp_name()<<" )\t"; + os<<"\t\t"<get_eltype(); + if (type->has_constraints()) + { + os<<"//"<<__FUNCTION__; + os<<" I have constraints type SET_OF or SEQUENCE_OF\n"; + } + switch (subtype->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + subtype->name(attribute.cpp_name()+std::string("_type")); + if ( ! attributes) + { + return; + } + if (attribute.flags().is_optional() ) { + os<<"\tASN1_ATTRIBUTE_OPTIONAL("; + } + os<name()<<"<"<"; + if (attribute.flags().is_optional() ) { + os<<") "; + } + break; + // Missing SET + case asn1::type::ASN1_CHOICE: + subtype->name(structName); + if ( ! attributes) + { + return; + } + if (attribute.flags().is_optional() ) + { + os<<"\tASN1_ATTRIBUTE_OPTIONAL("; + } + // TOBE CONSISTENT, this should be _type + os<name()<<"<"; + os<"; + if (attribute.flags().is_optional() ) + { + os<<") "; + } + break; + default: + asn1::node *ns; + if ( ! attributes) + { + return; + } + if (attribute.flags().is_optional() ) + { + os<<"\tASN1_ATTRIBUTE_OPTIONAL("; + } + if (type_in_imports(subtype,&ns) ) + { + os<<"\t"<name()<<"<"; + os<cpp_name()<<"::"<cpp_name()<<">"; + } else + { + if (asn1::typeref *stref = subtype->as_typeref()) + { + os<<"\t"<name()<<"get_reference()->cpp_name()<<">"; + } else { + os<<"\t"<name()<<"cpp_name()<<">"; + } + } + if (attribute.flags().is_optional() ) { + os<<") "; + } + } // end switch + // common to all switch + os<<"\t"<as_typeref(); + if ( ! attributes) + return; + os<<"\t"; + if (tref->get_reference()) + { + // New way to handle reference + gen_composite_attribute_ref(os,scope,&attribute,params); + } else + { + assert(0); + } + os<<"\t"<cpp_name()<<"::"; + os<cpp_name()<<" "; + } else if ( attribute.flags().is_optional() ) { + os<cpp_name()<<"::"; + os<cpp_name()<<") "; + } else + { + os<cpp_name()<<"::"; + os<cpp_name()<<" "; + } + } else + { + // Local attribute + //std::cout<<"HERE ?"<name(); + os<<") 2cpp string "<has_constraints()) + { + os<<"\t//"<<__FUNCTION__<<" default case I have constraints"; + } else + { + os<<" //"<<__FUNCTION__<<" "; + os<type_id()()<<" default without constraints"; + } + } + os<<"\n"; + } + } + } +} + + +/** + * + */ +void generate_header::gen_set(std::ostream &os,asn1::node *type) +{ + std::string scope(""); + std::string structName; + asn1::node *n = type->identifier(); + + // New way to handle and isolate sequence code generation + asn1::set *set = dynamic_cast(type); + assert(set != NULL); + + cghpph_set set_gen(*this,os,*set); + set_gen.generate(); +} + +/** + * + */ +class genh_oc_tplt : public node_visitor +{ + protected: + asn1::classdef &m_classdef; + generate_header &m_gen; + bool m_param; + std::ostringstream m_result; + long m_count; + public: + genh_oc_tplt( generate_header &_gen + , asn1::classdef &_cdef + , bool is_param=false) + : m_classdef(_cdef),m_gen(_gen) , m_count(0), m_param(is_param) + { m_result.str(""); }; + + inline std::string result() { return m_result.str(); } ; + +#define ASN1_CLASSFIELD_TYPE(cf,code) \ + void visit_##cf(asn1::cf *field) code + +ASN1_CLASSFIELD_TYPE(classfield_tf,{ + if (m_count++) + m_result<<","; + if (! m_param) + m_result<<"typename "; + std::string fieldname = field->cpp_name(); + fieldname[0] = '_'; + m_result< l; + genh_oc_tplt gt(*this,*type); + os<<"template<"; + for ( asn1::node::iterator it = type->begin() + ; it != type->end(); ++it) + { + gt.visit(*it); + } + os<\n"; +} + +void +generate_header::gen_object_class_tplt_params(std::ostream &os,asn1::classdef *type) +{ + assert(type != NULL); + asn1::node::iterator it = type->begin(); + std::list l; + + for ( ; it != type->end(); ++it) + { + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + /* Type Field */ + if ( (*it)->type_id()() == asn1::type::ASN1_CLASSFIELD_TF) + { + l.push_back(fieldname); + } + } + + if (l.size()>0) + { + os<<"<"; + for ( std::list::const_iterator it = l.begin() + ; it != l.end() + ; ++it) + { + if (it != l.begin()) { + os<<","; + } + os<<" "<<(*it)<<""; + } + os<<", _uuid /*uuid */"; + os<<">"; + } +} + +/** + * + * + */ +void generate_header::gen_object_class_missing(std::ostream &os,asn1::classdef *type) +{ + asn1::node::iterator it = type->begin(); + + // cosntructors + + // public methods + for ( ; it != type->end(); ++it) + { + asn1::classfield *ltype = dynamic_cast(*it); + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + os<<"//"<<(*it)->cpp_name()<<" type_id="<<(*it)->type_id()(); + //<type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_FTVF: /* Fixed Type Value Field */ + os<get_type()); + break; + case asn1::type::ASN1_CLASSFIELD_TF: /* Type Field */ + os<get_type()); + break; + case asn1::type::ASN1_CLASSFIELD_VTVSF: /* Variable Type Value Set Field*/ + os<(n->get_type()); + assert(type != NULL); + cghpph_classdef cdef(*this,os,*type); + cdef.generate(); +} + +/** + * + * + */ +void generate_header::gen_object(std::ostream &os,asn1::assignment *n) +{ + asn1::typenode *type = n->get_type(); + + os<<"// generate_header::"<<__FUNCTION__<<" "<name()<<"\n"; + os.flush(); + + assert(type->type_id()() == asn1::type::ASN1_REFERENCE); + asn1::node *real_type = + m_resolver.resolve(dynamic_cast(*type)); + if (real_type != NULL) + { + asn1::object *obj = dynamic_cast(type->get_eltype()); + asn1::classdef *cdef = dynamic_cast(real_type); + assert( obj != NULL); + assert( cdef != NULL); + // Check Done at optimization level + cghpph_object obj_gen(*this,os,*obj,*cdef); + obj_gen.generate(); + } else + { + std::cerr<<"OBJECT CLASS not found "<name()<name()<<"\n"; + } +} + + + + + +void +generate_header::gen_include(std::string fname,asn1::assignment *type) +{ + struct stat st; + char *cd = getcwd(NULL,0); + std::string cdir( cd); + + + std::fstream inc; + std::string module_path = cdir+"/include/"+m_module->cpp_name(); + std::string f; + if (type->meta_id()() == asn1::meta::OBJECTCLASS ) { + f = "./include/"+m_module->cpp_name()+"/I"+fname; + } else { + f = "./include/"+m_module->cpp_name()+"/"+fname; + } + + if (stat("./include",&st) == -1) { +#ifdef WIN32 + mkdir("include"); +#else + mkdir("include",0777); +#endif + } + + if (stat(module_path.c_str(),&st) == -1) { +#ifdef WIN32 + mkdir(module_path.c_str()); +#else + mkdir(module_path.c_str(),0777); +#endif + } + + inc.open(f.c_str(),std::fstream::out); + inc<<"#ifndef __"<cpp_name()<<"_H__"<cpp_name()<<"_H__"<cpp_name()<<".h\""< +{ + protected: + generate_header &m_gen; + std::ostream &m_os; + std::fstream &m_log; + std::vector &m_objects; + std::string path ; + public: + do_genh_assignment( generate_header &_h + , std::ostream &os + , std::vector &_objects + ) + : m_os(os),m_gen(_h),m_log(_h.logger()) ,m_objects(_objects) {}; + // Main processing function per assignment + void operator ()(asn1::node *n) + { + asn1::typenode *type = n->as_assignment()->get_type(); + path = n->cpp_name()+".h"; + GEN_LOG_DEBUG( "Process item=%s meta=%d\n" + , n->name().c_str() + , n->meta_id()()); + if ( ! type) + return; + if ( n->is_generated()) + { + GEN_LOG_DEBUG("%s already generated\n",n->name().c_str()); + return; + } + visit(n->as_assignment()); + n->set_color(asn1::node::CL_RED); + } +#define ASSIGNMENT(Ty,Code) \ + void visit_##Ty(asn1::Ty##_assignment *a) Code + + ASSIGNMENT(typeref,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "meta of %s is TYPEREF parameterized: %d\n" + , a->name().c_str(),params); + m_gen.gen_include(path,a); + m_gen.gen_typeref(m_os,a->get_type()->as_typeref()); + }) + ASSIGNMENT(type,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "meta of %s is TYPE parameterized: %d\n" + , a->name().c_str(),params); + m_gen.gen_include(path,a); + m_gen.gen_typedef(m_os,a->get_type()); + }) + ASSIGNMENT(value,{ + GEN_LOG_DEBUG("meta of %s is VALUE\n",a->name().c_str()); + m_gen.gen_const(m_os,a); + }) + ASSIGNMENT(valueset,{ + GEN_LOG_DEBUG( "meta of %s is VALUESET do nothing ?\n" + , a->name().c_str()); + }) + ASSIGNMENT(object,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "meta of %s is OBJECT parameterized: %d\n" + , a->name().c_str(),params); + m_gen.gen_object(m_os,a); + m_objects.push_back(a); + }) + ASSIGNMENT(objectclass,{ + int params = (a->parameters() != NULL)?1:0; + GEN_LOG_DEBUG( "meta of %s is OBJECT CLASS parameterized: %d\n" + , a->name().c_str(),params); + m_gen.gen_object_class(m_os,a); + }) + ASSIGNMENT(objectset,{}) + ASSIGNMENT(objectfield,{}) + +}; +/** + * + */ +void generate_header::gen_module(std::ostream &os,asn1::module *n) +{ + asn1::import_list *imports = n->imports(); + os<<"#ifndef "<cpp_name()<<"_H__"<cpp_name()<<"_H__"<begin(); it!= imports->end(); it++) + { + asn1::import *import = dynamic_cast( *it); + if (import) + { + cghpph_import imp_gen(*this,os,*import); + imp_gen.generate(); + } + } + } + + os<<"using namespace asn1;\n"<cpp_name()<<" {\n"<sort_childs(); + + do_genh_assignment dogen(*this,os,m_objects); + std::for_each( n->begin() + , n->end() + , dogen + ); + + os<<"}\n\n"<has_objects()) + { + std::string fname = m_module->cpp_name() + ".hpp"; + std::fstream ost; + ost.open(fname.c_str(),std::fstream::out); + if (!m_module->name().compare("Remote-Operations-Useful-Definitions")) + { + ost<<"// Dont generate anything\n"; + } else + { + std::for_each( m_objects.begin() + , m_objects.end() + , gen_tplt(ost,*this) + ); + } + ost.close(); + } +} + + +/** +* vim:et:sw=2:ts=2 +*/ diff --git a/libgen/asn1_gen_hpp.h b/libgen/asn1_gen_hpp.h new file mode 100644 index 0000000..2755032 --- /dev/null +++ b/libgen/asn1_gen_hpp.h @@ -0,0 +1,119 @@ +#ifndef GEN_HEADER_H__ +#define GEN_HEADER_H__ +#include +#include + + +/** + * + */ +class generate_header : public generate_cpp +{ + public: + + typedef std::vector template_list_type; + + generate_header(asn1::module *n); + + generate_header(asn1::module *n,asn1::module::modules_type &m); + + /** + * This is a recursive function + * In no nested context, it generates all private classes + * + */ + void gen_missing(std::ostream &os,asn1::node *n) ; + + void encode_integer(long value,std::vector &v); + + void gen_oid_value(std::ostream &os,asn1::object_identifier *n); + /** + * + * + */ + void gen_const(std::ostream &os,asn1::node *n); + /** + * + * + */ + void gen_enumerated(std::ostream &os,asn1::node *n ,const std::string &name); + /** + * + */ + void gen_bitstring(std::ostream &os,asn1::bit_string &type ); + // + // called for ntype ::= SEQUENCE OF + virtual void gen_sequence_of(std::ostream &os,asn1::sequence_of &) ; + // called for ntype ::= SEQUENCE OF + virtual void gen_set_of(std::ostream &os,asn1::set_of &) ; + // + void gen_typedef(std::ostream &os,asn1::typenode *n); + + void gen_typedef_integer(std::ostream &os,asn1::node *n); + + void gen_typeref(std::ostream &os,asn1::typeref *n); + + /** + * + */ + void gen_seq(std::ostream &os,std::string &scope,asn1::sequence *n); + + void gen_choice(std::ostream &os,asn1::choice *n,asn1::node *params = NULL); + /** + * + * attributes flags is for choice case. We only generate internal structures in that case. + */ + void gen_composite_attribute( std::ostream &os + , std::string &scope + , asn1::field &attribute + , asn1::node *params = NULL,bool attributes = true); + void gen_composite_attribute_ref(std::ostream &os + , std::string &scope + , asn1::field *attribute + , asn1::node *params = NULL); + void gen_template_params(std::ostream &os,asn1::node *params); + void gen_template_signature(std::ostream &os,asn1::node *params); + + /** + * + */ + void gen_set(std::ostream &os,asn1::node *n); + + /* + * Ros generation Code + */ + void gen_object_class(std::ostream &os,asn1::assignment *n); + void gen_object_class_missing(std::ostream &os,asn1::classdef *n); + void gen_object_class_tplt(std::ostream &os,asn1::classdef *n); + void gen_object_class_tplt_params(std::ostream &os,asn1::classdef *n); + + + void gen_object(std::ostream &os,asn1::assignment *n); + /** + * + */ + void gen_module(std::ostream &os,asn1::module *n); + void gen_include(std::string fname,asn1::assignment *type); + /** + * Helper method to compute structName + */ + void struct_name(asn1::node *type,std::string &sn); + + /** + * TODO Must be removed after migration with EXPLICT /IMPLICIT + * + */ + template_list_type &get_template_list() + { + return m_template_codec; + } + protected: + std::fstream m_tplt_os; + std::vector m_Stack; + std::vector m_template_codec; + std::vector m_objects; +}; +/** + * vim:et:sw=2:ts=2 + */ +#endif diff --git a/libgen/asn1_gen_optimizer.cpp b/libgen/asn1_gen_optimizer.cpp new file mode 100644 index 0000000..94d3af3 --- /dev/null +++ b/libgen/asn1_gen_optimizer.cpp @@ -0,0 +1,918 @@ +#include +#include +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_optimizer.h" + +#include +#include +#include +#if defined(__APPLE__) || (GCC_VERSION > 40800) +#include +#include +#endif +#if defined(_WIN32) +#include +#endif +#include "asn1_resolver.h" +#include "asn1_generator_helper.h" + +#include "asn1_recursive_visitor.h" + +/** + * + */ +struct find_type +{ + find_type(asn1::type::id t) + : m_type(t) + { } + bool operator ()(asn1::node *t) + { + asn1::field *f = dynamic_cast(t); + if (f->get_type() && + t->type_id()() == m_type) + { + return true; + } + return false; + } + asn1::type::id m_type; +}; + +/** + * Works for : + * components of are integrated in new class + * selection type is replaced with real type + * object defined syntax is checked + * + */ +class optimize_phase1 : public asn1::recursive_visitor +{ + public: + optimize_phase1(asn1::resolver &r,std::fstream &l) + : resolver(r) , m_log(l) + { + } + + bool traverse_module(asn1::module *m) + { + m_module = m ; + asn1::recursive_visitor::traverse_module(m); + return true; + } + + bool visit_typeref(asn1::node *tref) + { + tref->as_typeref()->resolve(resolver); + return true; + } + bool visit_sequence(asn1::sequence *n) + { + asn1::node::iterator it = std::find_if( n->begin() + , n->end() + , find_type(asn1::type::ASN1_COMPONENTS_OF)); + + if ( it != n->end()) + { + asn1::field *f = dynamic_cast(*it); + asn1::typeref *type = dynamic_cast(f->get_type()); + asn1::constructed *rtype = resolver.resolve(*type)->as_constructed(); + if (rtype) + { + GEN_LOG_INFO("%s COMPONENTS OF %s transformed \n" + ,n->identifier()->name().c_str() + ,type->name().c_str() + ); + std::insert_iterator iit(n->nodes(),it); + std::copy(rtype->begin(),rtype->end(),iit); + n->nodes().erase(it); + } + } + return true; + } + bool visit_selection(asn1::selection *n) + { + GEN_LOG_ERROR("SELECTION TO BE HANDLED %s\n",n->type_node()->name().c_str()); + return true; + } + + /** + * @brief handle selection type + * + */ + bool visit_component_type(asn1::field *n) + { + GEN_LOG_INFO("phase1 Visite %s\n" + ,n->name().c_str()); + process_selection(n); + return true; + } + // + bool visit_alternative_choice(asn1::field *n) + { + GEN_LOG_INFO("phase1 Visite %s\n" + ,n->name().c_str()); +#if 0 + if (asn1::typeref *_rf = n->get_type()->as_typeref()) + { + std::cerr<<"visit_alternative_choice "<name()<name().c_str() + ,n->get_type()->name().c_str() + ); + _rf->resolve(resolver); + // Trying to understand what's going on + if (! n->get_type()->name().compare("DistinguishedName")) + { + std::cerr<<"visit_alternative_choice real type "<<_rf->get_real_type()->from_module()->name(); + std::cerr<<"::"<<_rf->get_real_type()->name()<get_type(); + if (stype && stype->type_id()() == asn1::type::ASN1_SELECTION) + { + asn1::typeref *ref = dynamic_cast(stype->get_eltype()); + asn1::constructed *rtype = resolver.resolve(*ref)->as_constructed(); + + GEN_LOG_INFO("SELECTION HANDLED %s < %s\n" + ,stype->name().c_str() + ,ref->name().c_str() + ); + // Check if rtype is CHOICE and lookup for n->name type. + // Replace n->type with new type and delete selection + // Keep tag and other stuff from selection before delete + asn1::node::iterator it = std::find_if(rtype->begin() + ,rtype->end() + ,asn1::find_node(stype->name())); + if (it != rtype->end()) + { + asn1::field *a = dynamic_cast(*it); + asn1::typenode *ntype = a->get_type(); + asn1::typenode *t = ntype->clone(); + t->set_parent(n->get_parent()); + if (stype->tagged()) + { + t->tag(stype->tag()); + } + if (t->identifier()) + { + t->identifier(n); + } + n->set_type(t); + delete (stype); + GEN_LOG_INFO("TYPE IS : %s\n" + , a->get_type()->name().c_str()); + } else + { + GEN_LOG_INFO("ERROR Type not found : %s\n" + , n->name().c_str()); + } + } + return true; + } + /** + * Parse defined syntax and check object + */ + bool visit_assign_object(asn1::object_assignment *n) + { + asn1::typenode *type = n->get_type(); + + assert(type->type_id()() == asn1::type::ASN1_REFERENCE); + asn1::node *real_type = + resolver.resolve(dynamic_cast(*type)); + if (real_type != NULL) + { + asn1::object *obj = dynamic_cast(type->type_node()); + asn1::classdef *cdef = dynamic_cast(real_type); + assert( obj != NULL); + assert( cdef != NULL); + if ( cdef->check_object_syntax(obj) ) + { + GEN_LOG_INFO("OBJECT syntax OK %s\n",n->name().c_str()); + obj->set_classdef(cdef); + } else + { + GEN_LOG_ERROR("OBJECT syntax error %s\n",n->name().c_str()); + std::cerr<<"Syntax ERROR for object "<name()<name().c_str()); + std::cerr<<"OBJECT CLASS not found "<name()<is_constructed()) + { + asn1::object *obj = dynamic_cast(f->get_parent()); + std::string type_name = S->name().substr(1) + "_"+ obj->identifier()->cpp_name(); + asn1::assignment *nt = new asn1::type_assignment(type_name); + asn1::typeref *tr = new asn1::typeref( + new asn1::simple_reference(type_name)); + tr->set_parent(f->get_parent()); + // + nt->set_type(f); + nt->set_parent(m_module); + //nt->parameters(pi->parameters()); + f->set_parent(m_module); + f->identifier(nt); + m_module->append(nt); + obj->update_field(S->name(),tr); + GEN_LOG_INFO( "VISIT OBJECT FIELD %s NOT REF FIXED TO %s\n" + , S->name().c_str() + , type_name.c_str() + ); + } + return true; + } + /* + * + */ + bool visit_object_classfield_osf(asn1::classfield_osf *S,asn1::node *f) + { + asn1::object *obj = dynamic_cast(f->get_parent()); + std::string tname = S->name().substr(1) + "_"+ obj->identifier()->cpp_name(); + GEN_LOG_INFO( "VISIT OBJECT FIELD %s TO BE FIXED %s\n" + , S->name().c_str() + , tname.c_str() + ); + return true; + } + /** + * + */ + bool visit_object_classfield_ftvf(asn1::classfield_ftvf *ftvf,asn1::node *f) + { + asn1::valuetype *vt = dynamic_cast(f); + asn1::typenode *type= ftvf->get_type(); + asn1::object *obj = dynamic_cast(f->get_parent()); + asn1::classdef *cdef = obj->get_classdef(); + std::string tname = ftvf->name().substr(1) + "_"+ obj->identifier()->cpp_name(); + GEN_LOG_INFO( "VISIT OBJECT FIELD ftvf %s TO BE FIXED %s %s\n" + , ftvf->name().c_str() + , tname.c_str() + , f->cpp_name().c_str() + ); + assert((cdef != NULL) && "cdef should be set"); + //assert( (vt != NULL) && "fixed type value field should be value type node"); + if (! vt ) + { + return true; + } + asn1::value *v = vt->value(); + GEN_LOG_INFO( "ftvf %s value is %s\n" + , ftvf->name().c_str() + , v->cpp_name().c_str() + ); + // Get real type instead of typeref + if (type->as_typeref()) + { + asn1::node *real_type = + resolver.resolve(dynamic_cast(*type)); + type = real_type->as_typenode(); + } + // Check value node !!! + if (asn1::choice *c = type->as_choice()) + { + asn1::field *field = c->get_field(f->name()); + if (! field ) + { + GEN_LOG_ERROR("ftvf: field %s 0x0x",f->name().c_str() + , c->get_field(f->name())); + std::cerr<<"ftvf: "<cpp_name()<<" "<name()<<" 0x"<get_field(f->name())<get_field(f->name())->get_type(); + GEN_LOG_INFO( "ftvf %s type is %s id=%d\n" + , ftvf->name().c_str() + , ct->cpp_name().c_str() + , ct->type_id()() + ); + if (v && v->m_node->type_id()() == 0) + { + asn1::constructed *vn = v->m_node->value()->m_node->as_constructed(); + std::cerr<<__FUNCTION__<<" Proccess ftvf because of wrong id "; + std::cerr<<"<"<m_node->cpp_name()<<"> "<m_node)).name()<type_id()()) + { + case asn1::type::ASN1_INTEGER: + break; + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + #if 1 + asn1::object_identifier *oid = new asn1::object_identifier(); + std::copy (vn->begin(),vn->end(), + std::back_inserter(oid->nodes())); + delete vn; + oid->set_parent(cdef->from_module()); + //v->m_node->value()->m_node = oid; + v->m_node= oid; + #endif + } + break; + default: + std::cerr<<__FUNCTION__<<" Proccess ftvf AIIIIIII"< +{ + public: + optimize_nested(asn1::resolver &r,std::fstream &l) + : resolver(r) , m_log(l) + { + } + + bool traverse_module(asn1::module *m) + { + m_module = m ; + asn1::recursive_visitor::traverse_module(m); + return true; + } + + + bool visit_sequence(asn1::sequence *n) + { + GEN_LOG_INFO("optimize_nested %s set of %s transformed \n" + ,n->identifier()->name().c_str() + ,n->name().c_str() + ); + asn1::node::iterator it = std::find_if( n->begin() + , n->end() + , find_type(asn1::type::ASN1_COMPONENTS_OF)); + + if ( it != n->end()) + { + asn1::field *f = dynamic_cast(*it); + asn1::typeref *type = dynamic_cast(f->get_type()); + asn1::constructed *rtype = resolver.resolve(*type)->as_constructed(); + if (rtype) + { + GEN_LOG_INFO("optimize_nested ident: %s COMPONENTS OF %s transformed\n" + ,n->identifier()->name().c_str() + ,type->name().c_str() + ); + std::insert_iterator iit(n->nodes(),it); + std::copy(rtype->begin(),rtype->end(),iit); + n->nodes().erase(it); + } + } + return true; + } + + /** + * @brief handle selection type + * + */ + bool visit_alternative_choice(asn1::field *ident) + { + GEN_LOG_INFO("optimize_nested field: %s type: %s process\n" + ,ident->name().c_str() + ,(ident->get_type())?ident->get_type()->name().c_str():"..." + ); + process(ident); + process_reference(ident); + return true; + } + /** + * @brief handle selection type + * + */ + bool visit_component_type(asn1::field *ident) + { + GEN_LOG_INFO("optimize_nested field: %s type: %s process\n" + ,ident->name().c_str() + ,(ident->get_type())?ident->get_type()->name().c_str():"..." + ); + process(ident); + process_reference(ident); + return true; + } + // + bool visit_set_of(asn1::set_of *so) + { + asn1::typenode *stype = so->get_eltype(); + GEN_LOG_INFO("optimize_nested TODO %s set of %s transformed \n" + ,so->identifier()->name().c_str() + ,stype->name().c_str() + ); + switch (stype->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_SET: + case asn1::type::ASN1_CHOICE: + process(so); + break; + default: + ; + } + return true; + } + // + bool visit_sequence_of(asn1::sequence_of *so) + { + asn1::typenode *stype = so->get_eltype(); + GEN_LOG_INFO("TODO %s sequence of %s transformed \n" + ,so->identifier()->name().c_str() + ,stype->name().c_str() + ); + switch (stype->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_SET: + case asn1::type::ASN1_CHOICE: + process(so); + break; + default: + ; + } + return true; + } + /** + * Parse defined syntax and check object + */ + bool visit_assign_object(asn1::object_assignment *n) + { + return true; + } + + void process_reference(asn1::field *n) + { + asn1::typenode *stype = n->get_type(); + if (! stype) + return; + + GEN_LOG_INFO( "optimize_nested start field: %s type: %s \n" + , n->name().c_str() + , stype->name().c_str() + ); + if (asn1::typeref *_ref = stype->as_typeref()) + { + _ref->resolve(resolver); + } else { + GEN_LOG_INFO("optimize_nested FAILED type: %s not typeref !!!\n" + ,stype->name().c_str() + ); + } + } + + bool visit_assign_typeref(asn1::typeref_assignment *n) + { + asn1::typenode *stype = n->get_type(); + if (! stype) + return true; + GEN_LOG_INFO(" %s \n" + ,stype->name().c_str() + ); + if (asn1::typeref *_ref = stype->as_typeref()) + { + _ref->resolve(resolver); + } + return true; + } + /** + * Needs to be split into two prototypes. + * one for asn1::field types + * one for asn1::typenode types eg elements in set_of / seq_of + */ + void process(asn1::node *ident) + { + asn1::node::node_list pm; + asn1::node *type = ident->type_node(); + GEN_LOG_DEBUG(" %s %s\n" + , __FUNCTION__ + ,ident->name().c_str() + ); + if (type && type->is_constructed()) + { + asn1::node * pi = ident->get_parent()->identifier(); + std::string type_name; + if (pi) + { + type_name = pi->cpp_name() +"_" + ident->name(); + } else + { // It seams that parent for set_of subtypes are NULL !!!: + type_name = ident->identifier()->cpp_name() +"_type" ; + } + GEN_LOG_INFO("PROCESS %s -> %s\n",ident->name().c_str(),type_name.c_str()); + asn1::assignment *nt = new asn1::type_assignment(type_name); + asn1::typeref *tr = new asn1::typeref( + new asn1::simple_reference(type_name)); + nt->set_type(type); + nt->set_parent(m_module); + if (pi) + nt->parameters(pi->parameters()); + type->set_parent(m_module); + type->identifier(nt); + m_module->append(nt); + // + asn1::node *subtype = type->type_node(); + if ( subtype + && subtype->identifier() + && subtype->identifier()->get_parent() == NULL) + { + GEN_LOG_INFO( "PROCESS ERROR %s -> %s type-type->get_parent is NULL\n" + , ident->name().c_str() + , type_name.c_str()); + } else if (subtype) + { + GEN_LOG_INFO("PROCESS WARN %s -> %s Maybe change parent of subtype \n",ident->name().c_str(),type_name.c_str()); + } + // + if (ident->get_parent() == NULL) + { + GEN_LOG_INFO("PROCESS ERROR %s -> %s ident->get_parent is NULL\n",ident->name().c_str(),type_name.c_str()); + } + tr->set_parent(ident->get_parent()); + tr->identifier(ident); + ident->type_node(tr); + } else { + GEN_LOG_INFO( " Nothing field: %s -> type:%s DONE\n" + , ident->name().c_str() + , (type)?type->name().c_str():"NULL"); + } + } + protected: + asn1::module *m_module; + asn1::resolver &resolver; + std::fstream &m_log; +}; + + +/** + * OPTIMIZE params + */ +class replace_params : public asn1::recursive_visitor +{ + public: + replace_params(asn1::resolver &r,std::fstream &l,asn1::module *m,asn1::parameters &p,asn1::act_parameters &ap) + : resolver(r) , m_log(l), m_actual_params(ap),m_parameters(p),m_module(m) + { + } + /** + * @brief handle replacements in alternative_choice + * + */ + bool visit_alternative_choice(asn1::field *ident) + { + asn1::typenode *type = ident->get_type(); + asn1::module *m = ident->from_module(); + std::string type_name = type->name(); + + if ( (type->type_id()() == asn1::type::ASN1_REFERENCE) + && m_module != m ) + { + asn1::typeref *typeref = dynamic_cast(type); + if (typeref->is_simple()) + { + process_reference(ident); + } else + { + GEN_LOG_INFO("no process reference %s -> %s wp\n",ident->name().c_str(),type_name.c_str()); + } + } + if ( type->parameters()) + { + asn1::act_parameters &act_params = dynamic_cast(*type->parameters()); + + GEN_LOG_INFO("check %s -> %s wp\n",ident->name().c_str(),type_name.c_str()); + } + return true; + } + + /** + * + */ + void process_reference(asn1::field *ident) + { + asn1::typenode *type = ident->get_type(); + asn1::module *m = ident->from_module(); + asn1::node::iterator it; + asn1::external_type_reference *etr = + new asn1::external_type_reference(m->name(),type->name()); + asn1::typeref *nref = new asn1::typeref(type->name(),etr); + GEN_LOG_INFO("check process_reference %s -> %s with %s\n" + ,ident->name().c_str() + ,type->name().c_str() + ,etr->name().c_str()); + + nref->set_parent(type->get_parent()); + nref->identifier(ident); + + if (type->parameters()) + nref->parameters(type->parameters()->clone()); + + ident->set_type(nref); + } + /** + * @brief handle remplacement in component_type + * + */ + bool visit_component_type(asn1::field *ident) + { + std::string type_name = ident->get_type()->name(); + asn1::typenode *type = ident->get_type(); + asn1::module *m = ident->from_module(); + asn1::node::iterator it; + GEN_LOG_INFO("check ct %s:%s -> %s:%s\n" + , m_module->name().c_str() + ,ident->name().c_str() + , m->name().c_str() + ,type_name.c_str()); + + if ( (type->type_id()() == asn1::type::ASN1_REFERENCE) + && m_module != m ) + { + asn1::typeref *typeref = dynamic_cast(type); + if (typeref->is_simple()) + { + process_reference(ident); + } else + { + GEN_LOG_INFO("no process reference %s -> %s wp\n",ident->name().c_str(),type_name.c_str()); + } + } + + if (m_parameters.have_reference(type->name(),it)) + { + size_t l = std::distance(m_parameters.begin(),it); + asn1::typenode *rtype = m_actual_params[l]->clone()->as_typenode(); + GEN_LOG_INFO("check ct HOHO %s -> %s %s %ld\n" + , ident->name().c_str() + , type_name.c_str() + , rtype->name().c_str() + , l + ); + ident->set_type(rtype); + rtype->identifier(ident); + rtype->set_parent(ident->get_parent()); + } + return true; + } + + protected: + asn1::module *m_module; + asn1::resolver &resolver; + std::fstream &m_log; + asn1::act_parameters &m_actual_params; + asn1::parameters &m_parameters; +}; + +/** + * + * + */ +class optimize_params : public asn1::recursive_visitor +{ + public: + optimize_params(asn1::resolver &r,std::fstream &l) + : resolver(r) , m_log(l) + { + } + + bool traverse_module(asn1::module *m) + { + m_module = m ; + asn1::recursive_visitor::traverse_module(m); + return true; + } + + /** + * @brief handle selection type + * + */ + bool visit_alternative_choice(asn1::field *ident) + { + asn1::node *parent = ident->get_parent(); + if (parent->identifier()->parameters()) + { + GEN_LOG_ERROR( "PROCESS ALTERNATIVE TYPE WP %s -> forget\n" + ,ident->name().c_str()); + return true; + } + if (ident->get_type() && ident->get_type()->parameters()) + { + asn1::typeref *type = dynamic_cast(ident->get_type()); + asn1::act_parameters &act_params = dynamic_cast(*type->parameters()); + asn1::node *rtype = resolver.resolve(*type); + std::string type_name = ident->get_type()->name(); + if (rtype == NULL) + { + std::cerr<<"rtpye NULL === "<name()< %s\n" + ,ident->name().c_str() + ,type_name.c_str()); + } else + { + asn1::parameters &p = dynamic_cast + (*rtype->identifier()->parameters()); + std::cerr<<"visit_alternative_choice before clone "<name()<<"rtype="<name()<clone(); + std::cerr<<"visit_alternative_choice after clone :"<name()< %s\n" + ,ident->name().c_str(),type_name.c_str()); + // Process replacing parameters .... + replace_params replace(resolver,m_log,m_module,p,act_params); + replace.traverse_type(ctype); + process_component(ident,ctype->as_typenode()); + } + } else if (ident->get_type()) + { + std::string type_name = ident->get_type()->name(); + GEN_LOG_INFO("PROCESS ALTERNATIVE TYPE NP %s -> %s\n" + ,ident->name().c_str(),type_name.c_str()); + } + return true; + } + /** + * @brief handle selection type + * + */ + bool visit_component_type(asn1::field *ident) + { + if (ident->get_type() && ident->get_type()->parameters()) + { + asn1::typeref *type = dynamic_cast(ident->get_type()); + std::string type_name = type->name(); + GEN_LOG_INFO("PROCESS COMPONENT TYPE WP %s -> %s\n" + ,ident->name().c_str(),type_name.c_str()); + } else + { + } + return true; + } + /** + * Parse defined syntax and check object + */ + bool visit_assign_type(asn1::type_assignment *n) + { + if (! n->parameters( ) && n->get_type()->parameters()) + { + std::string type_name = n->get_type()->name(); + GEN_LOG_INFO("visit_assign_type %s -> %s\n" + ,n->name().c_str() + ,type_name.c_str()); + } + return true; + } + /** + * Parse typerefs and see if there are parameter instantiated classes + * If so process with the instantiation + * -> Replace typeref with the real type This can be bad for generator if + * the global type is not changed !!!! + * -> We should also replace all parameters with the actual parameters + */ + bool visit_assign_typeref(asn1::typeref_assignment *n) + { + asn1::typeref *type = dynamic_cast(n->get_type()); + if (! n->parameters( ) && type->parameters()) + { + asn1::act_parameters &act_params = dynamic_cast(*type->parameters()); + asn1::node *rtype = resolver.resolve(*type); + asn1::parameters &p = dynamic_cast + (*rtype->identifier()->parameters()); + std::string type_name = type->name(); + GEN_LOG_INFO("visit_assign_typeref TYPEREF %s -> %s\n" + ,n->name().c_str(),type_name.c_str()); + std::cerr<<"visit_assign_typeref "<name()<clone(); + // temp + //ctype->identifier(type->identifier()); + //ctype->set_parent(m_module); + + // Process replacing parameters .... + std::cerr<<"visit_assign_typeref before replace "<name()<get_type(); + + GEN_LOG_INFO("PROCESS %s -> type\n",ident->name().c_str()); + asn1::assignment *nt = new asn1::type_assignment(ident->name()); + nt->set_type(ntype); + nt->set_parent(m_module); + //nt->parameters(pi->parameters()); + ntype->set_parent(m_module); + ntype->identifier(nt); + m_module->append(nt); + // + } + /** + * + */ + void process_component(asn1::field *ident,asn1::typenode *ntype) + { + asn1::node::node_list pm; + asn1::node *type = ident->get_type(); + GEN_LOG_INFO("PROCESS COMPONENT %s -> type %s\n" + , ident->name().c_str() + , ntype->name().c_str()); + assert( (ntype != NULL) && "ntype must not be NULL"); + //nt->parameters(pi->parameters()); + ntype->set_parent(ident->get_parent()); + ntype->identifier(ident); + // + ident->set_type(ntype); + // If properly cloned, I should delete type from ident before replacing it + } + protected: + asn1::module *m_module; + asn1::resolver &resolver; + std::fstream &m_log; +}; + + + +namespace asn1 +{ + +/** + * + */ +gen_optimizer::gen_optimizer(asn1::module *n,asn1::module::modules_type &m) + : generator(n,m) +{ +} + + +/** + * + */ +void +gen_optimizer::gen_module(std::ostream &os,module *m) +{ + optimize_phase1 opt1(m_resolver,m_log); + + os<<"*"<name()< Parse Object Defined Syntax"< Replace components of"< Replace selection with real type"< nested types made global "< typeref resolution. Set real_type adjust reference "< Process parameterized types ..."< Check/Correct values eg v1 Toto ::= { mib 2 }"< +#include "asn1_generator.h" + +namespace asn1 +{ + +/** + * @brief this generator does not produce any output. + * It processes the module and performs AST transformation + * in order to facilitate the generators work. + * -> COMPONENTS OF and SELECTION replacement + * -> Object with defined syntax parsing + * -> Inner private types are set global with typeref + * example : G ::= SEQUENCE { a SEQUENCE { b INTEGER } } + * while be transormed G_a ::= SEQUENCE { b INTEGER } + * G ::= SEQUENCE { a G_a } + * + */ +class gen_optimizer : public asn1::generator +{ + public: + gen_optimizer(asn1::module *n,asn1::module::modules_type &m); + + virtual void gen_module(std::ostream &os,module *) ; + + void gen_const(std::ostream &os,asn1::node *n) {}; + // + void gen_typedef(std::ostream &os,asn1::typenode *n) {}; + private: +}; + + +} +/** + * vim:et:sw=2:ts=2 + */ +#endif /*ASN1_GEN_OPTIMIZER_H*/ diff --git a/libgen/asn1_generator.cpp b/libgen/asn1_generator.cpp new file mode 100644 index 0000000..9c74cad --- /dev/null +++ b/libgen/asn1_generator.cpp @@ -0,0 +1,472 @@ +#include +#include +#include +#include + +#include "asn1_node.h" +#include "asn1_module.h" +#include "asn1_generator.h" +#include "adt/asn1_recursive_visitor.h" + +namespace asn1 +{ + + +generator::generator(module *root_m) + : m_module(root_m) + , m_config() + , m_resolver(*root_m,asn1::module::modules_type()) +{ +} + +generator::generator(module *root_m,asn1::module::modules_type &m_) + : m_module(root_m) + , m_config() + , m_resolver(*root_m,m_) +{ + asn1::module::modules_type::iterator it; + GEN_LOG_DEBUG("generator::generator m_.size=%lu ",m_.size()); + m_modules.resize(m_.size()); + m_modules = m_; + // Debuging code +#if 0 + for ( it = m_.begin() + ; it != m_.end() + ; ++it) + { + std::cerr<<"generator::generator "<<(*it)->name()<<" "<<(*it)->size()<name().c_str() + ,(*it)->size()); + } + for ( it = m_modules.begin() + ; it != m_modules.end() + ; ++it) + { + std::cerr<<"generator::generator "<<(*it)->name()<<" "<<(*it)->size()<name().c_str() + ,(*it)->size()); + } +#endif +} + +// If a parameter is of type without value, it's template +// otherwise it's normal structure +// +bool +generator::is_template(asn1::node *_params) +{ + bool ret = false; + asn1::parameters *params = dynamic_cast(_params); + if (_params) + assert(params != NULL); + if (params) + { + asn1::node::iterator it = params->begin(); + if (params->name().compare("SIGNED") == 0) + { + std::cerr<<"generator::is_template "<name()<<" Should be yes "<<(it== params->end())<end(); ++it) + { + asn1::parameter ¶m = dynamic_cast(*(*it)); + if (params->name().compare("SIGNED") == 0) + { + std::cerr<<"generator::is_template "<name()<<" "<name().compare("SIGNED") == 0) + { + std::cerr<<"generator::is_template "<name()<<" but is false"< &v) +{ + long integer = value; + long intsize = 4; + long mask = 0x1FF <<23; // Shift 8 *3 - 1 ? 0xFF800000 +#ifdef DEBUG + GEN_LOG_DEBUG("generator::encode_integer %ld %lx",value,value); + // std::cout<<"encode_integer: "< 1)) { + intsize--; + integer <<=8; +#ifdef DEBUG + GEN_LOG_DEBUG("generator::encode_integer step 1 %lx",integer); + // std::cout<<"is: "<name()); + fn.append(suf); + fn.append(".gen.log"); + m_log.open(fn.c_str(),std::fstream::out); + gen_module(os,m_module); + m_log.close(); + } +} + +int generator::tag_mode(asn1::node *node) const +{ + assert((m_module != NULL) && "generator::tag_mode m_module should not be NULL"); + asn1::node::tag_type t = node->tag(); + if (node->tagged()) + { + if (t.m_mode == asn1::node::tag_type::TM_DEFAULT) + { + asn1::node::tag_type mt = m_module->tag(); + if (mt.m_mode == asn1::node::tag_type::TM_DEFAULT) + { + return asn1::node::tag_type::TM_EXPLICIT; + } else { + return mt.m_mode; + } + } else { + return t.m_mode; + } + } else { + return asn1::node::tag_type::TM_DEFAULT; + } +} + + +bool +generator::is_tag_explicit(asn1::typenode &_type) const +{ + return tag_mode(&_type) == asn1::node::tag_type::TM_EXPLICIT; +} +/** +* For the generator classes We provide a methode to convert types::ASN1_ to ASN1 tags ids +*/ +int generator::type2tagid(int v) const +{ + switch (v) { + case asn1::type::ASN1_BOOLEAN: + return 1; + break; + case asn1::type::ASN1_INTEGER: + return 2; + break; + case asn1::type::ASN1_BIT_STRING: + return 3; + break; + case asn1::type::ASN1_OCTET_STRING: + return 4; + break; + case asn1::type::ASN1_NULL: + return 5; + break; + case asn1::type::ASN1_OBJECT_IDENTIFIER: + return 6; + break; + case asn1::type::ASN1_OBJECT_DESCRIPTOR: + return 7; + break; + case asn1::type::ASN1_EXTERNAL: + return 8; + break; + case asn1::type::ASN1_REAL: + return 9; + break; + case asn1::type::ASN1_ENUMERATED: + return 10; + break; + case asn1::type::ASN1_EMBEDDED_PDV: + return 11; + break; + case asn1::type::ASN1_UTCTime: + return 23; + break; + case asn1::type::ASN1_GeneralizedTime: + return 24; + break; + case asn1::type::ASN1_STRING_IA5String: + return 22; + break; + case asn1::type::ASN1_STRING_PrintableString: + return 19; + break; + case asn1::type::ASN1_STRING_VisibleString: + return 26; + break; + case asn1::type::ASN1_STRING_ISO646String: + return 29; + break; /* aka VisibleString */ + case asn1::type::ASN1_STRING_NumericString: + return 18; + break; + case asn1::type::ASN1_STRING_UniversalString: + return 28; + break; + case asn1::type::ASN1_STRING_BMPString: + return 30; + break; + case asn1::type::ASN1_STRING_UTF8String: + return 12; + break; + case asn1::type::ASN1_STRING_GeneralString: + return 27; + break; + case asn1::type::ASN1_STRING_GraphicString: + return 25; + break; + case asn1::type::ASN1_STRING_TeletexString: + return 22; + break; + case asn1::type::ASN1_STRING_T61String: + return 20; + break; + case asn1::type::ASN1_STRING_VideotexString: + return 21; + break; + case asn1::type::ASN1_STRING_ObjectDescriptor: + return 7; + break; + default: return 0; + } +} +/** + * + */ +bool generator::type_in_imports(asn1::node *type,asn1::node **ns) +{ + return type_in_imports(type->name(),ns); +} + +bool generator::type_in_imports(const std::string &type,asn1::node **ns) +{ + bool ret = false; + asn1::import_list *imports = m_module->imports(); + if (imports == NULL) + { + GEN_LOG_ERROR("type %s not in imports no imports\n",type.c_str()); + return ret; + } + asn1::import *import; + asn1::typeref *ref; + if (ret = imports->get_item(type,import,ref)) + { + GEN_LOG_DEBUG("found %s in %s\n",type.c_str(),import->identifier()->name().c_str()); + *ns = import->identifier(); + } + return ret; +} + +bool +generator::get_type_in_module(const std::string &mod_name,const std::string &typ_name,asn1::node **n) +{ + GEN_LOG_INFO("generator::get_type_in_module mod=%s cur_module=%s name=%s modules=%lu\n" + ,mod_name.c_str() + ,m_module->name().c_str() + ,typ_name.c_str() + ,m_modules.size()); + asn1::module::modules_type::iterator mit = std::find_if(m_modules.begin(),m_modules.end(), + asn1::find_module(mod_name)); + if (mit != m_modules.end()) + { + asn1::node::iterator nit = + std::find_if((*mit)->begin(),(*mit)->end(),asn1::find_node(typ_name)); + if (nit != (*mit)->end()) + { + *n = (*nit); + return true; + } else + { + GEN_LOG_ERROR("get_type_in_module type %s not in module %s\n" + ,typ_name.c_str() + ,mod_name.c_str()); + return false; + } + } else { + GEN_LOG_ERROR("get_type_in_module did not find module %s\n",mod_name.c_str()); + return false; + } +} + +/** + * + */ +void generator::path2modulestring(asn1::node *type,std::string &ss) +{ + asn1::node::node_list lst; + + type->path2module(lst); + for (asn1::node::const_iterator nit = lst.begin() + ; nit != lst.end() + ; ++nit ) + { + if ( (*nit)->is_private() ) + { + ss += (*nit)->cpp_name() + "::"; + } else + ss += (*nit)->identifier()->cpp_name() + "::"; + } +} + +/** + * Find a referenced value + */ +bool +generator::loockup_value(const std::string &_v,asn1::node **ov) +{ + bool ret = false; + asn1::node *ns = NULL; + if (type_in_imports(_v,&ns)) { + GEN_LOG_ERROR("Value %s in import %s not yet handled\n",_v.c_str(),ns->name().c_str()); + } else { + asn1::node::iterator it = std::find_if( m_module->begin() + , m_module->end() + ,asn1::find_value(_v)); + if ( it != m_module->end()) + { + // Ok, found the value, return it + *ov = (*it); + ret = true; + } + } + return ret; +} + +/** + * Find the appropriate class node + */ +bool +generator::loockup_class(const std::string &_v,asn1::node **ov) +{ + bool ret = false; + GEN_LOG_ERROR("To be coded %s\n",_v.c_str()); + return ret; +} + +/** + * Find the primary type for a typeref type + */ +bool +generator::loockup_prim_type(const std::string &_v,asn1::node **ov) +{ + bool ret = false; + GEN_LOG_ERROR("To be coded %s \n",_v.c_str()); + return ret; +} + + + + +bool +generator::have_attributes_to_init(const asn1::constructed *type) const +{ + bool result = false; + asn1::node::const_iterator attr_it = type->begin(); + + for (; attr_it != type->end() ; ++attr_it) + { + asn1::field *f = dynamic_cast(*attr_it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL && attr_type->type_id()() != asn1::type::ASN1_EXTENSIBLE ) { + result = true; + break; + } + } + return result; +} + +void +generator::reference_chaine(asn1::typeref *type, std::list &lst) +{ + //asn1::node *t = type; + asn1::node *ns = NULL; + // add the first reference in case it's tagged Explicitly + //lst.push_back(type); + if ( type == NULL) + return; + // + asn1::node *t = type->get_real_type(); + while (t && t->as_typeref() ) + { + lst.push_back(t); + t = t->as_typeref()->get_real_type(); + } + if (t) + lst.push_back(t); +} + + +bool +generator::add_symbol(std::string &name,asn1::node *type) +{ + SymbolMap_iterator it = m_symbols.find(name); + + if (it == m_symbols.end()) + { + m_symbols[name] = type; + return true; + } else + { + GEN_LOG_WARN("generator::add_symbol %s are equal %d\n",name.c_str(),((*((it)->second)) == *type)); + return false; + } +} + +} +/* + * vim: et sw=2 ts=2 list: + */ diff --git a/libgen/asn1_generator.h b/libgen/asn1_generator.h new file mode 100644 index 0000000..7711321 --- /dev/null +++ b/libgen/asn1_generator.h @@ -0,0 +1,263 @@ +#ifndef ASN1_GENERATOR_H__ +#define ASN1_GENERATOR_H__ +#include +#include +#include +#include +#include "asn1_node.h" +#include "asn1_module.h" +#include "asn1_resolver.h" + +#if defined(_WIN32) +#define GEN_LOG_DEBUG(fmt,...) do {\ + } while (0) +#define GEN_LOG_INFO(fmt,...) do {\ + } while (0) +#define GEN_LOG_WARN(fmt,...) do {\ + } while (0) +#define GEN_LOG_ERROR(fmt,...) do {\ + } while (0) +#else +#define GEN_LOG_DEBUG(fmt,args...) do {\ + char _lbuf[1024]; \ + const char *fn = strrchr(const_cast(__FILENAME__),'/'); \ + fn = (fn == NULL)?__FILENAME__:fn+1; \ + if (m_log.is_open()) { \ + m_log<<"DEBUG "<<__FUNCTION__<<" "; \ + sprintf(_lbuf," (%s : %d) ",fn,__LINE__); m_log<<_lbuf; \ + sprintf(_lbuf,fmt,##args); m_log<<_lbuf; \ + } \ + } while (0) + +#define GEN_LOG_INFO(fmt,args...) do {\ + char _lbuf[1024]; \ + const char *fn = strrchr(const_cast(__FILENAME__),'/'); \ + fn = (fn == NULL)?__FILENAME__:fn+1; \ + if (m_log.is_open()) { \ + m_log<<"INFO "<<__FUNCTION__<<" "; \ + sprintf(_lbuf," (%s : %d) ",fn,__LINE__); m_log<<_lbuf; \ + sprintf(_lbuf,fmt,##args); m_log<<_lbuf; \ + } \ + } while (0) + +#define GEN_LOG_WARN(fmt,args...) do {\ + char _lbuf[1024]; \ + if (m_log.is_open()) { \ + m_log<<"WARN "<<__FUNCTION__<<" "; \ + sprintf(_lbuf," (%s : %d) ",__FILENAME__,__LINE__); m_log<<_lbuf; \ + sprintf(_lbuf,fmt,##args); m_log<<_lbuf; \ + } \ + } while (0) + +#define GEN_LOG_ERROR(fmt,args...) do {\ + char _lbuf[1024]; \ + if (m_log.is_open()) { \ + m_log<<"ERROR "<<__FUNCTION__<<" "; \ + sprintf(_lbuf," (%s : %d) ",__FILENAME__,__LINE__); m_log<<_lbuf; \ + sprintf(_lbuf,fmt,##args); m_log<<_lbuf; \ + } \ + } while (0) +#endif +namespace asn1 +{ + + +struct generator_config +{ + generator_config() + : m_printf(true) + , m_ber(true) + , m_per(false) + , m_xer(false) + , m_jer(false) + , m_ots(false) + , m_oer(false) + , m_template(false) + , m_debug(true) + , m_source_comment(true) + , m_source_debug(false) + , m_codec(false) + , m_split_cpp(false) + {}; +#define WITH_CODEC(nm) \ + bool with_##nm() { return m_##nm; } ; \ + void with_##nm(bool b) { m_##nm = b ; } ; + WITH_CODEC(ber) + WITH_CODEC(per) + WITH_CODEC(xer) + WITH_CODEC(jer) + WITH_CODEC(printf) + WITH_CODEC(oer) + WITH_CODEC(template) + WITH_CODEC(debug) + WITH_CODEC(source_comment) + WITH_CODEC(source_debug) + WITH_CODEC(nested) + WITH_CODEC(codec) + WITH_CODEC(split_cpp) +#undef WITH_CODEC + // generator configuration flags + bool m_printf; + bool m_ber; + bool m_per; + bool m_xer; + bool m_ots; + bool m_jer; + bool m_oer; + bool m_template; // tells if we generate template file or cpp file + bool m_debug; + bool m_source_comment; + bool m_source_debug; + bool m_nested; + bool m_codec; // Remove codec function code + bool m_split_cpp; // Implementation in separated cpp files + +}; + +/** + * + */ +class generator +{ + protected: + generator(const generator &g) : m_resolver(g.m_resolver) {}; + public: + typedef std::map SymbolMap; + typedef SymbolMap::iterator SymbolMap_iterator; + typedef SymbolMap::const_iterator SymbolMap_const_iterator; + + generator(module *n = NULL); + + generator(module *root_m,asn1::module::modules_type &m_) ; + + virtual ~generator() {}; + + void set_config(const generator_config &c) { m_config = c; } + + generator_config &get_config() { return m_config; } + + // Set and getters + // + module *get_module() const { return m_module ; }; + + asn1::module::modules_type &get_module_list() { return m_modules;}; + + // + void oid_value(asn1::node *n,int *pos,std::vector *v); + + void encode_integer(long value,std::vector &v); + + // Tells if a the structure should be in the form of templale +#define WITH_CODEC(nm) \ + bool with_##nm() { return m_config.m_##nm; } ; + WITH_CODEC(ber) + WITH_CODEC(per) + WITH_CODEC(xer) + WITH_CODEC(jer) + WITH_CODEC(printf) + WITH_CODEC(oer) + WITH_CODEC(template) + WITH_CODEC(debug) + WITH_CODEC(source_comment) + WITH_CODEC(source_debug) + WITH_CODEC(codec) + WITH_CODEC(split_cpp) +#undef WITH_CODEC + // generator configuration flags + // or not + bool is_template(asn1::node *params); + + virtual void gen_const(std::ostream &os,node *) = 0; + + virtual void gen_typedef(std::ostream &os,typenode *) = 0; + + virtual void gen_set_of(std::ostream &os,set_of &) {}; + + virtual void gen_sequence_of(std::ostream &os,sequence_of &) {}; + + virtual void gen_seq(std::ostream &os,sequence &) {}; + + virtual void gen_choice(std::ostream &os,choice &) {}; + + virtual void gen_object(std::ostream &os,node *) {}; + + virtual void gen_module(std::ostream &os,module *) = 0; + + virtual void gen(std::ostream &os,const std::string &s = "gen"); + // return the choosen tagging mode + int tag_mode(asn1::node *node) const; + /** + * + */ + bool is_tag_explicit(asn1::typenode &_type) const ; + /** + * This function loops over alll childs in module and + * depending on the meta type call gen_typedef,gen_const, + */ + int type2tagid(int v) const; + + //bool size_range(asn1::node * type,long &start ,long &end); + /** + * Generic function that is going to check if + * a type is imported. + * DEPRECATED. Use resolver + */ + bool type_in_imports(asn1::node *type,asn1::node **ns) ; + bool type_in_imports(const std::string &type,asn1::node **ns) ; + /** + * Find a referenced value + */ + bool loockup_value(const std::string &_v,asn1::node **ov) ; + /** + * Find the appropriate class node + */ + bool loockup_class(const std::string &_v,asn1::node **ov) ; + /** + * Find the primary type for a typeref type + */ + bool loockup_prim_type(const std::string &_v,asn1::node **ov) ; + + /** + * DEPRECATED, use resolver + */ + bool get_type_in_module(const std::string &mod_name,const std::string &typ_name,asn1::node **n) ; + + /** + * Usefull object functions + */ + inline void set_gen_printf(bool _b) { m_config.m_printf = _b;}; + inline bool do_gen_printf() {return m_config.m_printf;}; + + bool have_attributes_to_init(const asn1::constructed *type) const ; + // for optimization purpose + void reference_chaine(asn1::typeref *type, std::list &lst); + + void path2modulestring(asn1::node *type,std::string &s); + /** + * + */ + std::fstream &logger() { return m_log; }; + /** + * Give access to the resolver for helper classes + */ + asn1::resolver &resolver() { return m_resolver; }; + /** + * if the symbol does not exists, add it and return true. + * if the symbol exists in the map, return false; + */ + bool add_symbol(std::string &name,asn1::node *); + protected: + std::fstream m_log; + module *m_module; + SymbolMap m_symbols; + asn1::module::modules_type m_modules; + generator_config m_config; + asn1::resolver m_resolver; +}; + +} + +/* + * vim:et:sw=2:ts=2 + */ +#endif diff --git a/libgen/asn1_generator_helper.h b/libgen/asn1_generator_helper.h new file mode 100644 index 0000000..275e8ba --- /dev/null +++ b/libgen/asn1_generator_helper.h @@ -0,0 +1,42 @@ +#ifndef ASN1_GENERATOR_HELPER_H +#define ASN1_GENERATOR_HELPER_H + +/** + * This class defines the interface that each + * asn1 type generation should implement .... + * -- typedef sequence generator + * -- typedef choice generator + * -- typedef set generator + * -- typedef set of generator + * -- typedef sequ of generator + * + * This allows us to split and isolate the generation + * code .... and simplifity the readability + */ +class generator_helper +{ + public: + generator_helper(std::ostream &os) : m_os(os) { } ; + + // generate entry point + virtual void generate() {}; + // generate codec part + virtual void generate_per() = 0; + // + virtual void generate_ber() = 0; + // + virtual void generate_oer() = 0; + // + virtual void generate_jer() = 0; + // + virtual void generate_xer() = 0; + + // generate encoder + // generate decoder + // generate constructor + // generate + protected: + std::ostream &m_os; +}; + +#endif diff --git a/libgen/cpp/cgcpp_helper.cpp b/libgen/cpp/cgcpp_helper.cpp new file mode 100644 index 0000000..c9194f1 --- /dev/null +++ b/libgen/cpp/cgcpp_helper.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" + + +/** + * constructor + */ +cgcpp_helper::cgcpp_helper( generate_codec_cpp &g + , std::ostream &os + ) + : m_gencpp(g), generator_helper(os),m_log(g.logger()) +{ +} + +/** + * + * @brief common way to generate the required code depending + * on the global settings given to the asn1 parser. + */ +void +cgcpp_helper::generate() +{ + generate_descriptor(); + + generate_members(); + + generate_ctors(); + + generate_operators(); + + generate_printf(); + /* codec function generators */ + if (m_gencpp.with_ber()) + { + generate_ber(); + } + if (m_gencpp.with_oer()) + { + generate_oer(); + } + if (m_gencpp.with_jer()) + { + generate_jer(); + } + if (m_gencpp.with_per()) + { + generate_per(); + } +} + +void +cgcpp_helper::generate_descriptor() +{ +} + + diff --git a/libgen/cpp/cgcpp_helper.h b/libgen/cpp/cgcpp_helper.h new file mode 100644 index 0000000..71d6545 --- /dev/null +++ b/libgen/cpp/cgcpp_helper.h @@ -0,0 +1,53 @@ +#ifndef CODE_GEN_CPP_HELPER_H +#define CODE_GEN_CPP_HELPER_H + +/** + * This class defines the interface that each + * asn1 type generation should implement .... + * Unlike generator_helper, this class provides a first + * level of functions dedicated to c++ code generation. The goal is + * to move the generation from one unique file to one file per type. + * -> provide streams for cpp,h and hpp. + * -> provide generic preamble et epilog + * -> open /close stream + */ +class cgcpp_helper : public generator_helper +{ + public: + cgcpp_helper( generate_codec_cpp &g + , std::ostream &os + ); + + // generate entry point + virtual void generate() ; + // generate codec part + virtual void generate_per() {}; + // + virtual void generate_ber() {}; + // + virtual void generate_oer() {}; + // + virtual void generate_jer() {}; + // + virtual void generate_xer() {}; + + // Type of code generated in CPP files + virtual void generate_ctors() {}; + + virtual void generate_printf() {}; + + virtual void generate_descriptor() ; + + virtual void generate_members() {}; + + virtual void generate_operators() {}; + // generate encoder + // generate decoder + // generate constructor + // generate + protected: + std::fstream &m_log; + generate_codec_cpp &m_gencpp; +}; + +#endif diff --git a/libgen/cpp/cgcpph_bitstring.cpp b/libgen/cpp/cgcpph_bitstring.cpp new file mode 100644 index 0000000..9c7eed2 --- /dev/null +++ b/libgen/cpp/cgcpph_bitstring.cpp @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_construct.h" +#include "cgcpph_bitstring.h" + + +/** + * + * + */ +cgcpph_bit_string::cgcpph_bit_string(generate_codec_cpp &g,std::ostream &os,asn1::bit_string &s) + : cgh_construct(g,os,s) , m_bit_string(s) +{ +} + +/** + * + * + */ +cgcpph_bit_string::~cgcpph_bit_string() +{ +} + + +/** Helper functions + * + */ +void cgcpph_bit_string::generate(const std::string &scope) +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_bit_string helper launched "<identifier()->cpp_name(); + + m_os<<"std::ostream & operator <<(std::ostream &os,const "; + m_os<cpp_name() ); + std::string structName ( ns + "::" + m_bit_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + /* template specialisation hpp */ + // m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecPER::encode(streams::per &c,const "<\n"; + hpp<<"int codecPER::decode(streams::per &c,"<\n"; + cpp<<"void codecPER::encode(asn1::streams::per &c,const "<\n"; + cpp<<"int codecPER::decode(asn1::streams::per &c,"<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + m_os<<"\t\tBIT_STRING tmp;\n"; + m_os<<"\t\tint rest = tmp.decode(ctx);\n"; + m_os<<"\t\tthis->get_value() = tmp.get_value();\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + } + if (m_gencpp.with_codec()) + { + std::string ns( m_gencpp.get_module()->cpp_name() ); + std::string structName ( ns + "::" + m_bit_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + /* template specialisation hpp */ + // m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name() ); + std::string structName ( ns + "::" + m_bit_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + /* template specialisation hpp */ + // m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecOER::encode(streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name() ); + std::string structName ( ns + "::" + m_bit_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + /* template specialisation hpp */ + // m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_primitive.h" +#include "cgcpph_boolean.h" + + +cgcpph_boolean::cgcpph_boolean(generate_codec_cpp &g,std::ostream &os,asn1::boolean &s) + : cgcpph_primitive(g,os,s) + , m_boolean(s) +{ +} + +cgcpph_boolean::~cgcpph_boolean() +{ +} + +/** Helper functions + * + * + */ +void cgcpph_boolean::generate_ctors() +{ + if (m_gencpp.with_source_comment()) + { + m_os<<"// cgcpph_boolean helper launched "; + m_os<cpp_name(); + std::string structName(ns + "::" + m_boolean.identifier_cpp_name()); + + if (m_gencpp.with_codec()) + { + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecPER::encode(streams::per &c,const "<\n"; + hpp<<"int codecPER::decode(streams::per &c,"<\n"; + cpp<<"void codecPER::encode(asn1::streams::per &c,const "<\n"; + cpp<<"int codecPER::decode(asn1::streams::per &c,"<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + m_os<<"\t\tBOOLEAN tmp;\n"; + m_os<<"\t\tint rest = tmp.decode(ctx);\n"; + m_os<<"\t\tthis->get_value() = tmp.get_value();\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + } + /** + * New way with codec .... + */ + if (m_gencpp.with_codec()) + { + std::string structName; + std::string ns = m_gencpp.get_module()->cpp_name(); + structName = ns + "::" + m_boolean.identifier_cpp_name(); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + /* header template specialisation */ + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name(); + std::string structName(ns + "::" + m_boolean.identifier_cpp_name()); + + if (m_gencpp.with_codec()) + { + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecOER::encode(streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name(); + std::string ns = m_gencpp.get_module()->cpp_name(); + structName = ns + "::" + m_boolean.identifier_cpp_name(); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + + + if (m_gencpp.with_codec()) + { + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "asn1_visitor.h" +#include "cgh_construct.h" +#include "cgcpph_choice.h" + + +cgcpph_choice::cgcpph_choice(generate_codec_cpp &g,std::ostream &os,asn1::choice &s) + : cgh_construct(g,os,s) + , m_choice(s) +{ +} + +cgcpph_choice::~cgcpph_choice() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cgcpph_choice::generate() +{ + + GEN_LOG_DEBUG("cgcpph_choice::generate node=%s\n",m_choice.identifier_cpp_name().c_str()); + + // End generate private ... + + cgcpp_helper::generate(); + + if (m_gencpp.with_codec()) + gen_codec(); + // Generate encoders and decoders +} + +/** + * + */ +void cgcpph_choice::generate_descriptor() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_choice helper launched "<(*lit); + asn1::typenode *ft = f->get_type(); + + if (m_gencpp.with_source_comment()) + { + m_os<<"//gen_choice preproc="<cpp_name(); + m_os<<" private="<cpp_name().c_str() + , ft->name().c_str()); + if (m_gencpp.with_source_comment()) + m_os<<"// gen_choice call gen_private_attribute: "<cpp_name()<cpp_name()<cpp_name(); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// choice type "<<"::"<\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<identifier(); + + m_os<<"\t\tunsigned long pos = ctx.bytes();"<cpp_name()<<" tag = %02x \",(unsigned short)b[pos]);"<cpp_name()<<" none selected tag = %02x WRONG\",(unsigned short)b[pos]);"<identifier(); + + if (n == NULL ) + { + std::cerr<<"gen_choice_encode n == NULL"; return; + } + + m_os<<"\t\tint _ret = asn1::ok;\n"; + m_os<<"\t\tif (m_choice)\n"; + m_os<<"\t\t{\n"; + if (m_gencpp.with_source_debug()) + { + m_os<<"\t\t\tASN1_BER_LOG_DEBUG(\""<cpp_name(); + m_os<<"::codec ENCODE tag=%d \",m_choice->tag().byte());\n"; + } + m_os<<"\t\t\tencode(ctx);"<type_node()) + ) + { + m_os<<"// Reference"<cpp_name()<<"(const "; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<" &s)\n{\n"; + m_os<<"\tif (m_kind != typeof_"<cpp_name()<<" )\n"; + m_os<<"\t{\n"; +#if 1 + asn1::node::tag_type o_tag = tref.otag(m_gencpp.resolver()); + m_os<<"\t\tchoice_type::set_tag(asn1::tag("; + m_os<cpp_name()<<";\n"; + m_os<<"\t\tcreate_object();\n"; +#endif + m_os<<"\t}\n"; + + m_os<<"\tget_"<cpp_name()<<"() = s;\n"; + m_os<<"};\n"<cpp_name()<cpp_name()<<"(const "; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<" *s)\n{\n"; + m_os<<"\tassert(0);\n"; + m_os<<"};\n"<type_node()) + ) + { + // getter + m_gencpp.gen_composite_attribute_ref( m_os + ,scope + ,attribute + ,params); + m_os<<" &"<cpp_name()<<"()\n{\n"; + // Debug Version + m_os<<"#ifdef DEBUG"<cpp_name(); + m_os<<"(%p) "<cpp_name()<<" k=%d tag=%ld\",this,m_kind,m_tag.get_tag());\n"; + } + /**/ + asn1::node::tag_type o_tag = tref.otag(m_gencpp.resolver()); + m_os<<"\t"<<"if ( m_kind != typeof_"<cpp_name()<<")\n\t{\n"; + m_os<<"\t\t"<<"set_tag( asn1::tag("; + m_os<(m_choice) != NULL);"<cpp_name()<<") {\n"; + m_os<<"\treturn dynamic_cast<"; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<" &>(*m_choice);\n"; + // Release Version + m_os<<"#else"<cpp_name()<<")\n"; + m_os<<"\t\t"<<"set_tag( asn1::tag("; + m_os<(*m_choice);\n"; + m_os<<"#endif"<cpp_name()<<"() const\n{\n"; + m_os<<"\treturn dynamic_cast(*m_choice);\n"; + m_os<<"}\n"; + } else + { + m_os<<"// getter to DO get_"<cpp_name()<cpp_name()<<"()\n{\n"; + m_os<<"assert(0);\n"; + //m_os<<"\t\treturn dynamic_cast<"; + //m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + //m_os<<" &>(*m_choice);\n"; + m_os<<"}\n"; + } +} + + + +// +void +cgcpph_choice::gen_attribute_setter( const std::string &scope + , const std::string &structName + , asn1::field *attribute + , asn1::node *params + , bool priv) +{ + asn1::typenode *attr_type = attribute->get_type(); + + if (attr_type != NULL) + { + switch (attr_type->type_id()()) + { + case asn1::type::ASN1_ENUMERATED: + case asn1::type::ASN1_CHOICE: + case asn1::type::ASN1_SET: + case asn1::type::ASN1_SEQUENCE: + { + m_os<<"//\nvoid "<cpp_name(); + m_os<<"(const "<cpp_name()<<"_t"; + m_os<<" &s)\n{\n\tm_kind = typeof_"<cpp_name(); + m_os<<";\n"; + m_os<<"\tget_"<cpp_name()<<"()=s;\n}\n\n"<cpp_name()<<" ()\n{\n"; + m_os<<"\tassert(check_create());\n"; + m_os<<"\tif (m_kind == typeof_"<cpp_name()<<")\n\t{\n"; + m_os<<"\t\treturn static_cast<"<(*m_choice);\n"; + m_os<<"\t} else {\n"; + m_os<<"\t\tif (m_choice)\n\t\t{\n"; + m_os<<"\t\t\tdelete m_choice;\n\t\t\t m_choice = NULL;\n"; + m_os<<"\t\t\tm_kind = typeof_"<cpp_name()<<";\n"; + m_os<<"\t\t\tcreate_object();\n"; + m_os<<"\t\t\tassert( m_choice != NULL);\n"; + m_os<<"\t\t}\n"; + m_os<<"\t\treturn static_cast<"<(*m_choice);\n"; + m_os<<"\t}\n"; + m_os<<"}\n"; + } + } + break; + case asn1::type::ASN1_REFERENCE: + { + asn1::typeref *tref = dynamic_cast(attr_type); + gen_setter_ref(scope,structName,attribute,*tref,params,priv); + gen_getter_ref(scope,structName,attribute,*tref,params,priv); + } + break; + default: + { + std::string strtype; + if (m_gencpp.type2cppstring(attr_type,strtype,scope) ) + { + m_os<<"//cgcpph_choice::"<<__FUNCTION__<<" default: "<cpp_name()<cpp_name()<<"(const "; + m_os<cpp_name()<<" )\n"; + m_os<<"\t{"; + if (attr_type->tagged()) + { // Tagged value + asn1::node::tag_type tg = attr_type->tag(); + m_os<<"\t\tset_tag(asn1::tag("<tag(); + //std::cerr<<"attribute "<cpp_name()<<" not tagged(0,"<cpp_name()<<";\n"; + m_os<<"\t\tcreate_object();\n"; + m_os<<"\t}\n"; + //os<<"\t"<cpp_name()<<"\t=\ts;\n"; + m_os<<"\tget_"<cpp_name()<<"() = s;\n"; + m_os<<"}\n"<cpp_name()<<" ()\n{\n"; + m_os<<"\tif (m_kind != typeof_"<cpp_name()<<" )\n"; + m_os<<"\t{"; + if (attr_type->tagged()) + { // Tagged value + asn1::node::tag_type tg = attr_type->tag(); + m_os<<"\t\tset_tag(asn1::tag("<tag(); + std::cerr<<"attribute "<cpp_name()<<" not tagged(0,"<cpp_name()<<")\n\t{\n"; + m_os<<"\t\treturn static_cast<"<(*m_choice);\n"; + m_os<<"\t} else\n\t{\n"; + m_os<<"\t\tif (m_choice)\n"; + m_os<<"\t\t{\n"; + m_os<<"\t\t\tdelete m_choice;\n"; + m_os<<"\t\t\tm_choice = NULL;\n"; + m_os<<"\t\t\tm_kind = typeof_"; + m_os<cpp_name()<<"; create_object() ;\n"; + m_os<<"\t\t}\n"; + m_os<<"\t\treturn static_cast<"<(*m_choice);\n"; + m_os<<"\t}\n"; + m_os<<"}\n"; + /* const*/ + m_os<<"const "<cpp_name()<<" () const\n{\n"; + m_os<<"\treturn dynamic_cast(*m_choice);\n"; + m_os<<"}\n"; + } + } + break; + } + } else + { + GEN_LOG_ERROR("attr_type is NULL\n"); + } + +} + +// Helper function to replace :: with _ in scope +static +char lop_substitute(char c) +{ + return (c == ':')?'_':c; +} + +// +void cgcpph_choice::generate_printf() +{ + asn1::node::iterator lit; + asn1::node *ident = m_choice.identifier(); + + + // FIND ANOTHER NAME FOR THAT DEFINE ASN1_WITH_PRINTF + m_os<<"#if 1\n"; + // ostream function + m_os<<"std::ostream &operator <<(std::ostream &os,const "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s)\n"; + + m_os<<"{\n"; + // Ok, Now, deal with the attributes and so on + // + //os<<"\tif (s.m_choice != NULL)"<cpp_name(); + std::string structName( ns + "::" + m_choice.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + bool priv = m_choice.is_private(); + + // Generator for encode en decode wrong place + gen_ber_encode("",m_choice.identifier_cpp_name(),priv); + gen_ber_decode("",m_choice.identifier_cpp_name(),priv) + ; + if (m_gencpp.with_codec()) + { + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// choice type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<cpp_name()<<": "; + cpp<<"return decode(c,_t.get_"<cpp_name()<<"());\n"; + } + } + } + cpp<<"\t\t\t}\n"; + cpp<<"\t\t}\n"; + cpp<<"\t}\n"; + cpp<<"\treturn asn1::ok;\n"; + cpp<<"}\n"; + } +// + if (m_choice.tagged()) + { + if ( m_gencpp.is_tag_explicit(m_choice) ) + { + } + } +} + +/** + * + * + */ +void cgcpph_choice::gen_ctor( ) +{ + asn1::node *type = &m_choice; + // Constructor + // + m_os<<""<identifier_name(); + m_os<<"(%p) choice:: 1 "<identifier_name()<<" k=%d tag=%ld\",this,k,t.get_tag());\n"; + } + m_os<<"\tset_tag(t);\n"; + m_os<<"}\n"; + + // New constructor without k + m_os<<""<identifier_name(); + m_os<<"(%p) choice:: 2 "<identifier_name()<<" m_choice=%p tag=%ld\",this,m_choice,t.get_tag());\n"; + } + m_os<<"\tset_tag(t);\n"; + m_os<<"}\n"; + + // Needed for clone + m_os<<""<identifier_name(); + m_os<<"(%p) copy ctor "<identifier_name()<<" s.m_kind=%d s.tag=%ld\",this,s.m_kind,s.m_tag.get_tag());\n"; + } + m_os<<"}\n"; + // destructor +} +// +void +cgcpph_choice::gen_clone( ) +{ + asn1::node *ident = m_choice.identifier(); + asn1::constructed *params = NULL; + + if (ident != NULL) + { + params = ident->parameters(); + } + + m_os<equal(*(o.m_choice));\n"; + /** + * Handle choices for down casting ... + */ + m_os<<"\t\tswitch (m_kind)\n"; + m_os<<"\t\t{\n"; + for (; lit != (type)->end() ; lit++) + { + std::string strtype; + asn1::field *field = dynamic_cast(*lit); + asn1::typenode *attribute_type = field->get_type(); + if (attribute_type == NULL) + continue; + asn1::type type_id = attribute_type->type_id(); + + if (type_id() == asn1::type::ASN1_EXTENSIBLE) + { + m_os<<"\t\t// Extensible marker"<cpp_name()<<":\n"; + m_os<<"\t\t\treturn get_"<cpp_name()<<"() =="; + m_os<<" o.get_"<cpp_name()<<"();\n"; + } + } + m_os<<"\t\tdefault: return false;\n;"; + m_os<<"\t\t}\n"; /* End switch */ + + m_os<<"\t}\n"; + m_os<<"\treturn false;\n"; + m_os<<"}\n\n"; +} +// + +// +void cgcpph_choice::gen_ber_encode( const std::string &scope + , const std::string &structName + , bool priv) +{ + std::string lscope; + asn1::node *type = &m_choice; + if ( m_gencpp.with_ber() + && type->tagged() + && m_gencpp.is_tag_explicit(m_choice) ) + { + lscope = scope + structName; + + m_os<<"void "<tag().m_class<<",1,"<tag().m_value<<");"<encode(ctx);"< 127)"<tagged() + && m_gencpp.is_tag_explicit(m_choice) ) + { + lscope = scope + structName; + // decode + m_os<<"int "<tag().m_class<<","; + m_os<tag().m_value<<",true),len) ) {"<decode(ctx);"<cpp_name(); + std::string structName = MName + "::" + m_choice.identifier()->cpp_name(); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + // TODO + if (m_gencpp.with_codec()) + { + std::string ns = m_gencpp.get_module()->cpp_name(); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// choice type "<\n"; + hpp<<"void codecOER::encode(streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(streams::oer &c,"<cpp_name(); + std::string structName = MName + "::" + m_choice.identifier()->cpp_name(); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + + if (m_gencpp.with_codec()) + { + std::string ns = m_gencpp.get_module()->cpp_name(); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// choice type "<\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void asn1::codecJER::encode(asn1::streams::jer &c,const "<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<cpp_name()<<":\n"; + cpp<<"\t\t{\n"; + cpp<<"\t\t\tc.put_char(\"\\\"\",1);\n"; + cpp<<"\t\t\tc.put_char(_t.get_member()->m_name,"<cpp_name().size()<<");\n"; + cpp<<"\t\t\tc.put_char(\"\\\": \",3);\n"; + cpp<<"\t\t\tencode(c,_t.get_"<cpp_name()<<"());\n"; + cpp<<"\t\t\tbreak;\n"; + cpp<<"\t\t}\n"; + } + } + } + cpp<<"\t\tdefault: ;\n"; + cpp<<"\t}\n"; + cpp<<"\tc.put_char(\"}\",1);\n"; + cpp<<"}\n"; + + /** Implementation for decoder */ + cpp<<"\ntemplate<>\n"; + cpp<<"int asn1::codecJER::decode(asn1::streams::jer &c,"<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<cpp_name()<<"\"))\n"; + cpp<<"\t\t{\n"; + cpp<<"\t\t\tdecode(c,_t.get_"<cpp_name()<<"());\n"; + cpp<<"\t\t\tgoto choice_end;\n"; + cpp<<"\t\t}\n"; + } + } + } + cpp<<"\t}\n"; + cpp<<"choice_end:\n"; + cpp<<"\tif (!c.get_token(asn1::streams::jer::jer_tok_right_bracket))\n"; + cpp<<"\t\treturn asn1::wrong_type;\n"; + cpp<<"\treturn asn1::ok;\n"; + cpp<<"}\n"; + } + +} + +// +void cgcpph_choice::generate_xer() +{ +} + +/** + * Helper class to generate parameter + * initialization per attribute. + */ +class gco_actp : public node_visitor +{ + public: + gco_actp(std::ostream &_os,generate_codec_cpp &_g,asn1::choice &_c) + : m_os(_os) , m_log(_g.logger()), m_gencpp(_g), m_choice(_c) + { + m_assign = m_choice.identifier()->as_assignment(); + assert( (m_assign != NULL ) && " m_assign should not be NULL for choice type"); + } + + + void visit_valueset(asn1::valueset *v) + { + long pos; + asn1::typeref *g = NULL; // governor + m_os<<"\t\t// Ok "<<__FUNCTION__<<" todo "; + if (asn1::typeref *tref = v->get_typeref()) + { + m_os<name()<<" "; + if (asn1::parameter *p = m_assign->have_parameter(tref,pos) ) + { + if (asn1::node *gov = p->get_governor()) + g = dynamic_cast(gov); + m_os<<" yes have parameter "<name()<<"\n"; + // If gorvernor is not simple, + if ( g && (! g->is_simple())) + { + asn1::parameters &cparams = *m_rt->identifier()->parameters()->as_parameters(); + m_os<<"\t\tinstance."<name()<<" = "<name()<<";\n"; + } + } + } + m_os<act_parameters(); + if ( ! aplist) + return; + for ( asn1::node::iterator it = aplist->begin() ; + it != aplist->end(); ++it) + { + /* either value_set, object_set value, typeref */ + if ((*it)) + visit((*it)); + } + } + protected: + asn1::node *m_rt; + asn1::assignment *m_assign; + std::fstream &m_log; + std::ostream &m_os; + generate_codec_cpp &m_gencpp; + asn1::choice &m_choice; +}; + +void cgcpph_choice::gen_create_object( ) +{ + std::string scope(""); // Needs to be removed in the futur + // There is a possibility to optimize here. count the types .... + asn1::choice *type = &m_choice; + asn1::node *ident = m_choice.identifier(); + asn1::node::iterator lit; + std::list choice_nodes; + + asn1::node *params = ident->parameters(); + + m_os<<"bool "<begin(); + for (; lit != type->end() ; lit++) + { + std::string strtype; + asn1::field *f = dynamic_cast(*lit); + asn1::typenode *attr_type = f->get_type(); + if (attr_type == NULL) + continue; + asn1::type type_id = attr_type->type_id(); + std::list refs; + + m_gencpp.reference_chaine(attr_type->as_typeref(),refs); + + if (type_id() == asn1::type::ASN1_EXTENSIBLE) + { + m_os<<"\t\t// Extensible marker"< 0) + && ! (refs.back()->tagged() ) + && attr_type + && (!attr_type->tagged() ) + && (refs.back()->tag().m_value < 0) + && (type_id() == asn1::type::ASN1_REFERENCE) ) + { + choice_nodes.push_back(f); + } else + { + asn1::node::tag_type tg ; + m_os<<"\tcase "<cpp_name()<<":\n"; + + // In ber mode, also check tag (for CSTA ...) + if (m_gencpp.with_ber() && attr_type->tagged() ) + { + tg = attr_type->tag(); + m_os<<"\tif ( tag() == MAKE_LONG_TAG("; + m_os<tagged()) + { + asn1::node::tag_type tg = attr_type->tag(); + m_os<<"\t\t"; + if (attr_type->type_id()() == asn1::type::ASN1_REFERENCE) + { + asn1::typeref *tref = dynamic_cast(attr_type); + asn1::node *rt = m_gencpp.resolver().resolve(*tref); + if (tref->is_simple() + || (rt && rt->type_node())) + { + m_gencpp.gen_composite_attribute_ref(m_os,scope,f,params); + m_os<<" instance( asn1::tag("; + m_os<cpp_name(); + m_os<<" instance( asn1::tag("; + m_os<cpp_name()<<"(); /*untg 2*/\n"; + } + m_os<<"\t\treturn true; \n"; + // In ber mode, also check tag (for CSTA ...) + if (m_gencpp.with_ber() && attr_type->tagged() ) + { + asn1::node::tag_type tg = attr_type->tag(); + m_os<<"\t} else {"<identifier_name()<<" tag=%ld expected "; + m_os<lst; + m_gencpp.reference_chaine(attr_type->as_typeref(),lst); + + if ((lst.size() > 0) && lst.back() != NULL) + { + if (lst.back()->tag().m_value >= 0) + { + asn1::node::tag_type tg = lst.back()->tag(); + m_os<<"\t}"<(*lit); + asn1::typenode *attribute_type = f->get_type(); + m_os<<"\tm_choice = new "; + if (m_gencpp.type2cppstring(attribute_type,strtype) ) + { + m_os<cpp_name()<<"(m_tag.get_tag(),m_tag);\n"; + + m_os<<"\tif (static_cast(m_choice)->create_object())\n"; + m_os<<"\t{"<cpp_name()<<";\n"; + m_os<<"\t\treturn true;"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_construct.h" +#include "cgcpph_enumerated.h" + +static +char lop_substitute(char c) +{ + return (c == ':')?'_':c; +} + + +cgcpph_enumerated::cgcpph_enumerated(generate_codec_cpp &g,std::ostream &os,asn1::enumerated &s) + : cgh_construct(g,os,s) , m_enumerated(s) +{ +} + +cgcpph_enumerated::~cgcpph_enumerated() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cgcpph_enumerated::generate(const std::string &scope) +{ + asn1::node *ident = m_enumerated.identifier(); + + if (m_gencpp.with_source_comment()) + m_os<<"//\n// cgcpph_enumerated helper launched\n//"<type_id()() == asn1::type::ASN1_ENUMERATED ); + + m_os<<"#if 1 /* ASN1_PRINTF*/"<begin(); + for (; it != type->end(); it++) + { + asn1::value *num = (*it)->value(); + if (it != type->begin() ) + { + m_os<<"\t,\""<<(*it)->cpp_name()<<"\"\n"; + } else + { + m_os<<"\t \""<<(*it)->cpp_name()<<"\"\n"; + } + + } + m_os<<"};\n"<cpp_name()<<")\n"; + m_os<<"\t\tos<<\""<<(*it)->cpp_name()<<"\";\n"; + } else + { + m_os<<"\tif (s.m_Prim == "<cpp_name()<<")\n"; + m_os<<"\t\tos<<\""<<(*it)->cpp_name()<<"\";\n"; + } + + } + m_os<<"\t\tos<<\" (\"<cpp_name() ); + std::string structName( ns + "::" + m_enumerated.identifier_cpp_name() ); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name() ); + std::string structName ( ns + "::" + m_enumerated.identifier_cpp_name()); + + //m_gencpp.type2cppstring(&m_enumerated,structName,scope); + fname = structName; + + if (m_gencpp.with_codec()) + { + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<is_extensible()) continue; + cpp<<"\t\tcase "<cpp_name()<<": "; + cpp<<"c.put_field(\""<<(*it)->cpp_name()<<"\","<<(*it)->cpp_name().size()<<"); break;\n"; + } + cpp<<"\t};\n"; + /**/ + cpp<<"}\n"; + cpp<<"\ntemplate<>\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_import.h" + + +cgcpph_import::cgcpph_import(generate_codec_cpp &g,std::ostream &os,asn1::import &s) + : m_Gen(g), generator_helper(os) , m_import(s) , m_log(g.logger()) +{ +} + +cgcpph_import::~cgcpph_import() +{ +} + + +/** Helper functions + * + * + */ +void cgcpph_import::generate() +{ + asn1::node::iterator items,end; + asn1::node::iterator it = m_import.begin(); + + m_os<<"// cgcpph_import helper launched "; + + // GEN_LOG_DEBUG("cgcpph_import::generate node=%s\n",type->identifier_cpp_name().c_str()); + m_os<<"\n#if 0\n"; + // May be just include each module ... + + items = m_import.begin(); + end = m_import.end(); + // Loop over items and check if OPERATION is imported + for ( items = m_import.begin() + ; items != end + ; ++items) + { + //os <<"//#include \""<<(*it)->identifier_cpp_name()<<"/"<<(*items)->cpp_name()<<".h\" /*item "<<(*items)->name()<<"*/\n"; + if (std::string("OPERATION").compare((*items)->name()) == 0 ) + { + m_os<<"#include \"rtasn1/asn1_rose.h\"\n"; + } + } + m_os<<"#include \""<cpp_name()<<".h\"\n"; + + m_os<<"#endif\n"; +} + +// +void cgcpph_import::gen_printf(const std::string &scope) +{ +} + +// generate codec part +void cgcpph_import::generate_per() +{ +} + +// +void cgcpph_import::generate_ber() +{ +} + +// +void cgcpph_import::generate_oer() +{ + // +} + +// +void cgcpph_import::generate_jer() +{ +} + +// +void cgcpph_import::generate_xer() +{ +} + diff --git a/libgen/cpp/cgcpph_import.h b/libgen/cpp/cgcpph_import.h new file mode 100644 index 0000000..9cf0f94 --- /dev/null +++ b/libgen/cpp/cgcpph_import.h @@ -0,0 +1,45 @@ +#ifndef CGCPPH_IMPORT_H +#define CGCPPH_IMPORT_H + + +/** + * + */ +class cgcpph_import : public generator_helper +{ + protected: + cgcpph_import(const cgcpph_import &s) : generator_helper(s.m_os) + , m_Gen(s.m_Gen) + , m_import(s.m_import) + , m_log(s.m_log) + {} + public: + cgcpph_import(generate_codec_cpp &g,std::ostream &os,asn1::import &s) ; + + ~cgcpph_import(); + + // Helper functions + virtual void generate() ; + + void gen_printf(const std::string &scope); + // generate codec part + virtual void generate_per() ; + // + virtual void generate_ber() ; + // + virtual void generate_oer() ; + // + virtual void generate_jer() ; + // + virtual void generate_xer() ; + + // loop over the attributes of SEQUENCE or CHOICE + // and check if there are some type of SEQUENCE or CHOICE + // launch generation for these types first. + protected: + std::fstream &m_log; + generate_codec_cpp &m_Gen; + asn1::import &m_import; +}; + +#endif diff --git a/libgen/cpp/cgcpph_integer.cpp b/libgen/cpp/cgcpph_integer.cpp new file mode 100644 index 0000000..dc893a9 --- /dev/null +++ b/libgen/cpp/cgcpph_integer.cpp @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_construct.h" +#include "cgcpph_integer.h" + + +cgcpph_integer::cgcpph_integer(generate_codec_cpp &g,std::ostream &os,asn1::integer &s) + : cgh_construct(g,os,s) + , m_integer(s) +{ +} + +cgcpph_integer::~cgcpph_integer() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cgcpph_integer::generate() +{ + m_os<<"// cgcpph_integer helper launched "<name()< 0) + { + m_os<<"bool "<cpp_name()); + std::string structName(ns + "::" +m_integer.identifier_cpp_name()); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + //m_Gen.gen_template_signature(m_os,type); + hpp<<"\n// construct type "<\n"; + hpp<<"void codecPER::encode(streams::per &c,const "<\n"; + hpp<<"int codecPER::decode(streams::per &c,"<\n"; + cpp<<"void codecPER::encode(asn1::streams::per &c,const "<\n"; + cpp<<"int codecPER::decode(asn1::streams::per &c,"<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + if (m_integer.is_unsigned()) + { + m_os<<"\t\tUInt64 tmp;\n"; + } else + { + m_os<<"\t\tINTEGER tmp;\n"; + } + m_os<<"\t\tint rest = tmp.decode(ctx);\n"; + m_os<<"\t\tthis->get_value() = tmp.get_value();\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + } + /* Handle codec aspect */ + if (m_gencpp.with_codec()) + { + std::string ns(m_gencpp.get_module()->cpp_name()); + std::string structName(ns + "::" +m_c.identifier()->cpp_name()); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + //m_Gen.gen_template_signature(m_os,type); + hpp<<"\n// construct type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name()); + std::string structName(ns + "::" +m_integer.identifier_cpp_name()); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + //m_Gen.gen_template_signature(m_os,type); + hpp<<"\n// construct type "<\n"; + hpp<<"void codecOER::encode(streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name()); + std::string structName(ns + "::" +m_integer.identifier_cpp_name()); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + //m_Gen.gen_template_signature(m_os,type); + hpp<<"\n// construct type "<\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "asn1_recursive_visitor.h" +#include "cgh_object.h" +#include "cgcpph_object.h" +#include "adt/asn1_node.h" +#include "adt/asn1_constraint.h" +#include "asn1_visitor.h" + +/** + * Generate Missing Objects before instanciating them in the set. + */ +class missing_object : public asn1::recursive_visitor +{ + public: + missing_object(std::ostream &os,cgcpph_object &h,generate_codec_cpp &g) + : m_os(os), m_cgh(h) , m_Gen(g), m_count(0) + {} + + bool visit_celt_value(asn1::celt_value *cv) + { + asn1::node::iterator ref = std::find_if(m_Gen.get_module()->begin(), + m_Gen.get_module()->end(), + asn1::find_node(cv->value()->name())); + if (ref != m_Gen.get_module()->end()) + { + asn1::node *ntype = *ref; + if (ntype->parameters()) + { + std::cerr<<"generate_codec_cpp::gen_const "<name()<<" has parameters"<name()<<" has parameters NO GEN YET"<as_assignment()); + } + } + return true; + } + + long m_count; + std::ostream &m_os; + cgcpph_object &m_cgh; + generate_codec_cpp &m_Gen; +}; + +/** + * Generate Object sets in class: + */ +class gen_objectset : public asn1::recursive_visitor +{ + public: + gen_objectset( std::ostream &os + , const std::string field + , const std::string sname + , const long nbelems + , cgcpph_object &h + , generate_codec_cpp &g) + : m_os(os), m_cgh(h) , m_Gen(g),m_count(0),m_struct_name(sname),m_nb_elems(nbelems) + {} + + bool visit_celt_value(asn1::celt_value *cv) + { + asn1::node::iterator ref = std::find_if(m_Gen.get_module()->begin(), + m_Gen.get_module()->end(), + asn1::find_node(cv->value()->name())); + if (ref != m_Gen.get_module()->end()) + { + asn1::node *ntype = *ref; + if (ntype->parameters()) + { + std::cerr<<"generate_codec_cpp::gen_const "<name()<<" has parameters"<name()<<" has parameters NO GEN YET"<cpp_name()<<"()}\n"; + } + } + return true; + } + /** + * + */ + bool traverse_objectset(asn1::objectset *S) + { + bool ret = asn1::recursive_visitor::traverse_objectset(S); + if (m_count) + { + m_os<<",{NULL,NULL}"; + }else + { + m_os<<"{NULL,NULL} "; + } + return ret; + } + + bool traverse_valueset(asn1::valueset *S) + { + bool ret = asn1::recursive_visitor::traverse_valueset(S); + if (m_count) + { + m_os<<",{NULL,NULL}"; + }else + { + m_os<<"{NULL,NULL} "; + } + return ret; + } + long m_count; + long m_nb_elems; + std::string m_field; + std::string m_struct_name; + std::ostream &m_os; + cgcpph_object &m_cgh; + generate_codec_cpp &m_Gen; +}; + +/** +* INTERNAL HELPER CLASS +*/ +struct g_objectset +{ + g_objectset(std::ostream &os,cgcpph_object &h,generate_codec_cpp &g) + : m_os(os) , m_cgh(h) , m_Gen(g) + { + } + + void operator ()(asn1::node *n) + { + if (n->type_id()() == asn1::type::ASN1_CLASSFIELD_OSF ) + { + asn1::typeref *tref = dynamic_cast(n)->get_typeref(); + std::string name = n->cpp_name().substr(1); + asn1::node *ident = m_Gen.resolver().resolve(*tref); + // Get field Loop over union ... + m_os<<"// OBJECTSET "<name()<name()) ) != NULL ) + { + std::string sname = m_cgh.get_object().identifier()->cpp_name()+"_"+name; + m_os<<"// HAVE VALUES "<name()<<" object set is element_set_spect "<name().compare(ident->get_parent()->name())) + { + m_os<<"struct "; + //<get_parent()->cpp_name()<<"::"; + m_os<cpp_name()<<"Set "; + m_os<cpp_name()<<"_"<name(),sname,mo.m_count,m_cgh,m_Gen); + gset.traverse_objectset(type); + m_os<<"};\n"; + } + } + } + std::ostream &m_os; + cgcpph_object &m_cgh; + generate_codec_cpp &m_Gen; +}; + + +/* +* CLASS chgpph_object IMPLEMENTATION +*/ + +cgcpph_object::cgcpph_object( generate_codec_cpp &g + , std::ostream &os + , asn1::object &s + , asn1::classdef &cdef) +: m_Gen(g) +, cgh_object(g,os,s,cdef) +, m_log(g.logger()) +{ +} + +cgcpph_object::~cgcpph_object() +{ +} + + +/** Helper functions +* generate object template code +*/ +void cgcpph_object::generate() +{ + asn1::node *n = m_object.identifier(); + asn1::node *type = &m_object; + asn1::node *params = NULL; + std::string structName; + + m_os<<"\n//\n// cgcpph_object helper launched "<name()<<"\n"; + if (!m_Gen.get_module()->name().compare("Remote-Operations-Useful-Definitions")) + { + m_os<<"// Dont generate anything For this module\n"; + return; + } + gen_objectset(); + // Generate template_specialisation + if (m_classdef.get_parent() == m_Gen.get_module()) + { + m_os<<"template <>\n"; + m_os<::"<cpp_name()<<" {\n"; + gen_ctors() ; + m_os<<"} // close namespace\n"; // Close template namespace + // Reopen current namespace + m_os<<"namespace "<cpp_name()<<" {\n"; +#if defined(_WINDOWS) + // Solve link issue in cstav1 + m_os<<"static "<cpp_name()<<" "<cpp_name()<<"_instance;\n"; +#endif + } + + m_os<<"\n"; + +} + +void +cgcpph_object::gen_ctors() +{ + asn1::node *n = m_object.identifier(); + m_os<<"template <>\n"; + m_os<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<">::"<cpp_name()<<"()\n"; + m_os<<"{\n"; // Open function content + if (m_Gen.with_source_debug()) + m_os<<"\tASN1_BER_LOG_DEBUG(\"ctor::"<name()<<"\");\n"; + gen_ctor_set_ftvf(); + m_os<<"}\n"; // Close function content + // Add copy ctor even if private + m_os<<"template <>\n"; + m_os<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<">::"<cpp_name()<<"(const "; + m_os<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<"> &o )\n"; + m_os<<"{\n"; // Open function content + if (m_Gen.with_source_debug()) + m_os<<"\tASN1_BER_LOG_DEBUG(\"cpctor::"<name()<<"\");\n"; + gen_ctor_set_ftvf(); + m_os<<"}\n"; // Close function content + // Add Create static function to check if yes or not + +} + +// +void cgcpph_object::gen_printf(const std::string &scope) +{ +} + +// generate codec part +void cgcpph_object::generate_per() +{ + std::string scope; + // + m_os< +{ + public: + ftvf_init(std::ostream &os,const std::string &s) : m_s(s),m_os(os) {}; + + void visit_integer(asn1::integer *_int) + { + //TODO This is wrong code + m_os<<"\t"<cpp_name(); + m_os<<")));\n"; + } + + void visit_object_identifier(asn1::object_identifier *_oid) + { + asn1::object_identifier::arcsType v; + _oid->arcs(v); + m_os<<"\t"<print_strhex(m_os,v); + m_os<<") ) ;\n"; + } + + void visit_choice(asn1::choice *type) + { + asn1::value *val = type->value(); + m_os<<"\t// FTVF CHOICE "<cpp_name()<<" "<cpp_name()<m_node->type_id()()) + { + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + asn1::object_identifier::arcsType v; + asn1::object_identifier *_oid = val->m_node->as_object_identifier(); + _oid->arcs(v); + m_os<<"\t"<cpp_name(); + m_os<<" ( OBJECT_IDENTIFIER("<print_strhex(m_os,v); + m_os<<") ) ;\n"; + } + break; + case asn1::type::ASN1_INTEGER: + { + m_os<<"\t"<cpp_name(); + m_os<<"( INTEGER("; + m_os<cpp_name(); + m_os<<") );\n"; + } + default: + ; + } + } + // Default unhandled case + void visit_node(asn1::node *type) + { + m_os<<"\t// FTVF "<cpp_name()<<" ID="<type_id()()<type_id()() == asn1::type::ASN1_CLASSFIELD_OSF ) + { + asn1::objectset *type = NULL; + if ( (type = m_object.get_objectset((*fit)->name()) ) != NULL ) + { + std::string s = (*fit)->name(); + s[0] = '_'; + m_os<<"\t// SET OBJECT SET "<type_id()() == asn1::type::ASN1_CLASSFIELD_FTVF ) + { + asn1::valuetype *type = NULL; + if ( (type = m_object.get_ftvf((*fit)->name()) ) != NULL ) + { + std::string s = (*fit)->name(); + s[0] = '_'; + ftvf_init vint(m_os,s); + vint.visit(type); + } + } + } +} + + +/** + * + */ +void cgcpph_object::gen_objectset() +{ + std::for_each(m_classdef.begin() + , m_classdef.end() + , g_objectset(m_os,*this,m_Gen)); +} + +/* + * vim: et sw=2 ts=2 list: + */ diff --git a/libgen/cpp/cgcpph_object.h b/libgen/cpp/cgcpph_object.h new file mode 100644 index 0000000..b7cef09 --- /dev/null +++ b/libgen/cpp/cgcpph_object.h @@ -0,0 +1,63 @@ +#ifndef CGCPPH_OBJECT_H +#define CGCPPH_OBJECT_H + + +/** + * + */ +class cgcpph_object : public cgh_object +{ + protected: + cgcpph_object(const cgcpph_object &s) : cgh_object(s.m_Gencpp + , s.m_os + , s.m_object + , s.m_classdef + ) + , m_Gen(s.m_Gen) + // , m_object(s.m_object) + // , m_classdef(s.m_classdef) + , m_log(s.m_log) + {} + public: + cgcpph_object( generate_codec_cpp &g + , std::ostream &os + , asn1::object &s + , asn1::classdef &c + ) ; + + ~cgcpph_object(); + + // Helper functions + virtual void generate() ; + + void gen_printf(const std::string &scope); + // generate codec part + virtual void generate_per() ; + // + virtual void generate_ber() ; + // + virtual void generate_oer() ; + // + virtual void generate_jer() ; + // + virtual void generate_xer() ; + + // loop over the attributes of SEQUENCE or CHOICE + // and check if there are some type of SEQUENCE or CHOICE + // launch generation for these types first. + protected: + //void gen_template_args(bool with_scope); + // + void gen_ctor_set_ftvf(); + + void gen_ctors(); + /** + * CLASS might have object sets + */ + void gen_objectset(); + protected: + std::fstream &m_log; + generate_codec_cpp &m_Gen; +}; + +#endif diff --git a/libgen/cpp/cgcpph_objectset.cpp b/libgen/cpp/cgcpph_objectset.cpp new file mode 100644 index 0000000..6ff590a --- /dev/null +++ b/libgen/cpp/cgcpph_objectset.cpp @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_object.h" +#include "cgcpph_objectset.h" + + +/** + * INTERNAL HELPER CLASS + */ +struct g_object +{ + g_object(std::ostream &os,cgcpph_objectset &h) + : m_os(os) , m_cgh(h) + { + } + + void operator ()(asn1::node *n) + { + if (n->type_id()() == asn1::type::ASN1_CLASSFIELD_OSF ) + { + // Get field Loop over union ... + asn1::node *type = NULL; + if ( (type = m_cgh.get_object().get_field(n->name()) ) != NULL ) + { + m_os<<"// HAVE VALUES "<name()<name()<<"\n"; + if (!m_Gen.get_module()->name().compare("Remote-Operations-Useful-Definitions")) + { + m_os<<"// Dont generate anything For this module\n"; + return; + } + gen_objectset(); + // Generate template_specialisation + if (m_classdef.get_parent() == m_Gen.get_module()) + { + m_os<<"template <>\n"; + m_os<::"<cpp_name()<<" {\n"; + m_os<<"template <>\n"; + m_os<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<">::"<cpp_name()<<"()\n"; + m_os<<"{\n"; // Open function content + m_os<<"\tASN1_BER_LOG_DEBUG(\"ctor::"<name()<<"\");\n"; + gen_ctor_set_ftvf(); + m_os<<"}\n"; // Close function content + + m_os<<"} // close namespace\n"; // Close template namespace + // Reopen current namespace + m_os<<"namespace "<cpp_name()<<" {\n"; + } + + m_os<<"\n"; + +} + +// +void cgcpph_objectset::gen_printf(const std::string &scope) +{ +} + + +/** + * + */ +void cgcpph_objectset::gen_objectset() +{ + std::for_each(m_classdef.begin() + , m_classdef.end() + , g_objectset(m_os,*this)); +} diff --git a/libgen/cpp/cgcpph_objectset.h b/libgen/cpp/cgcpph_objectset.h new file mode 100644 index 0000000..deb5daf --- /dev/null +++ b/libgen/cpp/cgcpph_objectset.h @@ -0,0 +1,39 @@ +#ifndef CGCPPH_OBJECTSET_H +#define CGCPPH_OBJECTSET_H + + +/** + * + */ +class cgcppg_objectset : public cgh_object +{ + protected: + cgcppg_objectset(const cgcppg_objectset &s) : cgh_object(s.m_Gencpp + , s.m_os + , s.m_object + , s.m_classdef + ) + , m_Gen(s.m_Gen) + , m_log(s.m_log) + {} + public: + cgcppg_objectset( generate_codec_cpp &g + , std::ostream &os + , asn1::object &s + , asn1::classdef &c + ) ; + + ~cgcppg_objectset(); + + // Helper functions + virtual void generate() ; + + void gen_printf(const std::string &scope); + // generate codec part + + protected: + std::fstream &m_log; + generate_codec_cpp &m_Gen; +}; + +#endif diff --git a/libgen/cpp/cgcpph_octetstring.cpp b/libgen/cpp/cgcpph_octetstring.cpp new file mode 100644 index 0000000..aa49313 --- /dev/null +++ b/libgen/cpp/cgcpph_octetstring.cpp @@ -0,0 +1,221 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_primitive.h" +#include "cgcpph_octetstring.h" + + +cgcpph_octet_string::cgcpph_octet_string(generate_codec_cpp &g,std::ostream &os,asn1::octet_string &s) + : cgcpph_primitive(g,os,s) + , m_octet_string(s) +{ +} + +cgcpph_octet_string::~cgcpph_octet_string() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cgcpph_octet_string::generate_ctors() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_octet_string helper launched "<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + m_os<<"\t\tOCTET_STRING tmp;\n"; + m_os<<"\t\tint rest = tmp.decode(ctx);\n"; + m_os<<"\t\tthis->get_value() = tmp.get_value();\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + } + /* Handler BER Codec */ + if (m_gencpp.with_codec()) + { + std::string ns(m_gencpp.get_module()->cpp_name()); + std::string structName(ns + "::" + m_octet_string.identifier_cpp_name()); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name()); + std::string structName(ns + "::" + m_octet_string.identifier_cpp_name()); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecOER::encode(streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name()); + std::string structName(ns + "::" + m_octet_string.identifier_cpp_name()); + if (m_gencpp.with_codec()) + { + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_construct.h" +#include "cgcpph_oid.h" + + +cgcpph_oid::cgcpph_oid( generate_codec_cpp &g + , std::ostream &os + , asn1::object_identifier &s) + : cgh_construct(g,os,s) , m_oid(s) +{ +} + +cgcpph_oid::~cgcpph_oid() +{ +} + + +/** Helper functions + * + * + */ +void cgcpph_oid::generate() +{ + + GEN_LOG_DEBUG("cgcpph_oid::generate node=%s\n",m_oid.identifier_cpp_name().c_str()); + // May be just include each module ... + // Handles the call with condition of the different generate_xxx + cgcpp_helper::generate(); +} + +// +void cgcpph_oid::generate_ctors() +{ + std::string structName = m_oid.identifier_cpp_name(); + + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_oid helper launched \n"; + + // With tag + m_os<<"\n"<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + m_os<<"\t\tOBJECT_IDENTIFIER tmp;\n"; + m_os<<"\t\tint rest = tmp.decode(ctx);\n"; + m_os<<"\t\tthis->get_value() = tmp;\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + // + if (m_gencpp.with_codec()) + { + std::string ns (m_gencpp.get_module()->cpp_name()); + std::string structName ( ns + "::" +m_oid.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name()); + std::string structName ( ns + "::" +m_oid.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + + hpp<<"\ntemplate<>\n"; + hpp<<"void codecOER::encode(streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name()); + std::string structName ( ns + "::" +m_oid.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_primitive.h" + + +cgcpph_primitive::cgcpph_primitive( generate_codec_cpp &g + , std::ostream &os + , asn1::primitive &s) + : cgcpp_helper(g,os) , m_primitive(s) +{ + m_structName = m_primitive.identifier_cpp_name(); +} + +cgcpph_primitive::~cgcpph_primitive() +{ +} + + +/** Helper functions + * + * + */ +void cgcpph_primitive::generate() +{ + + GEN_LOG_DEBUG("cgcpph_primitive::generate node=%s\n",m_primitive.identifier_cpp_name().c_str()); + cgcpp_helper::generate(); +} + + +/** + * + */ +void +cgcpph_primitive::generate_descriptor() +{ + std::string cn(m_primitive.identifier_cpp_name()); + unsigned int _count = 0; + + m_os<<"static asn1::tag TAGS_"<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + //m_os<<"\t\tBOOLEAN tmp;\n"; + m_os<<"\t\t"<get_value() = tmp;\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + } + if (m_gencpp.with_codec()) + { + std::string ns(m_gencpp.get_module()->cpp_name()); + std::string structName(ns + "::" + m_primitive.identifier()->cpp_name()); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name()); + std::string structName(ns + "::" + m_primitive.identifier()->cpp_name()); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_primitive.h" +#include "cgcpph_real.h" + + +cgcpph_real::cgcpph_real(generate_codec_cpp &g,std::ostream &os,asn1::real &s) + : cgcpph_primitive(g,os,s) + , m_real(s) +{ +} + +cgcpph_real::~cgcpph_real() +{ +} + + +// +void cgcpph_real::generate_ctors() +{ + if (m_gencpp.with_source_comment()) + { + m_os<<"// cgcpph_real ctors helper launched "; + m_os<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + m_os<<"\t\tBOOLEAN tmp;\n"; + m_os<<"\t\tint rest = tmp.decode(ctx);\n"; + m_os<<"\t\tthis->get_value() = tmp.get_value();\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + } +} + +// +void cgcpph_real::generate_oer() +{ + // +} + +// +void cgcpph_real::generate_jer() +{ +} + +// +void cgcpph_real::generate_xer() +{ +} + diff --git a/libgen/cpp/cgcpph_real.h b/libgen/cpp/cgcpph_real.h new file mode 100644 index 0000000..8ca7aa3 --- /dev/null +++ b/libgen/cpp/cgcpph_real.h @@ -0,0 +1,41 @@ +#ifndef CGCPPH_REAL_H +#define CGCPPH_REAL_H + + +/** + * + */ +class cgcpph_real : public cgcpph_primitive +{ + protected: + cgcpph_real(const cgcpph_real &s) : cgcpph_primitive(s) + , m_real(s.m_real) + {} + public: + cgcpph_real(generate_codec_cpp &g,std::ostream &os,asn1::real &s) ; + + ~cgcpph_real(); + + // generate codec part + virtual void generate_per() ; + // + virtual void generate_ber() ; + // + virtual void generate_oer() ; + // + virtual void generate_jer() ; + // + virtual void generate_xer() ; + protected: + virtual void generate_ctors(); + + virtual void generate_operators(); + + void gen_equal(); + + virtual void generate_printf(); + protected: + asn1::real &m_real; +}; + +#endif diff --git a/libgen/cpp/cgcpph_sequence.cpp b/libgen/cpp/cgcpph_sequence.cpp new file mode 100644 index 0000000..e067eec --- /dev/null +++ b/libgen/cpp/cgcpph_sequence.cpp @@ -0,0 +1,598 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "asn1_visitor.h" +#include "cgh_construct.h" +#include "cgcpph_sequence.h" + + +cgcpph_sequence::cgcpph_sequence(generate_codec_cpp &g,std::ostream &os,asn1::sequence &s) + : m_seq(s) + , cgh_construct(g,os,s) +{ +} + +cgcpph_sequence::~cgcpph_sequence() +{ +} + + +// Helper functions +void cgcpph_sequence::generate(const std::string &scope) +{ + bool priv = m_seq.is_private() ; + + if (m_gencpp.with_source_comment()) + { + m_os<<"\n//\n// cgcpph_sequence helper launched "; + m_os<<"\n//\n"; + } + /* Issue with parameterized types */ + + cgcpp_helper::generate(); + + if (m_gencpp.with_ber()) + gen_data_length(); + + m_os<parameters()) + return ; + cgh_construct::gen_desc_seqset(); +} + +/** + * + */ +void cgcpph_sequence::generate_ctors() +{ + std::string scope(""); + bool priv( m_seq.is_private() ); + gen_ctor(scope,priv); + + gen_clone(scope,priv); +} + +/** + * generate codec part + */ +void cgcpph_sequence::generate_per() +{ +} + +// +void cgcpph_sequence::generate_ber() +{ + bool priv( m_seq.is_private() ); + + gen_nencode("",priv); + gen_ndecode("",priv); + + if (m_gencpp.with_codec()) + { + std::string ns ( m_gencpp.get_module()->cpp_name() ) ; + std::string structName ( ns + "::" +m_seq.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// sequence type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<flags().is_optional() && (! f->flags().is_default())) + { + cpp<<"\tdecode(c,_t."<cpp_name()<<".get());\n"; + } else + { + cpp<<"\tdecode(c,_t."<cpp_name()<<");\n"; + } + //cpp<<"\t}\n"; + } + } + } + cpp<<"\tif ( c.decode_sequence_epilogue(_t) != asn1::ok)\n"; + cpp<<"\t\treturn asn1::wrong_type;\n"; + cpp<<"\treturn asn1::ok;\n"; + cpp<<"}\n"; +#endif + + /**/ + } +} + +// +void cgcpph_sequence::generate_oer() +{ +} + +// +void cgcpph_sequence::generate_xer() +{ +} + + +/** +* Generate ctor code +*/ +void +cgcpph_sequence::gen_ctor(const std::string &scope,bool priv) +{ + asn1::node::iterator lit = m_seq.begin(); + std::string structName; + + m_gencpp.gen_template_signature(m_os,&m_seq); + + if (!priv) + { + structName = m_seq.identifier_cpp_name(); + } else + { + structName = m_seq.cpp_name(); + } + + m_os<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + m_os<<" , "; + if (attr_type->meta_id()() == asn1::meta::OBJECT) + { + m_os<cpp_name()<<"(NULL)"; + } + //std::cout<<"1 and HERE "<<(*it)->name()<flags().is_default() ) + { + gen_ctor_init(f); + } else + { + switch(attr_type->type_id()()) + { + case asn1::type::ASN1_INTEGER: + if ( attr_type && attr_type->tagged()) + { // Ok tagged value + if(attr_type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT) + { + asn1::node::tag_type lt = attr_type->tag(); + m_os<<(*it)->cpp_name()<<"(asn1::tag("<cpp_name()<<"(/*Explicit tag*/)"; + } else + m_os<<(*it)->cpp_name()<<"()"; + //os<<(*it)->cpp_name()<<"(asn1::prim::types::Integer(0))"; + break; + case asn1::type::ASN1_BOOLEAN: + m_os<<(*it)->cpp_name()<<"()"; + //os<<(*it)->cpp_name()<<"(asn1::prim::types::Boolean(false))"; + break; + default: + { + if ( attr_type && attr_type->tagged()) + { // Ok tagged value + if(attr_type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT) + { + asn1::node::tag_type lt = attr_type->tag(); + m_os<<(*it)->cpp_name()<<"(asn1::tag("<cpp_name()<<"(/*Explicit tag*/)"; + } else + m_os<<(*it)->cpp_name()<<"(/*def no tag*/)"; + } + + } /* end switch */ + } + if ( (*it)->flags().is_optional() ) + { + m_os<<"/*optional*/"; + } + m_os<<"\n"; + } + + } /* end for */ + + m_os<<"{"<get_type(); + switch(attr_type->type_id()()) { + case asn1::type::ASN1_INTEGER: + { + asn1::value::ptr val = field->flags().m_value1; + if (! val.is_nul()) { + m_os<cpp_name()<<"(INTEGER("<< val->m_integer <<"))"; + } else + m_os<cpp_name()<<"()"; + } + break; +#if 0 + case asn1::type::ASN1_BOOLEAN: + if ( ! (field->flags().m_value1).is_nul() ) + { + switch ((field->flags().m_value1)->type) + { + case asn1::value::VT_TRUE: + m_os<cpp_name()<<"(BOOLEAN(asn1::prim::types::Boolean(true)))"; + break; + case asn1::value::VT_FALSE: + m_os<cpp_name()<<"(BOOLEAN(asn1::prim::types::Boolean(false)))"; + break; + default: + m_os<cpp_name()<<"(false) /*no*/"; + } + } else + m_os<cpp_name()<<"(false) /*m_value1 NULL "<name()<<"*/"; + break; +#endif + case asn1::type::ASN1_STRING: + case asn1::type::ASN1_STRING_IA5String: + case asn1::type::ASN1_STRING_PrintableString: + case asn1::type::ASN1_STRING_VisibleString: + case asn1::type::ASN1_STRING_ISO646String: + case asn1::type::ASN1_STRING_NumericString: + case asn1::type::ASN1_STRING_UniversalString: + case asn1::type::ASN1_STRING_BMPString: + case asn1::type::ASN1_STRING_UTF8String : + case asn1::type::ASN1_STRING_GeneralString: + case asn1::type::ASN1_STRING_GraphicString: + case asn1::type::ASN1_STRING_TeletexString: + case asn1::type::ASN1_STRING_T61String: + case asn1::type::ASN1_STRING_VideotexString: + case asn1::type::ASN1_STRING_ObjectDescriptor: + { + asn1::value::ptr val = field->flags().m_value1; + if (! val.is_nul()) { + m_os<cpp_name()<<"(asn1::prim::types::String("<< val->m_string <<"))"; + } else + m_os<cpp_name()<<"()"; + } + break; + + default: + { + if ( attr_type && attr_type->tagged()) + { // Ok tagged value + if(attr_type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT) + { + asn1::node::tag_type lt = attr_type->tag(); + m_os<cpp_name()<<"(asn1::tag("<cpp_name()<<"(/*Explicit tag*/)"; + } else + m_os<cpp_name()<<"(/*def no tag*/)"; + } + } +} +#if 1 + +/** + * Helper class to generate parameter + * initialization per attribute. + */ +class gco_pc +{ + public: + gco_pc(std::ostream &_os,generate_codec_cpp &_g,asn1::sequence &_c) + : m_os(_os) , m_log(_g.logger()), m_Gen(_g), m_seq(_c) + { + m_assign = m_seq.identifier()->as_assignment(); + assert( (m_assign != NULL ) && " m_assign should not be NULL for choice type"); + } + + void do_parameters(asn1::assignment *_a) + { + if ( ! _a) + return; + asn1::constructed *aplist = _a->parameters(); + if ( ! aplist) + return; + for ( asn1::node::iterator it = aplist->begin() ; + it != aplist->end(); ++it) + { + /* either value_set, object_set value, typeref */ + asn1::parameter *p = dynamic_cast(*it); + if (asn1::node *g = p->get_governor()) + { + asn1::typeref *objr = dynamic_cast(g); + if (objr) + { + m_os<<"\t// "<name()<<" "<name()<is_simple()) + { + m_os<<"\t"<cpp_name()<<" = t."<cpp_name()<<";"<name()<<" "<name()<as_assignment(); + asn1::sequence *type = &m_seq; + bool first = true; + + m_gencpp.gen_template_signature(m_os,&m_seq); + if (!priv) + { + name=type->identifier_cpp_name(); + m_os<<""<identifier_cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::"<identifier_cpp_name()<<"(const "; + m_os<identifier_cpp_name()<<" &t)"<<"\t"<cpp_name(); + m_os<<""<cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::"<cpp_name()<<"(const "; + m_os<cpp_name()<<" &t)"<<"\t"<begin(); it != type->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + + if (attr_type != NULL) + { + m_os<<" , "; + m_os<<(*it)->cpp_name()<<"(t."<<(*it)->cpp_name()<<")"; + if ( (*it)->flags().is_optional() ) { + m_os<<"/*optional*/"; + } + m_os<<"\n"; + } + + } + + m_os<<"{"<parameters() && ident->parameters()->size()>0) + { + gco_pc docp_params(m_os,m_gencpp,m_seq); + docp_params.do_parameters(m_seq.identifier()->as_assignment()); + } + m_os<<"}\n\n"; +} + +/** + * + */ +void +cgcpph_sequence::gen_clone(const std::string &scope,bool priv) +{ + std::string lscope; + asn1::node *type = &m_seq; + asn1::node *ident = m_seq.identifier(); + asn1::constructed *params = NULL; + std::string structName ; + + if (ident != NULL) + { + params = ident->parameters(); + } + + if (!priv) + { + structName = type->identifier_cpp_name(); + } else + { + structName = type->cpp_name(); + } + + m_os<<"\n"; + m_gencpp.gen_template_signature(m_os,type); + + m_os<<""<identifier_name(); + m_os<<"::clone "<identifier_name()<<" \");\n"; + } + m_os<<"\treturn new "<cpp_name(); + m_os<<"::"<parameters() && m_gencpp.is_template(type->parameters())) + { + m_gencpp.gen_template_params(m_os,type->parameters()); + } + m_os<<" &s"<<")\n{\n"; + m_os<<"\tstd::streamsize indent = os.precision() + 2;"<begin(); it != type->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + m_os<<"\t// Extensible marker"<cpp_name(); + structName = structName + "::" +m_seq.identifier()->cpp_name(); + + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// sequence type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + hpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_sequenceof.h" + + +cgcpph_sequenceof::cgcpph_sequenceof( generate_codec_cpp &g + , std::ostream &os + , asn1::sequence_of &s) + : cgcpp_helper(g,os) , m_seqof(s) +{ +} + +cgcpph_sequenceof::~cgcpph_sequenceof() +{ +} + +void cgcpph_sequenceof::generate() +{ + std::string structName = m_seqof.identifier()->cpp_name(); + + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_sequenceof helper launched \n"; + + GEN_LOG_DEBUG("cgcpph_sequenceof::generate node=%s\n",m_seqof.identifier_cpp_name().c_str()); + + gen_ctors(); + + gen_equal(); + + gen_printf(); + // Generate generators + cgcpp_helper::generate(); +} +// +void cgcpph_sequenceof::gen_ctors() +{ + asn1::node *ns = NULL; + asn1::typenode *eltype = m_seqof.get_eltype(); + std::string structName = m_seqof.identifier_cpp_name(); + std::string eltypeName; + if (m_gencpp.type_in_imports(eltype,&ns) ) + { + eltypeName = ns->cpp_name() + "::" + eltype->cpp_name(); + } else + eltypeName = eltype->cpp_name(); + + // With tag + m_os<<"\n"<(t)\n{\n}\n"; + m_os<<"\n// Copy Constructor "<(c)\n{\n}\n"; + //clone + m_os<identifier()->cpp_name(); + + // With tag + m_os<<"\n// comparaison "<cpp_name() + "::" + eltype->cpp_name(); + } else + eltypeName = eltype->cpp_name(); + + + m_os<<"\nstd::ostream & operator <<(std::ostream &os,const "; + m_os< &)s);\n"; + //m_os<<"\tos<<\"SEQUENCE OF PERSO TODO\";\n"; + m_os<<"\treturn os;\n"; + m_os<<"}\n"; +} + + + +void +cgcpph_sequenceof::generate_ber() +{ + std::string NameS = m_gencpp.get_module()->cpp_name(); + std::string eltypeName; + std::string structName( NameS + "::" +m_seqof.identifier()->cpp_name()); + asn1::typenode *eltype = m_seqof.get_eltype(); + asn1::node *ns = NULL; + + if (m_gencpp.type_in_imports(eltype,&ns) ) + { + eltypeName = ns->cpp_name() + "::" + eltype->cpp_name(); + } else + { + if (eltype->is_primitive()) + { + eltypeName = eltype->cpp_name(); + } else + eltypeName = m_gencpp.get_module()->cpp_name() +"::" + eltype->cpp_name(); + } + + if (m_gencpp.with_codec()) + { + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "< &)_t);\n"; + cpp<<"}\n"; + cpp<<"\ntemplate<>\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"< &)_t);\n"; + cpp<<"}\n"; + } + +} +// generate per +// +void +cgcpph_sequenceof::generate_per() +{ + std::string NameS = m_gencpp.get_module()->cpp_name(); + std::string eltypeName; + std::string structName( NameS + "::" +m_seqof.identifier()->cpp_name()); + asn1::typenode *eltype = m_seqof.get_eltype(); + asn1::node *ns = NULL; + + if (m_gencpp.type_in_imports(eltype,&ns) ) + { + eltypeName = ns->cpp_name() + "::" + eltype->cpp_name(); + } else + { + if (eltype->is_primitive()) + { + eltypeName = eltype->cpp_name(); + } else + eltypeName = m_gencpp.get_module()->cpp_name() +"::" + eltype->cpp_name(); + } + + + if (m_gencpp.with_codec()) + { + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecPER::encode(asn1::streams::per &c,const "<\n"; + hpp<<"int codecPER::decode(asn1::streams::per &c,"<\n"; + cpp<<"void codecPER::encode(asn1::streams::per &c,const "< &)_t);\n"; + cpp<<"\tc.put_char(\"] \",2);\n"; + cpp<<"}\n"; + cpp<<"\ntemplate<>\n"; + cpp<<"int codecPER::decode(asn1::streams::per &c,"< &)_t);\n"; + cpp<<"}\n"; + } + +} + +// Generate oer +// +void +cgcpph_sequenceof::generate_oer() +{ + std::string NameS = m_gencpp.get_module()->cpp_name(); + std::string eltypeName; + std::string structName( NameS + "::" +m_seqof.identifier()->cpp_name()); + asn1::typenode *eltype = m_seqof.get_eltype(); + asn1::node *ns = NULL; + + if (m_gencpp.type_in_imports(eltype,&ns) ) + { + eltypeName = ns->cpp_name() + "::" + eltype->cpp_name(); + } else + { + if (eltype->is_primitive()) + { + eltypeName = eltype->cpp_name(); + } else + eltypeName = m_gencpp.get_module()->cpp_name() +"::" + eltype->cpp_name(); + } + + + if (m_gencpp.with_codec()) + { + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(asn1::streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "< &)_t);\n"; + cpp<<"\tc.put_char(\"] \",2);\n"; + cpp<<"}\n"; + cpp<<"\ntemplate<>\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"< &)_t);\n"; + cpp<<"}\n"; + } + +} + + + + +// +void +cgcpph_sequenceof::generate_jer() +{ + std::string NameS = m_gencpp.get_module()->cpp_name(); + std::string eltypeName; + std::string structName( NameS + "::" +m_seqof.identifier()->cpp_name()); + asn1::typenode *eltype = m_seqof.get_eltype(); + asn1::node *ns = NULL; + + if (m_gencpp.type_in_imports(eltype,&ns) ) + { + eltypeName = ns->cpp_name() + "::" + eltype->cpp_name(); + } else + { + if (eltype->is_primitive()) + { + eltypeName = eltype->cpp_name(); + } else + eltypeName = m_gencpp.get_module()->cpp_name() +"::" + eltype->cpp_name(); + } + + + if (m_gencpp.with_codec()) + { + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(asn1::streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "< &)_t);\n"; + cpp<<"\tc.put_char(\"] \",2);\n"; + cpp<<"}\n"; + cpp<<"\ntemplate<>\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< &)_t);\n"; + cpp<<"}\n"; + } + +} diff --git a/libgen/cpp/cgcpph_sequenceof.h b/libgen/cpp/cgcpph_sequenceof.h new file mode 100644 index 0000000..bd68601 --- /dev/null +++ b/libgen/cpp/cgcpph_sequenceof.h @@ -0,0 +1,43 @@ +#ifndef CODE_GEN_CPP_HELPER_SEQOF_H +#define CODE_GEN_CPP_HELPER_SEQOF_H + +/** + * This class defines the interface that each + */ +class cgcpph_sequenceof : public cgcpp_helper +{ + public: + cgcpph_sequenceof(cgcpph_sequenceof &s) : cgcpp_helper(s.m_gencpp,s.m_os) + , m_seqof(s.m_seqof) + { } ; + cgcpph_sequenceof(generate_codec_cpp &g + , std::ostream &os + , asn1::sequence_of &s) ; + + virtual ~cgcpph_sequenceof(); + // generate entry point + virtual void generate() ; + // generate codec part + virtual void generate_per() ; + // + virtual void generate_ber(); + // + virtual void generate_oer() ; + // + virtual void generate_jer() ; + // + virtual void generate_xer() {}; + + // generate encoder + // generate decoder + // generate constructor + // generate + protected: + void gen_ctors(); + void gen_equal(); + void gen_printf(); + protected: + asn1::sequence_of &m_seqof; +}; + +#endif diff --git a/libgen/cpp/cgcpph_set.cpp b/libgen/cpp/cgcpph_set.cpp new file mode 100644 index 0000000..c2b617d --- /dev/null +++ b/libgen/cpp/cgcpph_set.cpp @@ -0,0 +1,254 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_construct.h" +#include "cgcpph_set.h" + +//#undef GEN_LOG_DEBUG +//#define GEN_LOG_DEBUG + +cgcpph_set::cgcpph_set(generate_codec_cpp &g,std::ostream &os,asn1::set &s) + : cgh_construct(g,os,s) + , m_set(s) +{ +} + +cgcpph_set::~cgcpph_set() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cgcpph_set::generate(const std::string &scope) +{ + asn1::node *n = m_set.identifier(); + asn1::node *params = NULL; + + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_set helper launched "<name()<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<")\n{\n"; + m_os<<"\tstd::streamsize indent = os.precision() + 2;"<begin() + ; it != type->end() + ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + m_os<<"\tos<<\"\"<<"; + m_gencpp.gen_composite_attribute_printf(m_os,scope,*f); + } + + } + m_os<<"\tos<cpp_name() ) ; + std::string structName ( ns + "::" +m_set.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// sequence type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<flags().is_optional() && (! f->flags().is_default())) + { + cpp<<"\tif ( ! _t."<cpp_name()<<".is_nul())\n\t{\n"; + cpp<<"\t\tencode(c,_t."<cpp_name()<<".get());\n\t}\n"; + } else + { + cpp<<"\tencode(c,_t."<cpp_name()<<");\n"; + } + } + } + + } /* end for */ + cpp<<"\tc.encode_sequence_epilogue(_t);\n"; + cpp<<"}\n"; + /* Implementation of decoding stream */ + cpp<<"\ntemplate<>\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<flags().is_optional() && (! f->flags().is_default())) + { + cpp<<"\tdecode(c,_t."<cpp_name()<<".get());\n"; + } else + { + cpp<<"\tdecode(c,_t."<cpp_name()<<");\n"; + } + //cpp<<"\t}\n"; + } + } + } + cpp<<"\tif ( c.decode_sequence_epilogue(_t) != asn1::ok)\n"; + cpp<<"\t\treturn asn1::wrong_type;\n"; + cpp<<"\treturn asn1::ok;\n"; + cpp<<"}\n"; + + + /**/ + } +} + +// +void cgcpph_set::generate_oer() +{ + // + if (m_gencpp.with_codec()) + { + std::string ns ( m_gencpp.get_module()->cpp_name() ) ; + std::string structName ( ns + "::" +m_set.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_setof.h" + + +cgcpph_setof::cgcpph_setof( generate_codec_cpp &g + , std::ostream &os + , asn1::set_of &s) + : cgcpp_helper(g,os) , m_setof(s) +{ +} + +cgcpph_setof::~cgcpph_setof() +{ +} + +void cgcpph_setof::generate() +{ + std::string structName = m_setof.identifier_cpp_name(); + m_os<<"//cgcpph_setof::generate "<cpp_name() + "::" + eltype->cpp_name(); + } else + eltypeName = eltype->cpp_name(); + + // With tag + m_os<<"\n"<(t)\n{\n}\n"; + + m_os<<"\n"<(t)\n\t"; + m_os<<"{\n}\n"; +#if 0 + m_os<<" asn1::types::container<"<(asn1::tag(asn1::types::UNIVERSAL,17)\n"; + m_os<<"{ this->m_.push_back(t);\n}\n"; +#endif + m_os<<"\n// Copy Constructor "<(c)\n{\n}\n"; + //clone + m_os<cpp_name() + "::" + eltype->cpp_name(); + } else + eltypeName = eltype->cpp_name(); + + + m_os<<"\nstd::ostream & operator <<(std::ostream &os,const "; + m_os< &)s);\n"; + m_os<<"\treturn os;\n"; + m_os<<"}\n"; +} + + + +void +cgcpph_setof::generate_ber() +{ + asn1::node *type = &m_setof; + std::string structName = m_setof.identifier()->cpp_name(); + // + if (m_setof.tagged()) + { + if ( m_gencpp.tag_mode(type) == asn1::node::tag_type::TM_EXPLICIT) + { + // + m_os<<"\t void "<cpp_name()); + std::string structName (ns + "::" +m_setof.identifier()->cpp_name()); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + cpp<<"// type set of "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name()); + std::string structName (ns + "::" +m_setof.identifier()->cpp_name()); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + cpp<<"// type set of "<\n"; + hpp<<"void asn1::codecOER::encode(asn1::streams::oer &c,const "<\n"; + hpp<<"int asn1::codecOER::decode(asn1::streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name()); + std::string structName (ns + "::" +m_setof.identifier()->cpp_name()); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + cpp<<"// type set of "<\n"; + hpp<<"void asn1::codecJER::encode(asn1::streams::jer &c,const "<\n"; + hpp<<"int asn1::codecJER::decode(asn1::streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_primitive.h" +#include "cgcpph_string.h" + + +cgcpph_string::cgcpph_string( generate_codec_cpp &g + , std::ostream &os + , asn1::primitive &s) + : cgcpph_primitive(g,os,s) , m_string(s) +{ +} + +cgcpph_string::~cgcpph_string() +{ +} + + + +/** + * + */ +void cgcpph_string::generate_operators() +{ + gen_equal(); +} +/** + * + */ +void cgcpph_string::generate_ctors() +{ + asn1::node *type = &m_string; + + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_string helper launched "; + + GEN_LOG_DEBUG("cgcpph_string::generate node=%s\n",m_string.identifier_cpp_name().c_str()); + + // With tag + m_os<<"\n"<cpp_name()<<"(t)\n{\n}\n"; + // + m_os<<"\n// Copy Constructor "<cpp_name() ); + std::string structName ( ns + "::" + m_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + // hpp content + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// string type "<\n"; + hpp<<"void asn1::codecPER::encode(asn1::streams::per &c,const "<\n"; + hpp<<"int asn1::codecPER::decode(asn1::streams::per &c,"<\n"; + cpp<<"void codecPER::encode(asn1::streams::per &c,const "<\n"; + cpp<<"int codecPER::decode(asn1::streams::per &c,"<tag().byte());\n"; + m_os<<"\tb[pos++] = tag().byte();\n"; + m_os<<"\tctx.nb_bits(16);\n"; + m_os<<"\tasn1::tag t("<tag().byte());\n"; + m_os<<"\tif (ctx.decode_tag(t))\n\t{\n"; + m_os<<"\t\t"<get_value() = tmp;\n"; + m_os<<"\t\treturn rest;\n"; + m_os<<"\t}\n"; + m_os<<"\treturn asn1::wrong_tag;\n"; + m_os<<"}\n"; + } + } + if (m_gencpp.with_codec()) + { + std::string ns( m_gencpp.get_module()->cpp_name() ); + std::string structName ( ns + "::" + m_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + // hpp content + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// string type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name() ); + std::string structName ( ns + "::" + m_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + // hpp content + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// string type "<\n"; + hpp<<"void asn1::codecOER::encode(asn1::streams::oer &c,const "<\n"; + hpp<<"int asn1::codecOER::decode(asn1::streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name() ); + std::string structName ( ns + "::" + m_string.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + // hpp content + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// string type "<\n"; + hpp<<"void asn1::codecJER::encode(asn1::streams::jer &c,const "<\n"; + hpp<<"int asn1::codecJER::decode(asn1::streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgcpph_typeref.h" + + +/** + * + * + */ +cgcpph_typeref::cgcpph_typeref(generate_codec_cpp &g,std::ostream &os,asn1::typeref &s) + : cgcpp_helper(g,os) + , m_typeref(s) + //, m_log(g.logger()) +{ +} + +/** + * + * + */ +cgcpph_typeref::~cgcpph_typeref() +{ +} + + +/** Helper functions + * + */ +void cgcpph_typeref::generate(const std::string &scope) +{ + asn1::node *n = m_typeref.identifier(); + asn1::node *type = &m_typeref; + + if (m_gencpp.with_source_comment()) + m_os<<"// cgcpph_typeref helper launched "<name()<tag().m_class<<","<<_node->tag().m_value; + if (m_gencpp.is_tag_explicit(*_node->as_typenode())) + m_os<<",true"; + m_os<<")\n"; + } + std::ostream &m_os; + unsigned int &m_count; + generate_codec_cpp &m_gencpp; +}; + +void +cgcpph_typeref::generate_descriptor() +{ + std::string cn(m_typeref.identifier_cpp_name()); + unsigned int _count = 0; + std::list refs; + TyperefPrintTag pt(m_gencpp,m_os,_count); + m_gencpp.reference_chaine(&m_typeref,refs); + + m_os<<"static asn1::tag TAGS_"<cpp_name(); + + + if (m_gencpp.type_in_imports(type,&ns) ) + { + refName = ns->cpp_name()+"::"+type->cpp_name(); + } else + { + refName = type->cpp_name(); + } + + m_os<<"bool "<get_value() == o.get_value();\n"; + m_os<<"}\n"; +} + +// +void +cgcpph_typeref::gen_simple_ctors() +{ + std::string refName; + std::list refs; + asn1::node *ns = NULL; + asn1::node *n = m_typeref.identifier(); + asn1::typeref *type = &m_typeref; + std::string structName = n->cpp_name(); + + m_gencpp.reference_chaine(type,refs); + + if (m_gencpp.type_in_imports(type,&ns) ) + { + refName = ns->cpp_name()+"::"+type->cpp_name(); + } else + { + refName = type->cpp_name(); + } + + // Basic ctor + m_os<tagged() + && (type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT)) + { + m_os<<"\t: "<tagged()) + { + m_os<0 && + refs.back()->type_id()() == asn1::type::ASN1_CHOICE) + { + m_os<get_value() = _v.get_value();\n"; + m_os<<"\treturn *this;\n"; + m_os<<"}\n"; + +} + + +// This method will be used to deal with +// TYPE-IDENTIFIER and OBJECT CLASS +void +cgcpph_typeref::generate_objectclass() +{ + asn1::node *n = m_typeref.identifier(); + m_os<<"// cgcpph_typeref::generate_objectclass helper launched "<name(); + if (n->parameters()) + { + m_os<<" SHOULD ONLY GENERATE WITH ACTUAL_PARAMETERS "; + } + if (m_typeref.act_parameters()) + { + m_os<<" "<cpp_name() ); + std::string structName( ns + "::" + m_typeref.identifier_cpp_name() ); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecPER::encode(streams::per &c,const "<\n"; + hpp<<"int codecPER::decode(streams::per &c,"<\n"; + cpp<<"void codecPER::encode(asn1::streams::per &c,const "<\n"; + cpp<<"int codecPER::decode(asn1::streams::per &c,"< refs; + asn1::node *ident = m_typeref.identifier(); + asn1::typeref *type = &m_typeref; + std::string structName = ident->cpp_name(); + + m_gencpp.reference_chaine(type,refs); + + if (m_gencpp.type_in_imports(type,&ns) ) + { + refName = ns->cpp_name()+"::"+type->cpp_name(); + } else + { + refName = type->cpp_name(); + } + + // + if (m_typeref.tagged()) + { + if ( m_gencpp.tag_mode(type) == asn1::node::tag_type::TM_EXPLICIT) + { + asn1::node *refnode = refs.front(); + // encoder + m_os<<"void\n"<tag().m_class<<","<tag().m_value<<"));\n"; + m_os<<"\tthis->"<tag().m_class<<","<tag().m_value<<"));\n"; + m_os<<"\t\tthis->"<"<"<cpp_name() ); + std::string structName( ns + "::" + m_typeref.identifier_cpp_name() ); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecBER::encode(streams::ber &c,const "<\n"; + hpp<<"int codecBER::decode(streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<cpp_name() ); + std::string structName( ns + "::" + m_typeref.identifier_cpp_name() ); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecOER::encode(streams::oer &c,const "<\n"; + hpp<<"int codecOER::decode(streams::oer &c,"<\n"; + cpp<<"void codecOER::encode(asn1::streams::oer &c,const "<\n"; + cpp<<"int codecOER::decode(asn1::streams::oer &c,"<cpp_name() ); + std::string structName( ns + "::" + m_typeref.identifier_cpp_name() ); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + hpp<<"\ntemplate<>\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"< +#include +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgcpp_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgh_construct.h" +#include "asn1_recursive_visitor.h" + + +cgh_construct::cgh_construct( generate_codec_cpp &g + , std::ostream &os + , asn1::constructed &cdef) + : cgcpp_helper(g,os) ,m_c(cdef) + , m_elcount(0) + , m_t2elcount(0) +{ + m_gencpp.struct_name(&m_c,m_structName); +} + +cgh_construct::~cgh_construct() +{ +} + +/** + * I'm not yet convinced about what to put in here. + * below construct, there are simple types like + * integer, enumerated, oid, bit_string + * and real constructed type like + * choice, set, sequence + * + * Let's use the implementation below for the simple types. + */ +void +cgh_construct::generate_descriptor() +{ + + std::string cn(m_c.identifier_cpp_name()); + unsigned int _count = 0; + + m_os<<"static asn1::tag TAGS_"<(*it); + asn1::typenode *type = f->get_type(); + if (!type) + { + continue; + } + if (it != m_c.begin() ) + m_os<<"\t\t+ "; + m_os<<""<cpp_name()<<".get_length()\n"; + _count++; + } + if (! _count) + { + m_os<<"0 ;\n"; + }else + m_os<<"\t;\n"; + m_os<<"};\n"; +} + +struct ConstructPrintTag +{ + ConstructPrintTag(generate_codec_cpp &_g,std::ostream &os,unsigned int &c) + : m_gencpp(_g), m_os(os), m_count(c) {} + void operator ()(asn1::node *_node) + { + if (asn1::typenode *tn = _node->as_typenode()) + { + m_os<<"\t"; + if (m_count++) + m_os<<", "; + m_os<<"asn1::tag("<<_node->tag().m_class<<","<<_node->tag().m_value; + if (m_gencpp.is_tag_explicit(*_node->as_typenode())) + m_os<<",true"; + m_os<<")\n"; + } + } + std::ostream &m_os; + unsigned int &m_count; + generate_codec_cpp &m_gencpp; +}; + +/** + * + */ +void +cgh_construct::gen_member_tags(std::ostream &_os_tags,asn1::field &_f,asn1::typenode &_type) +{ + std::string cls(m_c.identifier()->cpp_name()); + unsigned int _count = 0; + ConstructPrintTag pt(m_gencpp,_os_tags,_count); + + + _os_tags<<"static asn1::tag MTAGS_"<otag(m_gencpp.resolver()); + std::list refs; + _os_tags<<"// Is private "<<_f.cpp_name()<<"\n"; + m_gencpp.reference_chaine(tref,refs); + std::for_each(refs.rbegin(),refs.rend(),pt); + } else + { + _os_tags<<"asn1::tag("<<_type.tag().m_class<<","<<_type.tag().m_value; + _os_tags<<")\n"; + } + } + _os_tags<<"};\n"; +} +/** + * + */ +void +cgh_construct::gen_member_desc(std::ostream &_os_desc,asn1::field &_f,asn1::typenode &_type) +{ + std::string cls(m_c.identifier()->cpp_name()); + std::string cn("MTAGS_"+cls+"_"+_f.cpp_name()); + + _os_desc<<"static asn1::types::descriptor DESC_"<cpp_name()); + std::ostringstream _os(""); + std::ostringstream _os_tags(""); + std::ostringstream _os_desc(""); + _os<<"static asn1::types::member_desc MEMBER_"<(*it); + asn1::typenode *type = f->get_type(); + if (!type) + { + _os<<" /*...*/\n"; + continue; + } + std::ostringstream mos(""); + gen_member_tags(_os_tags,*f,*type); + gen_member_desc(_os_desc,*f,*type); + std::string desc("DESC_"+cls+"_"+f->cpp_name()); + //mos<<"MEMBER_OFFSET("<flags().is_optional()) + tf="asn1::types::TF_SHARED_POINTER"; + else + tf="asn1::types::TF_NONE"; + } + m_elcount++; + if ( type + && type->tagged() + ) + { + std::string _mode = (m_gencpp.is_tag_explicit(*type))?" 1":"-1"; + _os<<" { "<tag().m_value<<"<<2) | "; + _os<tag().m_class<<" ,\n "<name()<<"\"}, /* "<name()<<" */\n"; + } else + { + if (asn1::typeref *ref = type->as_typeref()) + { + asn1::node::tag_type tg = ref->otag(m_gencpp.resolver()); + if ( ref->get_canonical_typenode() + && dynamic_cast(ref->get_canonical_typenode())) + { + _os<<" { "<name()<<"\"}, /* Choice ...*/\n"; + } else if (ref->is_complex() && (tg.m_value == -1)) + { + tf = "asn1::types::TF_OPEN_TYPE"; + _os<<" { "<name()<<"\"}, /* Cplx ...*/\n"; + } else + { + _os<<" { "<name()<<"\"},"; + _os<<" /* cano:"<get_canonical_typenode()->name()<<"*/\n"; + } + } else + { + if (f->flags().is_optional()) + tf="asn1::types::TF_SHARED_POINTER"; + else + tf="asn1::types::TF_NONE"; +#if 0 + // 2017/07/26 Generated too many compiler warning + if (! is_choice) + { + mos.str(""); + mos<<"MEMBER_OFFSET("<cpp_name()<<")"; + } +#endif + _os<<" { "<name()<<"\"},\n"; + } + } + + } + _os<<"};\n"; + m_os<<_os_tags.str()< +{ + protected: + std::fstream &m_log; + generate_cpp &m_gencpp; + asn1::constructed &m_c; + std::ostream &m_os; + std::string m_current_choice; + int &m_t2elcount; + int m_elcount; + public: + + tag2glv( generate_cpp &g + , std::ostream &os + , asn1::constructed &cdef + , int &_t2elc) + : m_gencpp(g), m_os(os) ,m_c(cdef) + , m_log(g.logger()) + , m_t2elcount(_t2elc) + , m_elcount(0) + { + } + + bool visit_alternative_choice(asn1::field *f) + { + asn1::typenode *type = f->get_type(); + if (f->get_parent()->name() == m_c.name()) + { + m_current_choice = f->cpp_name(); + m_elcount++; + } + if (f->is_extensible()) + return false; + if (type && type->tagged()) + { + asn1::node::tag_type tg = type->tag(); + print_entry(tg,f); + m_t2elcount++; + return false; + } else if (asn1::typeref *r = type->as_typeref()) + { + if (asn1::node *rt = r->get_real_type()) + { + if (r->is_complex()) + { + traverse_type(rt); + return false; + } + if (asn1::choice *c = dynamic_cast(rt)) + { + traverse_type(rt); + return false; + } + if (asn1::typeref *oref = rt->as_typeref()) + { + asn1::node::tag_type tg = oref->otag(m_gencpp.resolver()); + print_entry(tg,f); + m_t2elcount++; + return false; + } + asn1::node::tag_type tg = rt->tag(); + assert( (tg.m_value != -1) && "Tag must be other than -1"); + print_entry(tg,f); + m_t2elcount++; + return false; + } else { + asn1::node *nrt = m_gencpp.resolver().resolve(*r); + if (nrt && nrt->tagged()) + { + asn1::node::tag_type tg = nrt->tag(); + print_entry(tg,f); + m_t2elcount++; + return false; + } + } + //m_os<<"n"; + } else if (type ) { + asn1::node::tag_type tg = type->tag(); + print_entry(tg,f); + m_t2elcount++; + return false; + } + m_os<<"/*end "<<__FUNCTION__<<"*/"; + return true; + } + // + bool visit_primitive(asn1::node *p) + { + return true; + } + // + bool visit_reference(asn1::node *type) + { + if (type->tagged()) + return true; + if (asn1::typeref *r = type->as_typeref()) + { + if (asn1::node *rt = r->get_real_type()) + { + if (asn1::choice *c = dynamic_cast(rt)) + return traverse_type(rt); + if (r->is_complex()) + return traverse_type(rt); + m_os<<"."; + } + } + m_os<<"/* "<<__FUNCTION__<<" : "<cpp_name(); + m_os<<"*/"<cpp_name()<<"::"<<"typeof_"<name()<<" */"<cpp_name()<<"_tag2el[] = {\n"; + bool r= glv.traverse_type(&m_c); + m_os<<"};\n"; +} + + +/** + * + */ +void +cgh_construct::gen_codec_ber_encode() +{ + std::string ns ( m_gencpp.get_module()->cpp_name() ) ; + std::string structName ( ns + "::" +m_c.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); +#if 0 + //m_gencpp.gen_template_signature(m_os,type); + hpp<<"\n// sequence type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::streams::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::streams::ber &c,"<\n"; + cpp<<"void codecBER::encode(asn1::streams::ber &c,const "<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<tagged() + && (m_gencpp.is_tag_explicit(*attr_type))) + { + asn1::node::tag_type lt = attr_type->tag(); + cpp<<"\t{\n"; + cpp<<"\t\t"<<"asn1::tag t("<cpp_name()<<".get_length());\n"; + } + + if (f->flags().is_optional() && (! f->flags().is_default())) + { + cpp<<"\tif ( ! _t."<cpp_name()<<".is_nul())\n\t{\n"; + cpp<<"\t\tencode(c,_t."<cpp_name()<<".get());\n\t}\n"; + } else + { + cpp<<"\tencode(c,_t."<cpp_name()<<");\n"; + } + /* end explicit */ + if (attr_type->tagged() + && (m_gencpp.is_tag_explicit(*attr_type))) + cpp<<"\t}\n"; + } + + } /* end for */ + cpp<<"\tc.encode_sequence_epilogue(_t);\n"; + cpp<<"}\n"; +} +/** + * + */ +void +cgh_construct::gen_codec_ber_decode() +{ + std::string ns ( m_gencpp.get_module()->cpp_name() ) ; + std::string structName ( ns + "::" +m_c.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + + cpp<<"\ntemplate<>\n"; + cpp<<"int codecBER::decode(asn1::streams::ber &c,"<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<tagged() + && (m_gencpp.is_tag_explicit(*attr_type))) + { + asn1::node::tag_type lt = attr_type->tag(); + cpp<<"\t{\n"; + cpp<<"\t\tasn1::tag t("<flags().is_optional() && (! f->flags().is_default())) + { + cpp<<"\tdecode(c,_t."<cpp_name()<<".get());\n"; + } else + { + cpp<<"\tdecode(c,_t."<cpp_name()<<");\n"; + } + if (attr_type->tagged() + && (m_gencpp.is_tag_explicit(*attr_type))) + { + cpp<<"\t\t}\n"; + cpp<<"\t}\n"; + } + } + } + cpp<<"\tif ( c.decode_sequence_epilogue(_t) != asn1::ok)\n"; + cpp<<"\t\treturn asn1::wrong_type;\n"; + cpp<<"\treturn asn1::ok;\n"; + cpp<<"}\n"; + +} + +/** + * + */ +void +cgh_construct::gen_ndecode(const std::string &scope,bool priv) +{ + asn1::constructed *type = &m_c; + asn1::node::iterator lit = type->begin(); + asn1::node::iterator end = type->end(); + std::string lscope; + + gen_ndecode_preamble(scope,priv); + gen_ndecode_epilogue(scope,priv); + m_gencpp.gen_template_signature(m_os,type); + + if (!priv) + { + lscope = type->identifier_cpp_name(); + m_os<<"int "<identifier_cpp_name(); + } else + { + lscope = scope + type->cpp_name(); + m_os<<"int "<cpp_name(); + } + + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::decode(asn1::context &ctx)"<(*lit); + if (f->get_type() != NULL) + { + asn1::typenode *attribute_type = f->get_type(); + + if (f->flags().m_flags == asn1::node::marker_type::FL_OPTIONAL) + { + m_os<<"\t// DEF OPTIONAL ATTRIBUTE"<tagged()) + { // Ok tagged value + asn1::node::tag_type lt = attribute_type->tag(); + if(attribute_type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT) + { + m_os<<"\t"<cpp_name()<<".decode(ctx);"; + m_os<<"// IMPLICIT DEF="<type_id()()<has_constraints() ) + { + std::string indent("\t\t"); + m_gencpp.gen_attribute_constrained_ndecode(m_os,scope,indent ,f); + } else if (f->flags().is_default() ) + { + m_os<<"\t"<cpp_name()<<".decode(ctx);"; + m_os<<"// EXPLICIT DEF D ="<type_id()()<flags().is_optional()) + m_os<<"ASN1_ATTRIBUTE_OPTIONAL_DECODE("; + m_os<cpp_name(); + if (! f->flags().is_optional()) + m_os<<".decode(ctx"; + m_os<<");// EXPLICIT DEF O ="<type_id()()<has_constraints() ) + { + m_gencpp.gen_attribute_constrained_ndecode(m_os,scope,indent ,f); + } else if (f->flags().is_default() ) + { + // gen_attribute_default_encode(os,scope,indent ,(*lit)); + m_os<<"\t"<<""<cpp_name()<<".decode(ctx);//DEF D ="; + m_os<type_id()()<<" - "<flags().is_optional() ) + { + // gen_attribute_optional_encode(os,scope,indent ,(*lit)); + m_os<<"\t"<<"ASN1_ATTRIBUTE_OPTIONAL_DECODE("; + m_os<cpp_name()<<");//DEF O ="; + m_os<type_id()()<<" - "<cpp_name()<<".decode(ctx);//DEF="; + m_os<type_id()()<<" - "<tagged()) + { + if ( m_gencpp.is_tag_explicit(m_c) ) + { + if (!priv) + { + m_os<<"int "<identifier_cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::decode_preamble_ber(asn1::streams::ber &ctx)"<identifier_name()<<"::decode_preamble_ber EXPLICIT tag:%d\",this->tag().byte());\n"; + } else + { + m_os<<"int "<cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::decode_preamble_ber(asn1::streams::ber &ctx)"<cpp_name()<<"::decode_preamble_ber EXPLICIT tag:%d\",this->tag().byte());\n"; + } + // + m_os<<"\tctx.nb_bits((1)<<3);"<tagged()) + { + if ( m_gencpp.is_tag_explicit(m_c) ) + { + if (!priv) + { + m_os<<"int "<identifier_cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::decode_epilogue_ber(asn1::streams::ber &ctx)"<identifier_name(); + m_os<<"::decode_epilogue_ber EXPLICIT SEQUENCE tag:%d\",this->tag().byte());\n"; + } + } else + { + m_os<<"int "<cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::decode_epilogue_ber(asn1::streams::ber &ctx)"<cpp_name(); + m_os<<"::decode_epilogue_ber EXPLICIT SEQUENCE tag:%d\",this->tag().byte());\n"; + } + } + // + m_os<<"\tunsigned long pos = ctx.bytes();"<begin(); + asn1::node::iterator end = (type)->end(); + + gen_nencode_preamble(scope,priv); + gen_nencode_epilogue(scope,priv); + + m_gencpp.gen_template_signature(m_os,type); + if (!priv) + { + m_os<<"void "<identifier_cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::encode(asn1::context &ctx)"<identifier_name()<<"::encode SEQUENCE \");\n"; + } else + { + m_os<<"void "<cpp_name(); + m_gencpp.gen_template_signature_class(m_os,type); + m_os<<"::encode(asn1::context &ctx)"<cpp_name()<<"::encode SEQUENCE\");\n"; + } + // + m_os<<"\tencode_preamble(ctx);"<(*lit); + if (f->get_type() != NULL) + { + asn1::typenode *attribute_type = f->get_type(); + + if ((*lit)->flags().m_flags == asn1::node::marker_type::FL_OPTIONAL) + { + m_os<<"\t\t// DEF OPTIONAL ATTRIBUTE"<tagged()) + { // Ok tagged value + if(attribute_type->tag().m_mode == asn1::node::tag_type::TM_IMPLICIT) + { + asn1::node::tag_type lt = attribute_type->tag(); + m_os<<"\t\t"<cpp_name()<<".encode(ctx);// IMPLICIT DEF="<type_id()()<tag(); + m_os<<"\t\t"<cpp_name()<<".encode(ctx);// EXPLICIT DEF="<type_id()()<has_constraints() ) + { + // gen_attribute_constrained_encode(os,scope,indent ,(*lit)); + std::string indent("\t\t"); + m_gencpp.gen_attribute_constrained_nencode(m_os,scope,indent ,f); + } else if (f->flags().is_default() ) + { + // gen_attribute_default_encode(os,scope,indent ,(*lit)); + m_os<<"\tif (bit_mask.test("<cpp_name()<<"::"; + m_os<cpp_name()<<"_present))\n"; + m_os<<"\t\t"<<""<cpp_name()<<".encode(ctx);//DEF D ="; + m_os<get_type()->type_id()()<<" - "<flags().is_optional() ) + { + // gen_attribute_optional_encode(os,scope,indent ,(*lit)); + m_os<<"\t\t"<<"ASN1_ATTRIBUTE_OPTIONAL_ENCODE("; + m_os<cpp_name()<<");//DEF O ="; + m_os<type_id()()<<" - "<cpp_name()<<".encode(ctx);//DEF="; + m_os<type_id()()<<" - "<tagged()) + { + if ( m_gencpp.is_tag_explicit(m_c) ) + { + if (!priv) + { + m_os<<"void "<identifier_cpp_name()<<"::encode_preamble_ber(asn1::context &ctx)"<identifier_name()<<"::encode_preamble_ber EXPLICIT tag:%d\",this->tag().byte());\n"; + } else + { + m_os<<"void "<cpp_name()<<"::encode_preamble_ber(asn1::context &ctx)"<cpp_name()<<"::encode_preamble_ber EXPLICIT tag:%d\",this->tag().byte());\n"; + } + // + m_os<<"\tunsigned char *b = ctx.buffer();"<tag().m_class<<","<tag().m_value<<",true);"<type_id()() == asn1::type::ASN1_SET) + { + m_os<<"\tb[m_pos+2] = MAKE_TAG(0,1,17);\n"; + } else + m_os<<"\tb[m_pos+2] = MAKE_TAG(0,1,16);\n"; + + m_os<<"\tctx.nb_bits((4)<<3);"<tag().byte());\n"; + } else + { + m_os<<"void "<tag().byte());\n"; + } + // + m_os<<"\tunsigned long pos = ctx.bytes();"<cpp_name(); + structName = structName + "::" +m_c.identifier()->cpp_name(); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + //m_Gen.gen_template_signature(m_os,type); + hpp<<"\n// construct type "<\n"; + hpp<<"void asn1::codecBER::encode(asn1::codec::ber &c,const "<\n"; + hpp<<"int asn1::codecBER::decode(asn1::codec::ber &c,"<\n"; + hpp<<"void codecJER::encode(streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(streams::jer &c,"<cpp_name(); + std::string structName ( MName + "::" + m_c.identifier_cpp_name() ); + std::fstream &hpp(m_gencpp.get_streams().m_os_codec_hpp); + std::fstream &cpp(m_gencpp.get_streams().m_os_codec_cpp); + + + hpp<<"\n// cgh_construct sequence or set type "<\n"; + hpp<<"void codecJER::encode(asn1::streams::jer &c,const "<\n"; + hpp<<"int codecJER::decode(asn1::streams::jer &c,"<\n"; + cpp<<"void codecJER::encode(asn1::streams::jer &c,const "<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<flags().is_optional() ) + { + cpp<<"\tif ( ! _t."<cpp_name()<<".is_nul())\n\t"; + } + cpp<<"\tc.put_char(\", \",2);\n"; + } + if (f->flags().is_optional() ) + { + cpp<<"\tif ( ! _t."<cpp_name()<<".is_nul())\n\t{\n"; + cpp<<"\t\tc.put_field(\""; + cpp<cpp_name()<<"\","<cpp_name().size()<<");\n"; + cpp<<"\t\tc.put_char(\": \",2);\n"; + cpp<<"\t\tencode(c,_t."<cpp_name()<<".get());\n\t}\n"; + } else + { + cpp<<"\tc.put_field(\""; + cpp<cpp_name()<<"\","<cpp_name().size()<<");\n"; + cpp<<"\tc.put_char(\": \",2);\n"; + cpp<<"\tencode(c,_t."<cpp_name()<<");\n"; + } + } + } + + } + cpp<<"\tc.put_char(\"}\",1);\n"; + + cpp<<"}\n"; + /* Implementation of decoding stream */ + cpp<<"\ntemplate<>\n"; + cpp<<"int codecJER::decode(asn1::streams::jer &c,"<(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + cpp<<"\t// Extensible marker"<cpp_name()<<"\"))\n\t{\n"; + cpp<<"\t\tc.get_token(asn1::streams::jer::jer_tok_colon);\n"; + if (f->flags().is_optional()) + { + cpp<<"\t\tdecode(c,_t."<cpp_name()<<".get());\n"; + } else + { + cpp<<"\t\tdecode(c,_t."<cpp_name()<<");\n"; + } + cpp<<"\t}\n"; + } + } + } + cpp<<"\tif ( c.decode_sequence_epilogue(_t) != asn1::ok)\n"; + cpp<<"\t\treturn asn1::wrong_type;\n"; + cpp<<"\treturn asn1::ok;\n"; + cpp<<"}\n"; + } +} + + + +/** + * vim: et sw=2 ts=2 list: + */ diff --git a/libgen/cpp/cgh_construct.h b/libgen/cpp/cgh_construct.h new file mode 100644 index 0000000..d1293cc --- /dev/null +++ b/libgen/cpp/cgh_construct.h @@ -0,0 +1,68 @@ +#ifndef CGH_CONSTRUCT_H +#define CGH_CONSTRUCT_H + + +/** + * + */ +class cgh_construct : public cgcpp_helper +{ + protected: + int m_elcount; + int m_t2elcount; + cgh_construct(const cgh_construct &s ) + : cgcpp_helper(s.m_gencpp,s.m_os) + , m_c(s.m_c) + {} + public: + cgh_construct( generate_codec_cpp &g + , std::ostream &os + , asn1::constructed &cdef) ; + + ~cgh_construct(); + + // generate codec part + virtual void generate_per() {}; + // + virtual void generate_ber() {}; + // + virtual void generate_oer() {}; + // + virtual void generate_jer() ; + // + virtual void generate_xer() {} ; + + protected: + // + virtual void generate_descriptor() ; + /** + * Generate descriptor for set and sequence + */ + void gen_desc_seqset(); + void gen_codec(); + void gen_equal(); + void gen_data_length(); + void gen_codec_ber_encode(); + void gen_codec_ber_decode(); + protected: + void gen_member_tags(std::ostream &os,asn1::field &_f,asn1::typenode &_type); + void gen_member_desc(std::ostream &os,asn1::field &_f,asn1::typenode &_type); + // Usefull + void gen_member_table(); + // Generate a table for choice to be able to compute + // the appropriate m_kind from the tag + void gen_tag2el_table(); + // 2017/06/06 Lets say I'm going to use same way for + // sequence and set even if it's not the same + void gen_ndecode(const std::string &scope,bool priv); + void gen_ndecode_preamble(const std::string &scope,bool priv); + void gen_ndecode_epilogue(const std::string &scope,bool priv); + void gen_nencode(const std::string &scope,bool priv); + void gen_nencode_preamble(const std::string &scope,bool priv); + void gen_nencode_epilogue(const std::string &scope,bool priv); + protected: + asn1::constructed &m_c; + std::string m_structName; +}; + +#endif diff --git a/libgen/cpp/cgh_hconstruct.cpp b/libgen/cpp/cgh_hconstruct.cpp new file mode 100644 index 0000000..d6eaab7 --- /dev/null +++ b/libgen/cpp/cgh_hconstruct.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgh_hconstruct.h" +#include "asn1_recursive_visitor.h" + + +cgh_hconstruct::cgh_hconstruct( generate_header &g + , std::ostream &os + , asn1::constructed &cdef) + : cghpp_helper(g,os) ,m_c(cdef) +{ + m_gencpp.struct_name(&m_c,m_structName); +} + +cgh_hconstruct::~cgh_hconstruct() +{ +} + +void +cgh_hconstruct::generate() +{ +#if 1 + cghpp_helper::generate(); +#else + generate_prolog( ); + + // Missing constructors + generate_descriptor( ); + // Initial ctor + generate_ctors( ); + + generate_operators( ); + + generate_members( ); + // + generate_ber(); + // + generate_printf( ); + + m_os<<"};\n"; +#endif +} + +void +cgh_hconstruct::generate_descriptor() +{ + cghpp_helper::generate_descriptor( ); +} + + +/** + * vim: et sw=2 ts=2 list: + */ diff --git a/libgen/cpp/cgh_hconstruct.h b/libgen/cpp/cgh_hconstruct.h new file mode 100644 index 0000000..44a7ffe --- /dev/null +++ b/libgen/cpp/cgh_hconstruct.h @@ -0,0 +1,75 @@ +#ifndef CGH_HCONSTRUCT_H +#define CGH_HCONSTRUCT_H + + +/** + * + */ +class cgh_hconstruct : public cghpp_helper +{ + protected: + cgh_hconstruct(const cgh_hconstruct &s ) + : cghpp_helper(s.m_gencpp,s.m_os) + , m_c(s.m_c) , m_structName(s.m_structName) + {} + public: + cgh_hconstruct( generate_header &g + , std::ostream &os + , asn1::constructed &cdef) ; + + ~cgh_hconstruct(); + + // Helper functions + virtual void generate() ; + + // generate codec part + virtual void generate_per() {}; + // + virtual void generate_ber() {}; + // + virtual void generate_oer() {}; + // + virtual void generate_jer() {}; + // + virtual void generate_xer() {} ; + + protected: + // Usefull + /** + * @brief implement the code that generated + * the begin of the structure. example: + * struct type : public primary type \n {\n + */ + virtual void generate_prolog( ) { } ; + /** + * @ brief add a static descriptor attribute to each datatype + * this static variable contains the asn1 type meta data + * static const types::descriptor _meta; + */ + void generate_descriptor(); + /** + * @brief generate constructors for the type + * + */ + virtual void generate_ctors() { }; + /** + * @brief generique function to generate printf + */ + virtual void generate_printf() { }; + /** + * @brief for choice, sequence and set this + * can be useful + */ + virtual void generate_members() { }; + /** + * @brief use this function to generate code related to + * c++ operator like equal, + - * / etc... + */ + virtual void generate_operators() { }; + + protected: + asn1::constructed &m_c; + std::string m_structName; +}; + +#endif diff --git a/libgen/cpp/cgh_object.cpp b/libgen/cpp/cgh_object.cpp new file mode 100644 index 0000000..b86d5a0 --- /dev/null +++ b/libgen/cpp/cgh_object.cpp @@ -0,0 +1,220 @@ +#include +#include +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_object.h" +#include "asn1_visitor.h" + + +cgh_object::cgh_object( generate_cpp &g + , std::ostream &os + , asn1::object &s + , asn1::classdef &cdef) + : m_Gencpp(g), generator_helper(os) , m_object(s) ,m_classdef(cdef) + , m_log(g.logger()) +{ +} + +cgh_object::~cgh_object() +{ +} + + +/** + * Helper functions + * + */ +void cgh_object::generate() +{ +} + +// generate codec part +void cgh_object::generate_per() +{ +} + +// +void cgh_object::generate_ber() +{ +} + +// +void cgh_object::generate_oer() +{ +} + +// +void cgh_object::generate_jer() +{ +} + +// +void cgh_object::generate_xer() +{ +} + +/** + * + */ +class cgho_gtplt_args : public node_visitor +{ + protected: + asn1::classdef &m_classdef; + asn1::object &m_object; + generate_cpp &m_gen; + std::stringstream m_os; + std::fstream &m_log; + long m_count; + bool m_with_scope; + public: + cgho_gtplt_args(generate_cpp &_gen,asn1::object &_obj,asn1::classdef &_cdef,bool with_scope) + : m_count(0), m_classdef(_cdef),m_object(_obj),m_gen(_gen) + , m_log(_gen.logger()) , m_with_scope(with_scope) + { m_os.str(""); } ; + + std::string result() { return m_os.str() ; } + +#define ASN1_CLASSFIELD_TYPE(cf,code) \ + void visit_##cf(asn1::cf *field) code + +ASN1_CLASSFIELD_TYPE(classfield_tf,{ + asn1::node *type = NULL; + if ( (type = m_object.get_field(field->name()) ) != NULL) + { + if (m_count++) + m_os<<" ,"; + if (m_with_scope) + { + asn1::typeref *ref = dynamic_cast(type); + asn1::node *rtype = (ref)?ref->get_real_type():NULL; + if(ref && !rtype) + { + ref->resolve(m_gen.resolver()); + rtype = ref->get_real_type(); + } else + { + std::cerr<<"gen_template_args type= "; + std::cerr<name()<<" NOT TYPEREF\n"; + } + if (rtype) + { + m_os<<" "<get_parent()->cpp_name()<<"::"; + } + } else + m_os<<" "; + switch (type->type_id()()) + { + case asn1::type::ASN1_SET_OF: + { + asn1::node *seqof_type = type->as_typenode()->get_eltype(); + std::string strtype; + if (m_gen.type2cppstring(type->as_typenode(),strtype)) + { + m_os<cpp_name()<<"<"; + m_os< "; + } else + { + m_os<cpp_name()<<"<"; + m_os<cpp_name(); + m_os<<"> "; + } + } + break; + default: + GEN_LOG_ERROR( "gen_template_args TFT %s %s\n" + , field->name().c_str() + , type->cpp_name().c_str()); + m_os<cpp_name(); + } + } else + { // Undefined type. replace with asn1::type + if (m_count++) + m_os<<" ,"; + m_os<<" asn1::types::type"; + } + +}) +ASN1_CLASSFIELD_TYPE(classfield_ftvf,{ + asn1::valuetype *type = NULL; + if ( (type = m_object.get_ftvf(field->name()) ) != NULL ) + { + std::string s = field->name(); + s[0] = '_'; + switch (type->type_id()()) + { + case asn1::type::ASN1_INTEGER: + { + GEN_LOG_DEBUG( "gen_template_args INT %s %s\n" + , field->name().c_str() + , type->cpp_name().c_str()); + if (m_count++) + m_os<<" ,"; + m_os<<" "<cpp_name(); + } + break; + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + GEN_LOG_DEBUG( "gen_template_args OID %s %s\n" + ,field->name().c_str(),type->cpp_name().c_str()); + asn1::object_identifier *oid = type->as_object_identifier(); + long size = oid->hash(); + if (m_count++) + m_os<<" ,"; + m_os<<" "<value(); + GEN_LOG_DEBUG( "gen_template_args CHOICE %s %s\n" + , field->name().c_str(),type->cpp_name().c_str()); + if (m_count++) + m_os<<" ,"; + m_os<<" "<cpp_name(); + } + default: + GEN_LOG_ERROR( "gen_template_args %s id %s\n" + , field->name().c_str() + , type->type_id().name()); + } + } + +}) +ASN1_CLASSFIELD_TYPE(classfield_vtvf,{}) +ASN1_CLASSFIELD_TYPE(classfield_ftvsf,{}) +ASN1_CLASSFIELD_TYPE(classfield_vtvsf,{}) +ASN1_CLASSFIELD_TYPE(classfield_of,{}) +ASN1_CLASSFIELD_TYPE(classfield_osf,{}) +#undef ASN1_CLASSFIELD_TYPE +}; + +/** + * Needs some reworking for SET_OF type in CMIP + */ +void +cgh_object::gen_template_args(bool with_scope) +{ + asn1::node::iterator fit = m_classdef.begin(); + int count = 0; + + cgho_gtplt_args cgho(m_Gencpp,m_object,m_classdef,with_scope); + //std::cout<<"\n\nBEGIN FUNCTION get_template_args with_scope="< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cgh_value.h" + + +cgh_value::cgh_value( generate_header &g + , std::ostream &os + , asn1::value &s) + : m_Gen(g) + , generator_helper(os) + , m_value(s) + , m_log(g.logger()) +{ +} + +cgh_value::~cgh_value() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cgh_value::generate() +{ + asn1::node *n = m_value.identifier(); + asn1::node *type = &m_value; + asn1::node *params = NULL; + std::string structName; + std::string scope(""); + + if (m_Gen.with_source_comment()) + m_os<<"// cgh_value helper launched "< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_hpp.h" +#include "cghpp_helper.h" + + +/** + * constructor + */ +cghpp_helper::cghpp_helper( generate_header &g + , std::ostream &os + ) + : m_gencpp(g), generator_helper(os),m_log(g.logger()) +{ +} + +/** + * + * @brief common way to generate the required code depending + * on the global settings given to the asn1 parser. + */ +void +cghpp_helper::generate() +{ + // generate class begin + generate_prolog(); + // descriptor is a static attribute named _meta + generate_descriptor(); + // generate ctors + generate_ctors(); + // generate members + generate_members(); + // generate ber + generate_ber(); + // generate jer + // generate oer + // generate per + generate_operators(); + // + generate_printf(); + // generate class end + m_os<<"};\n"; +} + +void +cghpp_helper::generate_descriptor() +{ + m_os<<"\tstatic const asn1::types::descriptor _meta;\n"; +} + +void +cghpp_helper::generate_prolog() +{ +} + +void +cghpp_helper::generate_ctors() +{ +} + +/* Only valid for choice, set ,and sequence */ +void +cghpp_helper::generate_members() +{ +} + +void +cghpp_helper::generate_printf() +{ +} diff --git a/libgen/cpp/cghpp_helper.h b/libgen/cpp/cghpp_helper.h new file mode 100644 index 0000000..19bbf33 --- /dev/null +++ b/libgen/cpp/cghpp_helper.h @@ -0,0 +1,80 @@ +#ifndef CODE_GEN_HPP_HELPER_H +#define CODE_GEN_HPP_HELPER_H + +/** + * This class defines the interface that each + * asn1 type generation should implement .... + * Unlike generator_helper, this class provides a first + * level of functions dedicated to c++ code generation. The goal is + * to move the generation from one unique file to one file per type. + * -> provide streams for cpp,h and hpp. + * -> provide generic preamble et epilog + * -> open /close stream + */ +class cghpp_helper : public generator_helper +{ + public: + cghpp_helper( generate_header &g + , std::ostream &os + ); + + /** + * @brief entry point to generate the structure. Should + * follow the same pattern for all asn1 types. + * @TODO This function should not be virtual when you think + * of it. + */ + virtual void generate() ; + // generate codec part + virtual void generate_per() {}; + // + virtual void generate_ber() {}; + // + virtual void generate_oer() {}; + // + virtual void generate_jer() {}; + // + virtual void generate_xer() {}; + + // generate encoder + // generate decoder + // generate constructor + // generate + protected: + /** + * @brief implement the code that generated + * the begin of the structure. example: + * struct type : public primary type \n {\n + */ + virtual void generate_prolog(); + /** + * @ brief add a static descriptor attribute to each datatype + * this static variable contains the asn1 type meta data + * static const types::descriptor _meta; + */ + void generate_descriptor(); + /** + * @brief generate constructors for the type + * + */ + virtual void generate_ctors(); + /** + * @brief generique function to generate printf + */ + virtual void generate_printf(); + /** + * @brief for choice, sequence and set this + * can be useful + */ + virtual void generate_members(); + /** + * @brief use this function to generate code related to + * c++ operator like equal, + - * / etc... + */ + virtual void generate_operators() {}; + protected: + std::fstream &m_log; + generate_header &m_gencpp; +}; + +#endif diff --git a/libgen/cpp/cghpph_bitstring.cpp b/libgen/cpp/cghpph_bitstring.cpp new file mode 100644 index 0000000..90ef8b4 --- /dev/null +++ b/libgen/cpp/cghpph_bitstring.cpp @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cghpp_helper.h" +#include "cgh_hconstruct.h" +#include "cghpph_bitstring.h" + + +cghpph_bit_string::cghpph_bit_string(generate_header &g,std::ostream &os,asn1::bit_string &s) + : cgh_hconstruct(g,os,s) , m_bit_string(s) +{ +} + +cghpph_bit_string::~cghpph_bit_string() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_bit_string::generate() +{ + cgh_hconstruct::generate( ); +} + +/** + * + */ +void cghpph_bit_string::generate_prolog() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_bit_string helper launched "<(*it); + if ((*it)->type_id()()== asn1::type::ASN1_INTEGER /*&& (*it)->value_long()<31*/) + { + m_os<<"\tstatic unsigned long const "<<(*it)->cpp_name(); + long dest= tv->value_long(); + m_os<<"\t= "<cpp_name(); + long dest= tv->value_long(); + m_os<<"\t= "< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cghpph_primitive.h" +#include "cghpph_boolean.h" + + +cghpph_boolean::cghpph_boolean(generate_header &g,std::ostream &os,asn1::boolean &s) + : cghpph_primitive(g,os,s) + , m_boolean(s) +{ +} + +cghpph_boolean::~cghpph_boolean() +{ +} + +/** + * + */ +void cghpph_boolean::generate_prolog() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_boolean helper launched "<parameters(); + + m_os<<"\tfriend std::ostream &operator <<(std::ostream &os,const "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<");"; + m_os<<"\n"; +} + +/** + * + */ +void cghpph_boolean::generate_ber() +{ + // + if (m_boolean.tagged()) + { + if ( m_gencpp.is_tag_explicit(m_boolean) ) + { + // + m_os<<"\tvirtual void encode(asn1::context &ctx);"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cgh_hconstruct.h" +#include "cghpph_choice.h" + +#undef GEN_LOG_DEBUG +#define GEN_LOG_DEBUG + +cghpph_choice::cghpph_choice(generate_header &g,std::ostream &os,asn1::choice &s) + : cgh_hconstruct(g,os,s) , m_choice(s) +{ +} + +cghpph_choice::~cghpph_choice() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_choice::generate() +{ + asn1::node *ident = m_choice.identifier(); + asn1::constructed *params = (ident) ? ident->parameters() : NULL; + + if (m_gencpp.with_source_comment()) + { + m_os<<"\n//\n// cghpph_choice helper launched "; + m_os<parameters() : NULL; + + // Handle parameter stuff + if (ident->parameters() && m_gencpp.is_template(ident->parameters())) + { + m_os<<"//"<<__FUNCTION__<<" parameterized\n"; + // Forward declaration for ostream function + m_os<<"template "; + m_gencpp.gen_template_signature(m_os,params); + m_os<<" struct "<parameters() : NULL; + + // Constructor + // Initialize tag , with first aleternative choice + // First alternative choice + it = m_choice.begin(); + asn1::field *first = dynamic_cast(*it); + + if (first->get_type()->tagged()) + { + asn1::node::tag_type lt = first->get_type()->tag(); + + m_os<<"\t"<get_type()->as_typeref()) + { + // get outer most tag + //asn1::node::tag_type o_tag = tref->otag(); + asn1::node::tag_type o_tag = m_choice.get_tag(m_gencpp.resolver()); + m_os<<"\t"<get_type()->tag().m_value<<"));\n"; + // Why ... + m_os<<"\t"<get_type()->tag().m_value<<"));\n"; + } + + // Missing Copy constructor + m_os<<"\t"<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s) ;\n"; + // Clone + m_os<<"\tvirtual "<(ident->parameters()); + + // Ok, loop over attributes + // to generate setter and getter + for ( asn1::node::iterator it = m_choice.begin() + ; it != m_choice.end() ; ++it) + { + asn1::field *f = dynamic_cast(*it); + m_gencpp.gen_composite_attribute(m_os,scope,*f,ident->parameters(),false); + // Setter + gen_setter(f); + } + // Now add an enum to identifie type + gen_enum_type(); + // Gen attribute parameters (OPERATION ....) + + + if (params) + { + for (asn1::node::iterator it = params->begin(); + it != params->end(); + ++it) + { + asn1::parameter *p = dynamic_cast(*it); + if (asn1::node *g = p->get_governor()) + { + asn1::typeref *objr = dynamic_cast(g); + asn1::node *obj = m_gencpp.resolver().resolve(*objr); + asn1::module *m = dynamic_cast(obj->get_parent()); + m_os<<"\t// "<name()<<" "<name()<is_simple()) + { + m_os<<"\t"<cpp_name()<<"::I"<name()<<" **"<name()<<";"<parameters(); + asn1::typenode *attr_type = attribute->get_type(); + m_os<<"\n"; + // + if (attr_type != NULL) + { + switch (attr_type->type_id()()) + { + case asn1::type::ASN1_ENUMERATED: + case asn1::type::ASN1_CHOICE: + { + assert( 0 && "cghpph_choice::gen_setter ENUM OR CHOICE should not happend"); + } + break; + case asn1::type::ASN1_REFERENCE: + { + asn1::typeref *tref = dynamic_cast(attr_type); + asn1::node *rt = m_gencpp.resolver().resolve(*tref); + if ( tref->is_simple() + || (rt && rt->type_node()) + ) + { + m_os<<"\tvoid set_"<cpp_name()<<"(const "; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<" &s);\n"; + m_os<<"\t"; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<"& get_"<cpp_name()<<"();\n"; + + m_os<<"\tconst "; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<" &get_"<cpp_name()<<" () const ; \n"; + }else + { + m_os<<"// Complex reference "<name()<cpp_name()<<"(const "; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<" *s);\n"; + m_os<<"\t"; + m_gencpp.gen_composite_attribute_ref(m_os,scope,attribute,params); + m_os<<"* get_"<cpp_name()<<"();\n"; + + } + } + break; + default: + { + std::string strtype; + if (m_gencpp.type2cppstring(attr_type,strtype) ) + { + m_os<<"\tvoid set_"<cpp_name()<<"(const "; + m_os<cpp_name()<<" () ;\n"; + m_os<<"\tconst "<cpp_name()<<" () const;\n"; + } else + { + assert(0); + } + } + break; + } + } else + { + GEN_LOG_ERROR("attr_type is NULL\n"); + } +} + +/** + * + */ +void cghpph_choice::gen_enum_type() +{ + asn1::choice *type = &m_choice; + // Now add an enum to identifie type + + m_os<<"\tenum { "<begin(); + + for (; lit != (type)->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + asn1::typenode *attribute_type = f->get_type(); + if (f->is_extensible()) + continue; + if (attribute_type && attribute_type->tagged()) + { + /* tagged */ + m_os<<"\t\ttypeof_"<<(*lit)->cpp_name(); + if (m_gencpp.is_tag_explicit(*attribute_type) ) + { + m_os<<"\t="<tag().get_tag()<<", "; + m_os<<" // Explicit + "<<(int)attribute_type->tag().byte(); + } else + { + m_os<<"\t="<tag().get_tag()<<", "; + m_os<<" // Implicit + "<<(int)attribute_type->tag().byte(); + } + m_os<type_id()() == asn1::type::ASN1_REFERENCE) + { + /* reference type */ + std::listlst; + m_gencpp.reference_chaine(attribute_type->as_typeref(),lst); + + if ((lst.size() > 0) && lst.back() != NULL) + { + if (lst.back()->tag().m_value >= 0) + { + m_os<<"\t\ttypeof_"<<(*lit)->cpp_name(); + if (m_gencpp.is_tag_explicit(* dynamic_cast(lst.back())) ) + { + m_os<<"\t="<tag().get_tag()<<", "; + m_os<<" // Explicit "<<(int)lst.back()->tag().byte(); + } else + { + m_os<<"\t="<tag().get_tag()<<", "; + m_os<<" // Implicit "<<(int)lst.back()->tag().byte(); + } + m_os<<", /*ref tag*/"<cpp_name()<<", "; + m_os<<"// ref type no tag "<name()<cpp_name()<<",/*ext ref missing*/ "<tag().m_value > 0) + { + m_os<<"\t\ttypeof_"<<(*lit)->cpp_name()<<"\t="<tag().get_tag()<<" ,"; + m_os<<"// m_value > 0"; + m_os<cpp_name()<<",/*no tag */ "<cpp_name()<<", "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_os<<"<>"; + } + m_os<<"(std::ostream &os,const "; + m_os<<""<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<")"; + m_os<<";\n"; +} + +// generate codec part +void cghpph_choice::generate_per() +{ +} + +// +void cghpph_choice::generate_ber() +{ + std::string scope; + asn1::node *type = &m_choice; + + if ( m_gencpp.with_ber() + && m_choice.tagged() + && m_gencpp.is_tag_explicit(m_choice) ) + { + m_os<<"\tvirtual void encode_ber(asn1::streams::ber &ctx);"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgcpp_helper.h" +#include "cghpph_classdef.h" +#include "asn1_visitor.h" + + +cghpph_classdef::cghpph_classdef(generate_header &g,std::ostream &os,asn1::classdef &s) + : m_Gen(g) + , generator_helper(os) + , m_classdef(s) + , m_log(g.logger()) +{ +} + +cghpph_classdef::~cghpph_classdef() +{ +} + + +struct gen_iattr : public node_visitor +{ + std::string fieldname; + bool m_istemplate; // Use same generator for template + gen_iattr( std::ostream &os,generate_header &h,bool _istplt=false) + : m_os(os) , m_Gen(h),m_istemplate(_istplt) + { + } + void operator ()(asn1::node *n) + { + fieldname = n->cpp_name(); + fieldname[0] = '_'; + visit(n); + } +#define ASN1_CLASSFIELD_TYPE(cls,code) \ + void visit_##cls(asn1::cls *f) code + +ASN1_CLASSFIELD_TYPE(classfield_tf,{ + if (!m_istemplate) + return ; + //m_os<<" type "<cpp_name()<get_type(),strtype); + m_os<<"\t\t"<get_type()->cpp_name()<<">\t"<identifier()<cpp_name(); + + /** + * + */ + m_Gen.gen_object_class_missing(m_os,type); + // + // + gen_interface(); + + gen_objectset(); + + if (std::string("ERROR").compare(n->cpp_name()) == 0) + { + m_os<<"#ifdef ERROR\n"; + m_os<<"#undef ERROR\n"; + m_os<<"#endif\n"; + } + // + // + gen_template(); +} + + +/** + * Helper to travers class fields in template ... + */ +class cghcdtplt : public node_visitor +{ + protected: + std::ostream &m_os; + generate_header &m_gen; + std::string fieldname; + std::fstream &m_log; + public: + cghcdtplt(std::ostream &_os,generate_header &h) + : m_os(_os),m_gen(h),m_log(h.logger()) + {} + + // used by foreach + void operator ()(asn1::node *n) + { + fieldname = n->cpp_name(); + fieldname[0] = '_'; + m_os<<"\t// "<cpp_name()<<" type_id="<type_id()(); + visit(n); + } +#define ASN1_CLASSFIELD_TYPE(cls,code) \ + void visit_##cls(asn1::cls *f) code + +ASN1_CLASSFIELD_TYPE(classfield_tf,{ + + m_os<<"\n\t//getter \n"; + m_os<<"\tint get"<flags().is_optional() ) + { + m_os<<"\t\treturn m.present"<flags().is_optional() ) + { + m_os<<"\t\tmemset(&m,0x00,sizeof(struct _present)); \n"; + m_os<<"\t\tm.present"<cpp_name()<<"::decode"<flags().is_optional() ) + m_os<<"\t\tm.present"<cpp_name(); + m_os<<"::decode"<flags().is_optional() ) + m_os<<"\t\tif (m.present"<identifier()<cpp_name(); + + m_Gen.gen_object_class_tplt(m_os,type); + m_os<<"struct "<cpp_name()<<" : public I"<cpp_name()<<"\n{\n"< ptr; + m_os<<"\ttypedef asn1::intrusive_ptr<"<cpp_name(); + m_Gen.gen_object_class_tplt_params(m_os,type); + m_os<<" > ptr;\n"; + m_os<<"\ttypedef "<cpp_name(); + m_Gen.gen_object_class_tplt_params(m_os,type); + m_os<<" otype;\n"; + m_os<<"\ttypedef "<cpp_name(); + m_Gen.gen_object_class_tplt_params(m_os,type); + m_os<<" & otype_reference;\n"; + // constructors + m_os<<"\t"<cpp_name()<<"()\n\t{\n\t\t/*never called */\n"; + m_os<<"\t};\n"; + // Missing copy constructor + //m_os<<"\t"<cpp_name()<<""; + m_os<<"\t"<cpp_name()<<"(const "<cpp_name()<<""; + m_Gen.gen_object_class_tplt_params(m_os,type); + m_os<<" &o);"<cpp_name()<<"()\n\t{};\n"; + + //m_os<<"\tvirtual I"<cpp_name()<<" *Create()\n\t{\n"; + m_os<<"\tstatic otype *Create()\n\t{\n"; + if (m_Gen.with_source_debug()) + { + m_os<<"\t\tASN1_BER_LOG_DEBUG(\"Create "; + m_os<cpp_name()<<" %s\",typeid(this).name());\n"; + } + m_os<<"\t\totype *o = new otype"; + m_os<<"();\n"; + if (has_optional()) + m_os<<"\t\tmemset(&o->m,0x00,sizeof(struct _present)) ;\n"; + m_os<<"\t\treturn o;\n\t};\n"; + + m_os<<"\totype_reference"; + m_os<<"\toperator =(asn1::Object &_c)\n\t{\n"; + + if (m_Gen.with_source_debug()) + { + m_os<<"\t\tASN1_BER_LOG_DEBUG(\" "<cpp_name()<<" operator %s = %s\"\n"; + m_os<<"\t\t\t\t\t,typeid(this).name()\n"; + m_os<<"\t\t\t\t\t,typeid(_c).name());\n"; + } + m_os<<"\t\treturn *this;\n"; + m_os<<"\t};\n"; + + m_os<<"\tvirtual otype *clone() const\n\t{\n"; + if (m_Gen.with_source_debug()) + m_os<<"\t\tASN1_BER_LOG_DEBUG(\"Clone "<cpp_name()<<"\");\n"; + m_os<<"\t\treturn new otype(*this);\n\t}\n"; + // generate optionnals + gen_printf(); + // + cghcdtplt cga(m_os,m_Gen); + for_each( m_classdef.begin() + , m_classdef.end() + , cga); + + m_os<<"\tprotected:\n"; + + for_each( m_classdef.begin() + , m_classdef.end() + , gen_iattr(m_os,m_Gen,true)); + m_os<<"};\n"<parameters(); + /* + * Try to handler sequence of sequence + */ + it = type->begin(); + + structName = ident->cpp_name(); + if (m_Gen.with_source_comment()) + m_os<<"\t// display function\n"; + m_os<<"\tvirtual void printf(std::ostream &os) const\n\t{\n"; + for ( ; it != type->end(); ++it) + { + asn1::node *ltype = (*it); + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + + switch(ltype->type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_TF: /* Type Field */ + if ( (ltype->flags().m_flags & asn1::node::marker_type::FL_OPTIONAL) ) + { + m_os<<"\t\tif (m.present"<cpp_name(); + m_os<<" : \"<begin(); + std::string structName = ident->cpp_name(); + + m_os<<"\n//\n// Objectset struct\n//\n"; + m_os<<"struct "< +{ + protected: + std::ostream &m_os; + std::string fieldname; + generate_header &m_gen; + public: + cghcditf(std::ostream &_os,generate_header &h) + : m_os(_os),m_gen(h) + {} + // used by foreach + void operator ()(asn1::node *n) + { + std::string fieldname = n->cpp_name(); + fieldname[0] = '_'; + visit(n); + } +#define ASN1_CLASSFIELD_TYPE(cls,code) \ + void visit_##cls(asn1::cls *f) code + +ASN1_CLASSFIELD_TYPE(classfield_tf,{ + fieldname = f->cpp_name(); + fieldname[0] = '_'; + m_os<<"\t// "<cpp_name()<<" type_id="<type_id()(); + m_os<<" type "<cpp_name()<cpp_name(); + fieldname[0] = '_'; + asn1::typenode *ftvf_type = f->get_type(); + std::string strtype; + m_gen.type2cppstring(ftvf_type,strtype); + m_os<cpp_name(); + fieldname[0] = '_'; + m_os<get_type()->cpp_name()<<"> &get"; + m_os<begin(); +std::string structName = ident->cpp_name(); + +m_os<<"\n//\n// Interface I"< ptr;\n"; +m_os<<"\tI"<"; + m_os<<" I"<type_id()() == asn1::type::ASN1_CLASSFIELD_TF) + { + should = true; + break; + } + } + return should; +} + + +/** + * + */ +bool cghpph_classdef::has_optional() +{ + return m_classdef.opt_size() > 0; +} + +/** + * + */ +void cghpph_classdef::gen_optional() +{ + asn1::node *ident = m_classdef.identifier(); + asn1::classdef *type = &m_classdef; + asn1::node::iterator it = (type)->begin(); + bool opt = false; + std::list l; + + for ( ; it != type->end(); ++it) + { + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + if ( ((*it)->flags().m_flags & asn1::node::marker_type::FL_OPTIONAL) ) + { + l.push_back(fieldname); + } + } + + if ( l.size() > 0 ) + { + m_os<<"\tstruct _present\n\t{\n"; + for (std::list::const_iterator it = l.begin() + ; it != l.end() + ; ++it) + { + m_os<<"\t\tunsigned present"<<(*it)<<" : 1;\n"; + } + m_os<<"\t} m;\n"; + } +} + +/** + * vim: et sw=2 ts=2 list: + */ diff --git a/libgen/cpp/cghpph_classdef.h b/libgen/cpp/cghpph_classdef.h new file mode 100644 index 0000000..67b37f3 --- /dev/null +++ b/libgen/cpp/cghpph_classdef.h @@ -0,0 +1,56 @@ +#ifndef CGHPPH_CLASSDEF_H +#define CGHPPH_CLASSDEF_H + + +/** + * + */ +class cghpph_classdef : public generator_helper +{ + protected: + cghpph_classdef(const cghpph_classdef &s) : generator_helper(s.m_os) + , m_log(s.m_log) + , m_Gen(s.m_Gen) + , m_classdef(s.m_classdef) {} + public: + cghpph_classdef(generate_header &g,std::ostream &os,asn1::classdef &s) ; + ~cghpph_classdef(); + + // Helper functions + virtual void generate() ; + + // generate codec part + virtual void generate_per() ; + // + virtual void generate_ber() ; + // + virtual void generate_oer() ; + // + virtual void generate_jer() ; + // + virtual void generate_xer() ; + protected: + void gen_printf(); + // loop over the attributes of SEQUENCE or CHOICE + // and check if there are some type of SEQUENCE or CHOICE + // launch generation for these types first. + void gen_interface(); + + void gen_template(); + // + // Gen Optional structure + void gen_optional(); + // Are there optional attributes ? + bool has_optional(); + // Generate structure for ObjectSet of this class type + void gen_objectset(); + // Test If need to generate code for this class + // If there are no FT, probably not + bool should_generate(); + protected: + std::fstream &m_log; + generate_header &m_Gen; + asn1::classdef &m_classdef; +}; + +#endif diff --git a/libgen/cpp/cghpph_enumerated.cpp b/libgen/cpp/cghpph_enumerated.cpp new file mode 100644 index 0000000..6c5ecf3 --- /dev/null +++ b/libgen/cpp/cghpph_enumerated.cpp @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_generator_helper.h" +#include "cghpp_helper.h" +#include "cgh_hconstruct.h" +#include "cghpph_enumerated.h" + +#undef GEN_LOG_DEBUG +#define GEN_LOG_DEBUG + +cghpph_enumerated::cghpph_enumerated(generate_header &g,std::ostream &os,asn1::enumerated &s) + : cgh_hconstruct(g,os,s) , m_enumerated(s) +{ +} + +cghpph_enumerated::~cghpph_enumerated() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_enumerated::generate() +{ + cgh_hconstruct::generate( ); +} + +/** + * + */ +void cghpph_enumerated::generate_prolog( ) +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_enumerated helper launched private "<value(); + if (it != m_enumerated.begin() ) + m_os<<",\n"; + m_os<<"\t\t"<<(*it)->cpp_name()<<" "; + + if ( num != NULL) + { + m_os<<" = "<<(num)->m_integer; + } + } + m_os<<"\n"<<"\t};\n"; +} + +/** + * + */ +void cghpph_enumerated::generate_operators( ) +{ + m_os<<"\t"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgcpp_helper.h" +#include "cghpph_import.h" + + +cghpph_import::cghpph_import(generate_header &g,std::ostream &os,asn1::import &s) + : m_Gen(g) + , generator_helper(os) + , m_import(s) + , m_log(g.logger()) +{ +} + +cghpph_import::~cghpph_import() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_import::generate() +{ + asn1::node::iterator items,end; + + m_os<<"// cghpph_import helper launched "<identifier_cpp_name()<<"/"<<(*items)->cpp_name()<<".h\" /*item "<<(*items)->name()<<"*/\n"; + if (std::string("OPERATION").compare((*items)->name()) == 0 ) + { + m_os<<"#include \"rtasn1/asn1_rose.h\"\n"; + } + } + if (std::string("Remote-Operations-Useful-Definitions") + .compare(m_import.identifier()->name())) + m_os<<"#include \""<cpp_name()<<".h\"\n"; + + gen_forward_decl(); +} + +// +void cghpph_import::gen_printf(const std::string &_scope) +{ + std::string structName; + std::string scope(""); + asn1::node::iterator lit; + asn1::node *type = &m_import; + + +} + +// generate codec part +void cghpph_import::generate_per() +{ + std::string scope; + // +} + +// +void cghpph_import::generate_ber() +{ + std::string scope; + asn1::node *type = &m_import; + // +} + +// +void cghpph_import::generate_oer() +{ + // + std::string scope; +} + +// +void cghpph_import::generate_jer() +{ +} + +// +void cghpph_import::generate_xer() +{ +} + +/** + * private structures are generated before the current on. + * outside the scope of the current type. + * This code could be factorized and generator level + */ +void cghpph_import::gen_private() +{ + asn1::node *type = &m_import; +} +/** + * + */ +void cghpph_import::gen_forward_decl() +{ + asn1::node::iterator items,end; + + items = m_import.begin(); + end = m_import.end(); + m_os<<"namespace "<cpp_name()<<" {\n"; + // Loop over items and check if OPERATION is imported + for ( items = m_import.begin() + ; items != end + ; ++items) + { + asn1::node *type = NULL; + asn1::typeref *ref = dynamic_cast(*items); + if (ref) + { + type = m_Gen.resolver().resolve(*ref); + if (type) + { + switch(type->type_id()()) + { + case asn1::type::ASN1_BIT_STRING : + case asn1::type::ASN1_SET : + case asn1::type::ASN1_SEQUENCE : + if (type->identifier()->parameters()) + { + m_os<<"// type "<type_id()()<<" with param\n"; + } else + m_os<<"class "<cpp_name()<<";// type "<type_id()()<<"\n"; + break; + case asn1::type::ASN1_OBJECTSET: + { + asn1::objectset *objs = dynamic_cast(type); + asn1::typeref *cref = objs->get_classref(); + m_os<<"// object set "<name()<<" cref="<name()<cpp_name()<<" **"<name()<<";"<(type); + asn1::typeref *cref = objs->get_classref(); + m_os<<"// WRONG value set "<name()<<" its objs cref="; + m_os<name()<cpp_name()<<" **"<name()<<";"<(type); + if (type->type_node()) + { + std::cerr<<"// IMPORT TODO type "<name()<<" "<type_node()->cpp_name()<name()<<";"; + m_os<<"// type "<type_id()()<<"\n"; + } else if (type->identifier() && type->identifier()->parameters()) + { + m_os<<"// type "<type_id()()<<" with param\n"; + } else if (real_ref && real_ref->is_objectclass()) + { + m_os<<"// type "<type_id()()<<" object class\n"; + } else + m_os<<"class "<cpp_name()<<";// type "<type_id()()<<"\n"; + } + break; + case asn1::type::ASN1_INTEGER : + if (type->meta_id()() != asn1::meta::TYPE) + { + break; + } + case asn1::type::ASN1_CHOICE : + case asn1::type::ASN1_OCTET_STRING : + case asn1::type::ASN1_ENUMERATED: + m_os<<"struct "<cpp_name()<<";\n"; + break; + case asn1::type::ASN1_CLASSDEF : + { + std::string cls = type->identifier()->cpp_name(); + m_os<<"#ifndef TEMPLATE_CLASS_"<identifier()->cpp_name()) == 0) + { + m_os<<"#ifdef ERROR\n"; + m_os<<"#undef ERROR\n"; + m_os<<"#endif\n"; + } + m_os<<"class I"<identifier()->cpp_name()<<";// id="<type_id()()<<"\n"; + m_os<<"\n"; +#if 0 + m_Gen.gen_object_class_tplt(m_os,type->identifier()); + m_os<<"class "<identifier()->cpp_name()<<";\n"; +#endif + m_os<<"#endif\n"; + } + break; + default: + //m_os<<"class "<identifier_cpp_name()<<";"; + m_os<<"//default FOUND "<name()<<" id="<type_id()()<<"\n"; + ; + } + } else + { + m_os<<"//NOT FOUND "<name()<<"\n"; + } + } else + { + m_os<<"//NOT FOUND not typeref "<<(*items)->name()<<"\n"; + } + + // Resolve symbol to figure out the kind. + if (std::string("OPERATION").compare((*items)->name()) == 0 ) + { + } + } + m_os<<"}\n"; +} diff --git a/libgen/cpp/cghpph_import.h b/libgen/cpp/cghpph_import.h new file mode 100644 index 0000000..16409ce --- /dev/null +++ b/libgen/cpp/cghpph_import.h @@ -0,0 +1,43 @@ +#ifndef CGHPPH_IMPORT_H +#define CGHPPH_IMPORT_H + + +/** + * + */ +class cghpph_import : public generator_helper +{ + protected: + cghpph_import(const cghpph_import &s) : generator_helper(s.m_os) + , m_Gen(s.m_Gen) + , m_log(s.m_log) + , m_import(s.m_import) {} + public: + cghpph_import(generate_header &g,std::ostream &os,asn1::import &s) ; + ~cghpph_import(); + + // Helper functions + virtual void generate() ; + + void gen_printf(const std::string &scope); + // generate codec part + virtual void generate_per() ; + // + virtual void generate_ber() ; + // + virtual void generate_oer() ; + // + virtual void generate_jer() ; + // + virtual void generate_xer() ; + protected: + void gen_private(); + // + void gen_forward_decl(); + protected: + std::fstream &m_log; + generate_header &m_Gen; + asn1::import &m_import; +}; + +#endif diff --git a/libgen/cpp/cghpph_integer.cpp b/libgen/cpp/cghpph_integer.cpp new file mode 100644 index 0000000..a74a82a --- /dev/null +++ b/libgen/cpp/cghpph_integer.cpp @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cgh_hconstruct.h" +#include "cghpph_integer.h" + + +cghpph_integer::cghpph_integer(generate_header &g,std::ostream &os,asn1::integer &s) + : cgh_hconstruct(g,os,s) , m_integer(s) +{ +} + +cghpph_integer::~cghpph_integer() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_integer::generate() +{ + GEN_LOG_DEBUG("INTEGER type %s ident=%s size=%ld\n" + , m_integer.name().c_str() + , m_integer.identifier_name().c_str() + , m_integer.size()); + cgh_hconstruct::generate(); +} + +/** + * + */ +void cghpph_integer::generate_prolog( ) +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_integer helper launched "< 0) + { + asn1::node::iterator it = m_integer.begin(); + m_os<<"\tenum e"<(*it); + assert (tv != NULL); + if (it != m_integer.begin() ) + { + m_os<<"\t\t,"; + } else + m_os<<"\t\t"; + + m_os<<(*it)->cpp_name()<<" = "<value_long()<<"\n"; + } + m_os<<"\t};\n"; // end of enum + m_os<<"\tbool operator ==(const e"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgcpp_helper.h" +#include "cgh_object.h" +#include "cghpph_object.h" + +#undef GEN_LOG_DEBUG +#define GEN_LOG_DEBUG + +cghpph_object::cghpph_object( generate_header &g + , std::ostream &os + , asn1::object &s + , asn1::classdef &cdef) + : m_Gen(g) + , cgh_object(g,os,s,cdef) + //, m_object(s) + //,m_classdef(cdef) +{ +} + +cghpph_object::~cghpph_object() +{ +} + + +/** + * Helper functions + * + */ +void cghpph_object::generate() +{ + asn1::node *n = m_object.identifier(); + asn1::node *type = &m_object; + asn1::node *params = NULL; + std::string structName; + + //m_os<<"\n//\n// cghpph_object helper launched "<name()<name()<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<">;\n"; +#endif +} + +/** + * Helper functions + * + */ +void cghpph_object::generate_hpp() +{ + asn1::node *n = m_object.identifier(); + asn1::node *type = &m_object; + asn1::node *params = NULL; + std::string structName; + + m_os<<"\n//\n// cghpph_object helper launched "<name()<cpp_name()<<" {\n"; + m_os<<"template <>\n"; + m_os<::"<cpp_name()<<"\n{\n"; + + m_os<<"template <>\n"; + m_os<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<">::"<cpp_name()<<"();\n"; + // Instanciate copy ctor + m_os<<"template <>\n"; + m_os<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<">::"<cpp_name()<<"(const "; + m_os<cpp_name(); + m_os<<"<"; + gen_template_args(true); + m_os<<"> &o);\n"; + + m_os<<"}\n"; // Close template namespace + } + + // typedef instantiates the template + m_os<<"namespace "<cpp_name()<<"\n{\n"; + m_os<<"typedef "; + if (m_classdef.get_parent() == m_Gen.get_module() ) + { + m_os<(m_classdef.get_parent()); + m_os<cpp_name(); + m_os<<"::"<cpp_name()<<"<"; + } + // To check for CMIP + gen_template_args(true); + m_os<<"> "<cpp_name()<<";"<name()<type_id()() == asn1::type::ASN1_CLASSFIELD_TF ) + { + asn1::node *type = NULL; + if ( (type = m_object.get_field((*fit)->name()) ) != NULL) + { + if (type->get_parent() == m_Gen.get_module()) + m_os<<"struct "<cpp_name()<<";"<type_id()() == asn1::type::ASN1_CLASSFIELD_TF ) + { + asn1::node *type = NULL; + if ( (type = m_object.get_field((*fit)->name()) ) != NULL) + { + asn1::typeref *ref = dynamic_cast(type); + asn1::node *rtype = NULL; + if(ref) + { + rtype = m_Gen.resolver().resolve(*ref); + } else + { + std::cerr<<"cghpph_object::gen_private type= "; + std::cerr<name()<<" NOT TYPEREF\n"; + } + if (rtype && rtype->get_parent() == m_Gen.get_module()) + m_Gen.gen_missing(m_os,rtype->identifier()); + } + } + } +} diff --git a/libgen/cpp/cghpph_object.h b/libgen/cpp/cghpph_object.h new file mode 100644 index 0000000..8909716 --- /dev/null +++ b/libgen/cpp/cghpph_object.h @@ -0,0 +1,53 @@ +#ifndef CGHPPH_OBJECT_H +#define CGHPPH_OBJECT_H + + +/** + * + */ +class cghpph_object : public cgh_object +{ + protected: + cghpph_object(const cghpph_object &s ) + : cgh_object(s.m_Gencpp,s.m_os,s.m_object,s.m_classdef) + , m_Gen(s.m_Gen) + //, m_object(s.m_object) + //, m_classdef(s.m_classdef) + {} + public: + cghpph_object(generate_header &g,std::ostream &os,asn1::object &s,asn1::classdef &cdef) ; + + ~cghpph_object(); + + // Helper functions + virtual void generate() ; + + void generate_hpp() ; + + void gen_printf(const std::string &scope); + // generate codec part + virtual void generate_per() ; + // + virtual void generate_ber() ; + // + virtual void generate_oer() ; + // + virtual void generate_jer() ; + // + virtual void generate_xer() ; + + // loop over the attributes of SEQUENCE or CHOICE + // and check if there are some type of SEQUENCE or CHOICE + // launch generation for these types first. + void gen_private(); + protected: + void gen_forward(); + // Generate template arguments for object + //void gen_template_args(bool with_scope=false); + protected: + generate_header &m_Gen; + //asn1::object &m_object; + //asn1::classdef &m_classdef; +}; + +#endif diff --git a/libgen/cpp/cghpph_octetstring.cpp b/libgen/cpp/cghpph_octetstring.cpp new file mode 100644 index 0000000..0d56381 --- /dev/null +++ b/libgen/cpp/cghpph_octetstring.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cghpph_primitive.h" +#include "cghpph_octetstring.h" + + +cghpph_octet_string::cghpph_octet_string(generate_header &g,std::ostream &os,asn1::octet_string &s) + : cghpph_primitive(g,os,s) , m_octet_string(s) +{ +} + +cghpph_octet_string::~cghpph_octet_string() +{ +} + + +/** + * + */ +void cghpph_octet_string::generate_prolog() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_octet_string helper launched "< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cgh_hconstruct.h" +#include "cghpph_oid.h" + + +cghpph_oid::cghpph_oid(generate_header &g,std::ostream &os,asn1::object_identifier &s) + : cgh_hconstruct(g,os,s) + , m_oid(s) +{ +} + +cghpph_oid::~cghpph_oid() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + */ +void cghpph_oid::generate() +{ + cgh_hconstruct::generate( ); +} + +/** + * + */ +void cghpph_oid::generate_prolog() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_oid helper launched "<parameters(); + /* + * Try to handler sequence of sequence + */ + + if (m_oid.is_private()) + { + structName = type->cpp_name(); + } else + structName = ident->cpp_name(); + + m_os<<"\tfriend std::ostream &operator <<(std::ostream &os,const "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<") ;\n"; +} + +// generate codec part +void cghpph_oid::generate_per() +{ +} + +// +void cghpph_oid::generate_ber() +{ + std::string scope; + asn1::node *type = &m_oid; + // + if ( m_oid.tagged() + && m_gencpp.is_tag_explicit(m_oid) ) + { + m_os< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cghpph_primitive.h" + + +cghpph_primitive::cghpph_primitive( generate_header &g + , std::ostream &os + , asn1::primitive &s) + : cghpp_helper(g,os) + , m_primitive(s) + , m_structName("") +{ + + assert(m_primitive.type_id()() >= asn1::type::ASN1_ANY + && m_primitive.type_id()() < asn1::type::ASN1_STRING_ObjectDescriptor ); + if (m_primitive.is_private()) + { + m_structName = s.cpp_name(); + } else + m_structName = s.identifier_cpp_name(); + +} + +cghpph_primitive::~cghpph_primitive() +{ +} + +void cghpph_primitive::generate_prolog() +{ + assert(m_primitive.type_id()() >= asn1::type::ASN1_ANY + && m_primitive.type_id()() < asn1::type::ASN1_STRING_ObjectDescriptor ); + + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_primitive helper launched "<parameters(); + /* + * Try to handler sequence of sequence + */ + m_os<<"\tfriend std::ostream &operator <<(std::ostream &os,const "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<") ;\n"; + + +} + +// generate codec part +void cghpph_primitive::generate_per() +{ +} + +// +void cghpph_primitive::generate_ber() +{ + // + if (m_primitive.tagged()) + { + if ( m_gencpp.is_tag_explicit(m_primitive)) + { + // + m_os<<"\tvirtual void encode(asn1::context &ctx);"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cghpph_primitive.h" +#include "cghpph_real.h" + + +cghpph_real::cghpph_real(generate_header &g,std::ostream &os,asn1::real &s) + : cghpph_primitive(g,os,s) + , m_real(s) +{ +} + +cghpph_real::~cghpph_real() +{ +} + + +/** + * + */ +void cghpph_real::generate_prolog() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_real helper launched "<parameters(); + /* + * Try to handler sequence of sequence + */ + + m_os<<"\tfriend std::ostream &operator <<(std::ostream &os,const "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<");"; + m_os<<"\n"; +} + +// generate codec part +void cghpph_real::generate_per() +{ +} + +// +void cghpph_real::generate_ber() +{ + // + if (m_real.tagged()) + { + if ( m_gencpp.is_tag_explicit(m_real)) + { + // + m_os<<"\tvirtual void encode(asn1::context &ctx);"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cgh_hconstruct.h" +#include "cghpph_sequence.h" + + +cghpph_sequence::cghpph_sequence(generate_header &g,std::ostream &os,asn1::sequence &s) + : cgh_hconstruct(g,os,s) + , m_seq(s) +{ +} + +cghpph_sequence::~cghpph_sequence() +{ +} + + +/** Helper functions + * + * It seems that the sequence does not always have an identifier. Examples + * - SEQUENCE OF SEQUENCE {} + * - Test ::= CHOICE { toto INTEGER, SEQUENCE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_sequence::generate() +{ + if ( ! m_gencpp.add_symbol(m_structName,&m_seq) ) + { + m_os<<"// Structure already in map, skip\n"; + return; + } + + cgh_hconstruct::generate(); + + if (m_gencpp.with_source_comment()) + m_os<<"/* end cghpph_sequence "<parameters() : NULL; + + if (m_gencpp.with_source_comment()) + { + m_os<<"\n//\n// cghpph_sequence helper launched "; + m_os<parameters() + && m_gencpp.is_template(n->parameters()) ) + { + // forward declaration + m_os<<"template "; + m_gencpp.gen_template_signature(m_os,params); + m_os<<" struct "<begin(); p != params->end() ;++p) + { + if (p != params->begin()) + m_os<<","; + m_os<<"typename "<<(*p)->cpp_name(); + } + m_os<<"> "<parameters() : NULL; + + // Constructor + if (m_seq.tagged() ) + { + if ( ! m_gencpp.is_tag_explicit(m_seq) ) + { + asn1::node::tag_type tg = m_seq.tag(); + m_os<<"\t"<parameters() : NULL; + // Attribute Members + if (m_gencpp.with_source_comment()) + { + m_os<<"\t//Member attributes\n"; + } + for ( asn1::node::iterator lit = m_seq.begin() + ; lit != m_seq.end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + m_gencpp.gen_composite_attribute( m_os,scope,*f + , (n != NULL)?n->parameters():NULL); + } + + m_os<<"\n"; + // For PARAMETERS ObjectSet CLASSES generates + gen_members( ); + // + gen_optionals(); +} + + +/** + * See If there is a way to have a common class + * for this + * If I'm private, I also need to get parameters from parent classes example + * ReturnResult {OPERATION:Operations} ::= { + * result ::= sequence { + * + * } + * } + */ +void +cghpph_sequence::gen_members() +{ + std::set parameterset; + asn1::node *ident = m_seq.identifier(); + asn1::parameters *params = dynamic_cast(ident->parameters()); + /* Collect all parameters */ + asn1::node::node_list lst; + m_seq.path2module(lst); + for (asn1::node::iterator lit = lst.begin() + ; lit != lst.end() + ; ++lit) + { + if ( (*lit)->identifier() && (*lit)->identifier()->parameters()) + { + asn1::parameters *_p = dynamic_cast( (*lit)->identifier()->parameters()); + parameterset.insert(_p->begin(),_p->end()); + } + } + if (params) + { + parameterset.insert(params->begin(),params->end()); + } + /**/ + if ( parameterset.size() >0 ) + { + for (std::set::iterator it = parameterset.begin(); + it != parameterset.end(); + ++it) + { + asn1::parameter *p = dynamic_cast(*it); + if (asn1::node *g = p->get_governor()) + { + asn1::typeref *objr = dynamic_cast(g); + if (objr) + { + asn1::node *obj = m_gencpp.resolver().resolve(*objr); + asn1::module *m = dynamic_cast(obj->get_parent()); + m_os<<"\t// "<name()<<" "<name()<is_simple()) + { + m_os<<"\t"<cpp_name()<<"::I"<name()<<" **"<name()<<";"<name()<<" "<name()<parameters() :NULL; +#if 0 + if (n != NULL) + { + if (m_seq.is_private()) + { + structName = m_seq.cpp_name(); + } else + structName = n->cpp_name(); + params = n->parameters(); + } else + { + // Anonymous structure + structName = m_seq.cpp_name(); + } +#endif + m_os<<"\tvirtual void printf(std::ostream &os) const;\n"; + + m_os<<"\tfriend std::ostream &operator << "; + if (params && m_gencpp.is_template(params)) + m_os<<" <>"; + m_os<<"(std::ostream &os,const "; + m_os<parameters() && m_gencpp.is_template(n->parameters())) + { + m_gencpp.gen_template_params(m_os,n->parameters()); + } + m_os<<" &s"<<")"; + m_os<<";\n"; +} + + +/** + * + */ +void cghpph_sequence::generate_ber() +{ + std::string scope; + // + m_os<<"\tvirtual void encode(asn1::context &ctx);"< 0) + { + i++; l = l / 8; + } + if (i == 0) + return; + m_os<<"\n\t//Optional bit mask "<\tbit_mask;\n"; + m_os<<"\tenum {\n"; + for ( asn1::sequence::OptionalIterator it = m_seq.opt_begin() + ; it != m_seq.opt_end() + ; ++it) + { + m_os<<"\t\t"; + if (it != m_seq.opt_begin()) + m_os<<","; + m_os<<(*it)->cpp_name()<<"_present\t = "< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgcpp_helper.h" +#include "cghpph_sequenceof.h" + + +cghpph_sequenceof::cghpph_sequenceof( generate_header &g + , std::ostream &os + , asn1::sequence_of &s) + : m_Gen(g) + , generator_helper(os) + , m_seqof(s) + , m_log(g.logger()) +{ +} + +cghpph_sequenceof::~cghpph_sequenceof() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_sequenceof::generate() +{ + asn1::node *ns = NULL; + asn1::node *type = &m_seqof; + asn1::typenode *seqof_type = m_seqof.get_eltype(); + asn1::node *params = NULL; + std::string structName,eltype; + std::string scope(""); + + if (m_Gen.with_source_comment()) + m_os<<"// cghpph_sequenceof helper launched "<cpp_name() + "::" + seqof_type->cpp_name(); + } else + eltype = seqof_type->cpp_name(); + m_os<<"struct "<\n{\n"; + + // + // Initial ctor + m_os<<"\t"<::operator =(c); return *this; };\n"; + generate_ber(); + // equal operator + m_os<parameters(); + /* + * Try to handler sequence of sequence + */ + + if (m_seqof.is_private()) + { + structName = type->cpp_name(); + } else + structName = ident->cpp_name(); + + m_os<parameters() && m_Gen.is_template(ident->parameters())) + { + m_Gen.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<") ;\n"; + + +} + +// generate codec part +void cghpph_sequenceof::generate_per() +{ + std::string scope; + // + m_os< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cgh_hconstruct.h" +#include "cghpph_set.h" + + + +/** + * + */ +cghpph_set::cghpph_set(generate_header &g,std::ostream &os,asn1::set &s) + : cgh_hconstruct(g,os,s) + , m_set(s) +{ +} + +cghpph_set::~cghpph_set() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_set::generate() +{ + cgh_hconstruct::generate() ; +} + +/** + * + */ +void cghpph_set::generate_prolog( ) +{ + if (m_gencpp.with_source_comment() ) + m_os<<"// cghpph_set helper launched "<(*it); + m_gencpp.gen_composite_attribute(m_os,scope,*f,(n != NULL)?n->parameters():NULL); + m_os<<"\n"; + } +} + +/** + * + */ +void cghpph_set::generate_printf( ) +{ + asn1::node::iterator lit; + asn1::node *ident = m_set.identifier(); + asn1::constructed *params = ident->parameters(); + /* + * Try to handler sequence of sequence + */ + lit = m_set.begin(); +#if 0 + if (m_set.is_private()) + { + structName = type->cpp_name(); + } else + structName = ident->cpp_name(); +#endif + m_os<<"\tfriend std::ostream &operator <<(std::ostream &os,const "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<" ) ;"; + +} + +// generate codec part +void cghpph_set::generate_ber() +{ + // + m_os<<"\tvirtual void encode(asn1::context &ctx);"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cgcpp_helper.h" +#include "cghpph_setof.h" + + +cghpph_setof::cghpph_setof( generate_header &g + , std::ostream &os + , asn1::set_of &s) + : m_Gen(g) + , generator_helper(os) + , m_setof(s) + , m_log(g.logger()) +{ +} + +cghpph_setof::~cghpph_setof() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_setof::generate() +{ + asn1::node *ns = NULL; + asn1::node *type = &m_setof; + asn1::typenode *setof_type = m_setof.get_eltype(); + asn1::node *params = NULL; + std::string structName,eltype; + std::string scope(""); + + if (m_Gen.with_source_comment()) + m_os<<"// cghpph_setof helper launched "<cpp_name() + "::" + setof_type->cpp_name(); + } else + eltype = setof_type->cpp_name(); + m_os<<"struct "<\n{\n"; + + // + // Initial ctor + m_os<<"\t"<::operator =(c); return *this; };\n"; + generate_ber(); + // equal operator + m_os<parameters(); + /* + * Try to handler sequence of sequence + */ + //assert(m_setof.is_private()); + if (m_setof.is_private()) + { + structName = type->cpp_name(); + } else + structName = ident->cpp_name(); + + m_os<parameters() && m_Gen.is_template(ident->parameters())) + { + m_Gen.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<") ;\n"; + + +} + +// generate codec part +void cghpph_setof::generate_per() +{ + std::string scope; + // + m_os< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cghpph_primitive.h" +#include "cghpph_string.h" + + +cghpph_string::cghpph_string( generate_header &g + , std::ostream &os + , asn1::primitive &s) + : cghpph_primitive(g,os,s) + , m_string(s) +{ +} + +cghpph_string::~cghpph_string() +{ +} + + +/** + * + */ +void cghpph_string::generate_prolog() +{ + if (m_gencpp.with_source_comment()) + m_os<<"// cghpph_string helper launched "<= asn1::type::ASN1_STRING + && m_string.type_id()() < asn1::type::ASN1_STRING_ObjectDescriptor ); + + m_os<<"struct "<parameters() && m_gencpp.is_template(ident->parameters())) + { + m_gencpp.gen_template_params(m_os,ident->parameters()); + } + m_os<<" &s"<<") ;\n"; + + +} + +// generate codec part +void cghpph_string::generate_per() +{ +} + +// +void cghpph_string::generate_ber() +{ + if (m_string.tagged()) + { + if ( m_gencpp.is_tag_explicit(m_string) ) + { + // + m_os<<"\tvirtual void encode(asn1::context &ctx);"< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "asn1_gen_codec_cpp.h" +#include "cghpp_helper.h" +#include "cghpph_typeref.h" + + +cghpph_typeref::cghpph_typeref(generate_header &g,std::ostream &os,asn1::typeref &s) + : cghpp_helper(g,os) , m_typeref(s) +{ +} + +cghpph_typeref::~cghpph_typeref() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_typeref::generate() +{ + asn1::node *n = m_typeref.identifier(); + asn1::node *type = &m_typeref; + asn1::node *params = NULL; + std::string structName; + + assert( n!= NULL); + if (m_gencpp.with_source_comment()) + { + m_os<<"// cghpph_typeref helper launched "; + m_os<name()<cpp_name()+"::"+m_typeref.cpp_name(); + } else + { + refName = m_typeref.cpp_name(); + } + m_os<<"//\nclass "<cpp_name(); + std::string refName = type->cpp_name(); + + if (m_gencpp.type_in_imports(type,&ns) ) + { + refName = ns->cpp_name()+"::"+type->cpp_name(); + } else + { + refName = type->cpp_name(); + } + + //generate_ber(); + // If its the simple + if ( !type->tagged()) + { + // Process untagged elements + asn1::node *params = type->parameters(); + if (m_gencpp.type_in_imports(type,&ns) ) + { + // imported case + if (type->meta_id()() == asn1::meta::OBJECTCLASS) + { + m_os<<"// OBJECT CLASS NOT YET SUPPORTED "<cpp_name()<<" "; + } else if (std::string("OPERATON").compare(type->cpp_name())==0) + { + m_os<<"// OBJECT CLASS NOT YET SUPPORTED "<cpp_name()<<" "; + } else + { + //m_os<<"\t"<cpp_name()<<"::"; + //m_os<cpp_name()<<" "; + } + } else if (std::string("TYPE_IDENTIFIER").compare(type->cpp_name())==0) + { + m_os<<" /* def"<cpp_name()<<"*/INTEGER "; + + } else + { + // internal case + if (m_gencpp.with_source_comment()) + { + m_os<<" /* def no import, has constraints "<has_constraints(); + m_os<<" */ "; + } + } + } +} +// +// +// +void +cghpph_typeref::gen_simple_ctors() +{ + asn1::node *ns = NULL; + asn1::node *n = m_typeref.identifier(); + asn1::typeref *type = &m_typeref; + std::string type_name = n->cpp_name(); + std::string refName = type->cpp_name(); + std::list refs; + + m_gencpp.reference_chaine(type,refs); + + if (m_gencpp.type_in_imports(type,&ns) ) + { + refName = ns->cpp_name()+"::"+type->cpp_name(); + } + + if (type->tagged()) + { + /** + * When tagged explicit, may be build object with tag + * from referenced type which needs to be used to + * decode what follows + */ + m_os<<"\t"<tag().m_class<<","<tag().m_value<<")"; + m_os<<" ) ;"<0 && + refs.back()->type_id()() == asn1::type::ASN1_CHOICE) + { + m_os<<"\t"<has_constraints()) + { + // Try to find the constraint type value + m_os<<"//\ntypedef "<cpp_name()<<" "<cpp_name()<<";"; + m_os<<"\n"<cpp_name()<cpp_name()<<" "; + m_os<<"\n"<cpp_name()<<" ::= "; + m_os<cpp_name(); + m_os<<" Ref="<<_ref.name(); + if (n->parameters()) + { + m_os<<" TYPE with parameters don't generate code ";; + } + if (m_typeref.act_parameters()) + { + m_os<<" REF WITH PARAMETERS !!!"; + } + m_os<<"\n"<cpp_name()<cpp_name()<<" I"<cpp_name()<<";"; + m_os<<"\n"<cpp_name(); + std::string refName = type->cpp_name(); + std::list refs; + + m_gencpp.reference_chaine(type,refs); + + if (m_gencpp.type_in_imports(type,&ns) ) + { + refName = ns->cpp_name()+"::"+type->cpp_name(); + } + + // + // + if (m_typeref.tagged()) + { + if ( m_gencpp.is_tag_explicit(*type) ) + { + m_os< +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "asn1_generator_helper.h" +#include "cgcpp_helper.h" +#include "cghpph_value.h" + + +cghpph_value::cghpph_value( generate_header &g + , std::ostream &os + , asn1::value &s) + : m_Gen(g) + , generator_helper(os) + , m_value(s) + , m_log(g.logger()) +{ +} + +cghpph_value::~cghpph_value() +{ +} + + +/** Helper functions + * + * It seems that the choice does not always have an identifier. Examples + * - SEQUENCE OF CHOICE {} + * - Test ::= CHOICE { toto INTEGER, CHOICE { } } + * these sequences are anonymous definitions ... + */ +void cghpph_value::generate() +{ + asn1::node *n = m_value.identifier(); + asn1::node *type = &m_value; + asn1::node *params = NULL; + std::string structName; + std::string scope(""); + + if (m_Gen.with_source_comment()) + m_os<<"// cghpph_value helper launched "< +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_js.h" +#include "asn1_visitor.h" + +/** + * Default Cosntructor + */ +generate_js::generate_js(asn1::module *n) : asn1::generator(n) +{} + +generate_js::generate_js(asn1::module *n,asn1::module::modules_type &m) + : asn1::generator(n,m) +{ +} + +/** + * Helper function to look for missing prototypes + */ +void generate_js::gen_missing(std::ostream &os,asn1::node *n) +{ + asn1::node::iterator it; + //= std::find_if(m_module->begin(),m_module->end(),asn1::find_node(n->name())); + switch (n->type_id()()) + { + case asn1::type::ASN1_SEQUENCE_OF: + case asn1::type::ASN1_SET_OF: + { +#ifdef DEBUG + std::cout<<"Find sequence of or set of:\n"; +#endif + asn1::node *type = n->as_typenode()->get_eltype(); + if (type !=NULL) + { + if (asn1::typeref *tref = type->as_typeref()) + { + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(tref->get_reference()->name())); + } else + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(type->name())); + } else return; + + } + break; + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_CHOICE: + { + asn1::constructed *cons = n->as_constructed(); +#if 1 + std::cout<<"generate_js::"<<__FUNCTION__<<" Find choice or sequence :\n"; + asn1::node::iterator lit = cons->begin(); + for (; lit != cons->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if (asn1::typenode *tn = f->get_type()) { + gen_missing(os,tn); + } + } +#endif + } + return; + break; + case asn1::type::ASN1_NULL: + return; + case asn1::type::ASN1_REFERENCE: + { + asn1::typeref *tref = n->as_typeref(); + // Try to check references + if (n->parameters() != NULL) + { + asn1::constructed *params = n->parameters(); + std::cout<<"generate_js::"<<__FUNCTION__<<" Have parameters\n"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + std::cout<<"generate_js::"<<__FUNCTION__<<" Parameter:"<<(*p)->name()<<"\n"; + it = std::find_if(m_module->begin(),m_module->end(),asn1::find_node((*p)->name())); + + if (it != m_module->end()) + gen_missing(os,(*it)); + } + } + // + if (tref->get_reference()) + { + if (std::string("TYPE-IDENTIFIER::&Type").compare(tref->get_reference()->name()) == 0) + { + asn1::constraint::iterator c = tref->constraint_begin(); + if ((*c)->type() == asn1::constraint::EL_TYPE) + { + asn1::node *ctype = (*c)->value(); + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(ctype->name())); + } + } else { + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(tref->get_reference()->name())); + } + + } else + { + it = std::find_if(m_module->begin(),m_module->end(),asn1::find_node(n->name())); + + } + } + break; + default: + it = std::find_if(m_module->begin(),m_module->end(),asn1::find_node(n->name())); + } +// Found a element to be generated + if ( it != m_module->end()) + { + asn1::assignment *ltype = (*it)->as_assignment(); + if ( (ltype->is_generated() != true)) + { + if (ltype->get_color() == asn1::node::CL_GREEN) + { + ltype->set_generated(true); + std::cout<<" gen minssing:"<name()<get_type()->type_id()()) + { + case asn1::type::ASN1_REFERENCE: + gen_typeref(os,ltype->get_type()->as_typeref()); + break; + default: + gen_typedef(os,ltype->get_type()); + } + ltype->set_color(asn1::node::CL_RED); + } else if (ltype->get_color() == asn1::node::CL_ORANGE) + { + if (ltype->get_type()->type_id()() == asn1::type::ASN1_SEQUENCE || + ltype->get_type()->type_id()() == asn1::type::ASN1_CHOICE + ) + os<<"struct "<cpp_name()<<";"<set_generated(true); + }else { + ltype->set_generated(true); + } + } + } +} + +/** + * + * + */ +void generate_js::gen_const(std::ostream &os,asn1::node *type) +{ + switch(type->type_id()()) + { + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + os<<"struct "<identifier_cpp_name(); + os<<" : public OBJECT_IDENTIFIER {"; + //gen_oid_value(os,type->identifier()); + os<identifier_cpp_name(); + os<<"\t "<cpp_name()<<""; + } + break; + default: + std::cout<<" DEFAULT"; std::cout.flush(); + os<<" const "<identifier_cpp_name()<<"\t\t= "<cpp_name()<<";"; + ; + } + os<(*it)) + { + os<<"\telse if (this.m_value == this.e"<cpp_name()<<")\n"; + os<<"\t\tError(\""<<(*it)->cpp_name()<<"\");\n"; + } else + { + os<<"\tif (this.m_value === this.e"<cpp_name()<<")\n"; + os<<"\t\tError(\""<<(*it)->cpp_name()<<"\");\n"; + } + + } + os<<"\tError(\"(\"+this.m_value+\")\");\n"; + // os<<"\t\treturn os;\n"; + os<<"\t}\n"; + +} + +/** + * + * + */ +void generate_js::gen_enumerated( std::ostream &os,asn1::enumerated &_enum + , const std::string &name) +{ + asn1::enumerated *enumtype = &_enum; + assert(enumtype != NULL); + std::string indent(""); + asn1::node::iterator it = enumtype->begin(); + + os<<"AEBW.declare(\""<cpp_name()<<"."<cpp_name()<<" : "; + + } + os<<"\n"<identifier_name(); + std::cout<<" id="<type_id()()<<" "; + + if (type != NULL) + { + std::cout<<" typenode is "<name()<<" "; + } else + { + std::cout<<" typenode is NULL ERROR"; + std::cerr<<"generate_js::"<<__FUNCTION__<<" type is null\n"; + exit(0); + } + if (type->parameters() != NULL){ + std::cout<<" parameterized "; + } + std::cout<get_reference()) { + type_name = type->cpp_name(); + } else { + type_name = type->cpp_name(); + } + if (type->type_id()() != asn1::type::ASN1_REFERENCE) + { + std::cout<<__FUNCTION__<<"ERROR "<cpp_name()<<" type="<type_id()(); + exit(0); + } + + + gen_missing(os,type); + asn1::node *ns = NULL; + os<<"AEBW.declare(\""<cpp_name()<<"."<identifier_cpp_name()<<"\","; + os<cpp_name()<<"."<identifier_name(); + std::cout<<" id="<type_id()()<<" "; + if (type != NULL) + { + std::cout<<" typenode is "<name()<<" "; + } else + { + std::cout<<" typenode is NULL "; + } + std::cout<type_id()()) + { + case asn1::type::ASN1_REFERENCE: + { + std::cout<<"__FUNCTION__"<<" ERROR "<cpp_name()<tagged() ) + { + os<<"AEBW.declare(\""<cpp_name()<<"."<cpp_name()<<"\",AEBW.Asn1.Integer,null);\n "; + + } else { + os<<"AEBW.declare(\""<cpp_name()<<"."<identifier_cpp_name()<<""; + os<<"\",AEBW.Asn1.Integer,null);\n"; + } + return ; + } + break; + case asn1::type::ASN1_SEQUENCE: + { + asn1::sequence *seqtype = dynamic_cast(type); + std::string scope(""); + asn1::node::iterator lit = seqtype->begin(); + for (; lit != seqtype->end() ; ++lit) + { + asn1::field *f = dynamic_cast(*lit); + if ( f->get_type() != NULL) { + gen_missing(os,f->get_type()); + } + } + gen_seq(os,scope,seqtype); + os<<"\n"; + return ; + } + break; + case asn1::type::ASN1_SEQUENCE_OF: + { + asn1::node *ns = NULL; + asn1::typenode *sty =type->get_eltype(); + gen_missing(os,sty); + if (type_in_imports(sty,&ns) ) + { + os<<"AEBW.declare(\""<cpp_name(); + os<<"."<identifier_cpp_name()<<"\",AEBW.Asn1.SequenceOf /*"; + os<<"\t"<cpp_name()<<"."; + os<cpp_name()<<"*/,null) "; + } else { + switch (sty->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + std::string scope("\t"); + + sty->name(type->identifier_cpp_name()+"_type"); + gen_seq(os,scope,sty->as_sequence()); + } + break; + default: + if (asn1::typeref *tref = sty->as_typeref()) + { + os<<"AEBW.declare(\""<cpp_name(); + os<<"."<identifier_cpp_name(); + os<<"\",AEBW.Asn1.SequenceOf/*"; + os<get_reference()->cpp_name()<<"*/,null); "; + } else + { + os<<"AEBW.declare(\""<cpp_name(); + os<<"."<identifier_cpp_name(); + os<<"\",AEBW.Asn1.SequenceOf /*"<cpp_name(); + os<<"*/,null); "; + } + } + } + } + break; + case asn1::type::ASN1_SET: + { + asn1::set *settype = dynamic_cast(type); + asn1::node::iterator lit = settype->begin(); + for (; lit != settype->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if ( f->get_type() != NULL) { + gen_missing(os,f->get_type()); + } + } + gen_set(os,settype->identifier()); + os<<";\n"; + return ; + } + break; + case asn1::type::ASN1_SET_OF: + { + asn1::typenode *subtype =type->get_eltype(); + gen_missing(os,subtype); + if (asn1::typeref *tref = subtype->as_typeref()) + { + os<<"typedef SET_OF<"<get_reference()->name()<<"> "; + } else + { + os<<"typedef SET_OF<"<cpp_name()<<"> "; + } + } + break; + case asn1::type::ASN1_CHOICE: + { + asn1::choice *ch = dynamic_cast(type); + asn1::node::iterator lit = ch->begin(); + for (; lit != ch->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if ( f->get_type() != NULL) { + gen_missing(os,f->get_type()); + } + } + gen_choice(os,*ch); + os<<";\n"; + return; + } + break; + case asn1::type::ASN1_ENUMERATED: + { + //os<<"typedef "; + gen_enumerated( os + , *type->as_enumerated() + , type->identifier_cpp_name()); + } + break; + ; + case asn1::type::ASN1_BIT_STRING: + { + std::cerr<<__FUNCTION__<<" BIT_STRING TODO"<cpp_name()<<"."<identifier_cpp_name()<<""; + //os<<"typedef "; + if (type_in_imports(type,&ns) ) { + os<<"\","<cpp_name()<<"."<cpp_name()<<",null);\n"; + } else { + os<<"\","<cpp_name()<<",null/* default case*/);\n"; + } + return; + ; + }; + + +} + +/** + * + */ +void generate_js::gen_seq_printf(std::ostream &os,std::string &scope,asn1::sequence *type,bool priv) +{ + os<identifier(); + asn1::node::iterator lit = type->begin(); + asn1::constructed *params = n->parameters(); + m_Stack.push_back(n->cpp_name()); + assert(type != NULL); + + // default constructor + // I should probaly push optionnal attributes and OBEJECTS in a stack and add a initializer here. + std::vector opt_attrs; + for (asn1::node::iterator it = type->begin(); it != type->end() ; it++) + { + asn1::field *f = dynamic_cast(*lit); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + asn1::typeref *tref = attr_type->as_typeref(); + if ( tref && tref->is_complex()) + { + asn1::reference *r = tref->get_reference(); + std::string lr = r->back().m_identifier; + opt_attrs.push_back((*it)); + } + } + + } + os<cpp_name()<<"."; + os<cpp_name()<<"\",AEBW.Asn1.Sequence, {\n"; + // Constructor + os<cpp_name()<<": \"\""; + } else if (opt_attrs.size() > 1) + { + } + + os<<"\t},\n"; + // Copy constructor + os<end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + asn1::typenode *attr_type = f->get_type(); + if (! f->is_extensible()) + gen_composite_attribute(os,scope,f,n->parameters()); + } + + gen_seq_printf(os,scope,type,priv); + // What is scope for here ? + os<(_params); + asn1::node::node_list nl; + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} +// +// +// +void generate_js::gen_template_signature(std::ostream &os,asn1::node *_params) +{ + asn1::constructed *params = dynamic_cast(_params); + asn1::node::node_list nl; + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} + +/** + * + * + */ +void generate_js::gen_choice_printf(std::ostream &os,asn1::choice *type) +{ + asn1::node *n= type->identifier(); + os<<"\tprintf : function() {"; + os<<"\n\t},\n"; +} + +/** + * + * + */ +void generate_js::gen_choice(std::ostream &os,asn1::choice &_type) +{ + std::string scope(""); + asn1::choice *type = &_type; + asn1::node *n= type->identifier(); + assert(type != NULL); + m_Stack.push_back(n->cpp_name()); + std::cout<<"generate_js::gen_choice"<cpp_name()<<"."<cpp_name()<<"\",AEBW.Asn1.Choice,{\n"; + os<<"\tconstructor : function() {\n"; + os<<"\t\tthis.kind_ = 0;},\n"; + os<<"\tencode_ber : function(ctx,"; + // Parameter stuff here + if (n->parameters() && is_template(n->parameters())) + { + gen_template_params(os,n->parameters()); + } + os<<" Stream"<<") {\n"; + os<<"\t},\n"; + gen_choice_printf(os,type); + // == operator + // + asn1::node::iterator it; + it = type->begin(); + for (; it != (type)->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + if (! f->is_extensible()) + gen_composite_attribute(os,scope,f,n->parameters()); + + } + // Now add an enum tu identifie type + os<<"\tenums : { "; + asn1::node::iterator lit; + lit = type->begin(); + int count = 0; + for (; lit != (type)->end() ; lit++) + { + os<<" typeof_"<<(*lit)->cpp_name()<<": "<(_params); + asn1::reference *ref = attribute->get_reference(); + + if (ref->size() > 1) + { + // find the object and folow the links .... + std::string rname = ref->back().m_identifier; + os<<"\tasn1::Object * /* GCAT "<begin(), + m_module->end(), + asn1::find_node(ref->name())); + if (refm != m_module->end()) + { + // Here I have the type definition. I should add + os<<"\t"<cpp_name(); + if (attribute->parameters()!= NULL) + { + os<<"<"; + for (asn1::node::iterator it = attribute->parameters()->begin(); + it != attribute->parameters()->end(); ++it) + { + if (it != attribute->parameters()->begin()) + os<<","; + os<<(*it)->cpp_name(); + } + os<<">"; + } + os<<" /*NR c="<<(*refm)->get_color()<<"*/ "; + } else + { + asn1::node *ns = NULL; + if (type_in_imports(ref->name(),&ns) ) { + asn1::reference::component_const_iterator compit = ref->begin(); + // Check first element of reference + if ( (*compit).type == asn1::reference::component::CAPITALS) + { + os<<"\t/* GCAT */"<cpp_name()<<"::"<name()<<" "; + } else + os<<"\t"<cpp_name()<<"::"<cpp_name()<<" /*NR 2*/ "; + // check if attribute has parameters + if (attribute->parameters() != NULL) + { + os<<"<"; + for (asn1::node::iterator it = attribute->parameters()->begin(); it != attribute->parameters()->end(); ++it) + { + asn1::node *ns1 = NULL; + if (it != attribute->parameters()->begin()) + os<<","; + // check namespace + if (type_in_imports((*it)->name(),&ns1) ) { + os<cpp_name()<<"::"<<(*it)->cpp_name(); + } else + os<<(*it)->cpp_name(); + } + os<<">"; + + } + } else if (params) // reference in parameters of definition + { + bool found = false; + for (asn1::node::iterator it = params->begin() + ; it != params->end(); ++it ) + { + if (ref->name().compare((*it)->name())== 0) + { + os<<"\t"<<(*it)->cpp_name(); + found = true; + } + if (!found) + os<<" ERRORNOTPARAMS "; + + } + + } else + { + os<<" ERROR "; + } + } + + } +} + +void +generate_js::gen_composite_attribute( std::ostream &os + , std::string &scope + , asn1::field *attribute + , asn1::node *params) +{ + asn1::typenode *attr_type = attribute->get_type(); + assert(attr_type != NULL); + if (attr_type != NULL) + { + switch (attr_type->type_id()()) + { + case asn1::type::ASN1_ENUMERATED: + { + gen_enumerated( os + , *attr_type->as_enumerated() + , attribute->cpp_name()+"_t"); + os <cpp_name()<<";"<cpp_name()<<";\n"; + } + break; + case asn1::type::ASN1_CHOICE: + { + attr_type->name(attribute->cpp_name()+"_t"); + //gen_choice(os,attr_type); + os<<"\t\t"<cpp_name()<<": \"\",\n"; + } + break; + case asn1::type::ASN1_SEQUENCE: + { + std::string scope("\t"); + attribute->get_type()->name(attribute->cpp_name()+"_t"); + + os<<"\t\t"<<(attribute)->cpp_name()<<" : \"\",\n"; + } + break; + case asn1::type::ASN1_SELECTION: + { + os<<"\t\tINTEGER "<<(attribute)->cpp_name(); + os<<"; // SELECTION TO be done\n"; + } + break; + case asn1::type::ASN1_SET_OF: + case asn1::type::ASN1_SEQUENCE_OF: + { + asn1::typenode *type = attribute->get_type(); + asn1::typenode *subtype = type->get_eltype(); + + switch (subtype->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + subtype->name((attribute)->cpp_name()+std::string("_type")); + gen_seq(os,scope,subtype->as_sequence(),true); + os<<";\n\t"<name(); + os<<"<"<cpp_name()+"_type"); + os<<">\t"<<(attribute)->cpp_name()<<";\n"; + break; + default: + asn1::node *ns; + if (type_in_imports(subtype,&ns) ) + { + os<<" "<name()<<"<"<cpp_name(); + os<<"::"<cpp_name(); + os<<">\t"<<(attribute)->cpp_name()<<";\n"; + } else + { + if (asn1::typeref *tref = subtype->as_typeref()) + { + os<<" "<name()<<"<"; + os<<(tref->get_reference())->cpp_name(); + os<<">\t"<<(attribute)->cpp_name()<<";\n"; + } else + os<<" "<name()<<"<"<cpp_name()<<">\t"<cpp_name()<<";\n"; + } + } + } + break; + case asn1::type::ASN1_REFERENCE: + + { + os<<"\t"<<(attribute)->cpp_name()<<": \"\","; + os<cpp_name()<<": \"\","; + os<<"\n"; + } + } + } +} + + +/** + * + */ +void generate_js::gen_set_printf(std::ostream &os,std::string &scope,asn1::node *n,bool priv) +{ + /* + * Try to handler sequence of sequence + */ + +} + + +/** + * + */ +void generate_js::gen_set(std::ostream &os,asn1::node *n) +{ + std::string scope(""); +} + + +void generate_js::gen_object_class_opt(std::ostream &os,asn1::node *n) +{ +} + +/** + * + * + */ +void generate_js::gen_object_class_missing(std::ostream &os,asn1::node *n) +{ +} + + +/** + * + * + */ +void generate_js::gen_object_class_interface(std::ostream &os,asn1::node *n) +{ +} + + +void generate_js::gen_object_class_attributes(std::ostream &os,asn1::node *n) +{ +} + + +void +generate_js::gen_object_class_printf(std::ostream &os,asn1::node *n) +{ +} +/** + * + * + */ +void generate_js::gen_object_class(std::ostream &os,asn1::node *n) +{ +} +/** + * + * + */ +void generate_js::gen_object(std::ostream &os,asn1::node *n) +{ + os.flush(); +} + +/** + * + * + */ +void generate_js::gen_object_object_type(std::ostream &os,asn1::node *n) +{ +} + + + +/** + * + * + */ +void generate_js::gen_object_error(std::ostream &os,asn1::node *n) +{ + std::cerr<<__FUNCTION__<<" To rewrite"< +{ + protected: + generate_js &m_js; + std::ostream &m_os; + public: + do_assignment(generate_js &_js,std::ostream &os) + : m_os(os),m_js(_js) {}; + + void visit_type(asn1::type_assignment *type) + { + m_js.gen_typedef(m_os,type->get_type()); + } + void visit_value(asn1::value_assignment *type) + { + m_js.gen_const(m_os ,type->get_type()); + } +#if 0 + void visit_valueset(asn1::valueset_assignment *type) + { + } + void visit_objectclass(asn1::objectclass_assignment *type) + { + } +#endif + void visit_object(asn1::object_assignment *type) + { + m_js.gen_object(m_os,type->get_type()); + } + void visit_typeref(asn1::typeref_assignment *type) + { + m_js.gen_typeref(m_os,type->get_type()->as_typeref()); + } + void visit_assignment(asn1::assignment *type) + { + std::cout<<__FUNCTION__<<" Unhandled assignment "<name()<name()<imports(); + // Add include for external dependencies + + os<<"if ( ! "<<_module->cpp_name()<<")\n {\n"<sort_childs(); + + for ( asn1::node::iterator it = _module->begin() + ; it != _module->end() ; it++) + { + asn1::assignment *type = (*it)->as_assignment(); + std::cout<<"generate_js::"<<__FUNCTION__<<" process "<name(); + std::cout.flush(); + if (type->get_type() != NULL) + { + if ( type->is_generated()) + { + std::cout<<" ALREADY GENERATED "<name()<<" is NULL"<set_color(asn1::node::CL_RED); + } else + { + std::cout<<" no type "<name(); + os<<"// "<<__FUNCTION__<<" no type "<name(); + } + os< +#include + + +/** + * + */ +class generate_js : public asn1::generator +{ + public: + + generate_js(asn1::module *n); + + generate_js(asn1::module *n,asn1::module::modules_type &m); + + + void gen_missing(std::ostream &os,asn1::node *n) ; + + /** + * + * + */ + void gen_const(std::ostream &os,asn1::node *n); + + void gen_enumerated_printf( std::ostream &os + , asn1::enumerated &n + , const std::string &name); + void gen_enumerated(std::ostream &os,asn1::enumerated &n ,const std::string &name); + // + // + // + void gen_typedef(std::ostream &os,asn1::typenode *n); + void gen_typeref(std::ostream &os,asn1::typeref *n); + + void gen_seq_printf( std::ostream &os + , std::string &scope + , asn1::sequence *type,bool priv =false); + /** + * + */ + void gen_seq( std::ostream &os,std::string &scope + , asn1::sequence *n,bool priv = false); + + void gen_choice_printf(std::ostream &os,asn1::choice *n); + + void gen_choice(std::ostream &os,asn1::choice &choice); + + void gen_composite_attribute( std::ostream &os + , std::string &scope + , asn1::field *attribute,asn1::node *params = NULL); + void gen_composite_attribute_ref( std::ostream &os + , std::string &scope + , asn1::typeref *attribute + , asn1::node *params = NULL); + void gen_template_params(std::ostream &os,asn1::node *params); + void gen_template_signature(std::ostream &os,asn1::node *params); + + /** + * + */ + void gen_set(std::ostream &os,asn1::node *n); + void gen_set_printf(std::ostream &os,std::string &scope,asn1::node *n,bool priv =false); + + /* + * Ros generation Code + */ + void gen_object_class(std::ostream &os,asn1::node *n); + void gen_object_class_interface(std::ostream &os,asn1::node *n); + void gen_object_class_missing(std::ostream &os,asn1::node *n); + void gen_object_class_opt(std::ostream &os,asn1::node *n); + void gen_object_class_attributes(std::ostream &os,asn1::node *n); + + void gen_object_class_printf(std::ostream &os, asn1::node *n); + + void gen_object(std::ostream &os,asn1::node *n); + void gen_object_object_type(std::ostream &os,asn1::node *n); + void gen_object_error(std::ostream &os,asn1::node *n); + void gen_object_operation(std::ostream &os,asn1::node *n); + void gen_object_operation_package(std::ostream &os,asn1::node *n); + void gen_object_connection(std::ostream &os,asn1::node *n); + /** + * + */ + void gen_module(std::ostream &os,asn1::module *n); + protected: + std::vector m_Stack; +}; +/** + * vim:et:sw=2:ts=2 + */ +#endif diff --git a/libgen/lds/asn1_gen_lds.cpp b/libgen/lds/asn1_gen_lds.cpp new file mode 100644 index 0000000..bb67a5e --- /dev/null +++ b/libgen/lds/asn1_gen_lds.cpp @@ -0,0 +1,347 @@ +#include +#include +#include +#include +#include + +#include "asn1_generator.h" +#include "asn1_gen_lds.h" +#include "adt/asn1_visitor.h" + + + + +/** + * Default constructor to be used + */ +generate_lds::generate_lds(asn1::module *n,asn1::module::modules_type &m) + : generator(n,m) +{ +} + + + +/** +* +* +*/ +void +generate_lds::gen_const(std::ostream &os,asn1::node *n) +{ +} + + +/** + * + */ +void +generate_lds::gen_enumerated( std::ostream &os + , asn1::enumerated &_enum + ) +{ +} + + +class dolds_typedef : public node_visitor +{ + protected: + generate_lds &m_gen; + std::ostream &m_os; + std::fstream &m_log; + + public: + dolds_typedef(std::ostream &_os,generate_lds &_gen) + : m_os(_os) , m_gen(_gen) + , m_log(_gen.logger()) + { + } +#define DO_TYPEDEF(Tp,Code) \ + void visit_##Tp(asn1::Tp *type) \ + Code + + void visit_primitive(asn1::primitive *type) + { + m_os<<"string "<identifier_name()<<";"<identifier_name().c_str()); + m_os<<"boolean "<identifier_name()<<";"<identifier_name().c_str()); + m_os<<"integer "<identifier_name()<<";"<identifier_name().c_str()); + m_os<<"value type "<identifier_name()<<" { choice"<begin(); it != type->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + m_os<<"\t// Extensible marker"<cpp_name()<<"\t"<cpp_name()<<";\n"; + } + } + } + m_os<<" };"<identifier_name().c_str()); + m_os<<"value type "<identifier_name()<<" { struct"<begin(); it != type->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + m_os<<"\t// Extensible marker"<cpp_name()<<"\t"<cpp_name()<<";\n"; + } + } + } + m_os<<" };"<identifier_name().c_str()); + m_os<<"value type "<identifier_name()<<" { struct"<begin(); it != type->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + if (attr_type->type_id()() == asn1::type::ASN1_EXTENSIBLE) + { + m_os<<"\t// Extensible marker"<cpp_name()<<"\t"<cpp_name()<<";\n"; + } + } + } + m_os<<" };"<get_eltype(); + GEN_LOG_DEBUG( "visit_sequence_of %s \n" + , type->identifier_name().c_str()); + m_os<<"value type "<identifier_name()<<" inherits "; + m_os<<"Array <"<<","<cpp_name()<<">;"<identifier_name().c_str()); + m_os<<"octet_string "<identifier_name()<<";"<identifier_name().c_str()); + m_os<<"bitstring "<identifier_name()<<";"<identifier_name().c_str()); + m_os<<"enumerated "<identifier_name()<<";"<identifier_name()<<"\n */\n"; + dolds.visit(type); +} + + +/** + * + */ +void +generate_lds::gen_typeref( std::ostream &os + , asn1::typeref &type) +{ + os<<"\n/*\n * "< +{ + public: + dolds_assignment(std::ostream &_os,generate_lds &_gen) + : m_os(_os) , m_gen(_gen) + , m_log(_gen.logger()) + { + } + // Main processing function per assignment + void operator ()(asn1::node *n) + { + asn1::typenode *type = n->as_assignment()->get_type(); + std::string path = n->cpp_name()+".cpp"; + GEN_LOG_DEBUG( "Process item=%s meta=%d\n" + , n->name().c_str() + , n->meta_id()()); + if ( ! type) + return; + + if ( n->is_generated()) + { + GEN_LOG_DEBUG("%s already generated\n",n->name().c_str()); + return; + } +#if 0 + if (m_gen.with_split_cpp()) + m_gen.open_assignment_stream(m_sep_os,n->as_assignment()); +#endif + visit(n->as_assignment()); +#if 0 + if (m_sep_os.is_open()) + m_sep_os.close(); +#endif + n->set_color(asn1::node::CL_RED); + } +#define ASSIGNMENT(En,Tp,Parent,Code) \ + void visit_##Tp(asn1::Tp##_assignment *a) \ + Code +ASSIGNMENT(TYPEREF,typeref,assignment,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "visit_Typeref %s parameterized: %d\n" + , a->name().c_str(),params); + m_gen.gen_typeref(m_os,*a->get_type()->as_typeref()); + }) +ASSIGNMENT(TYPE,type,assignment,{ + int params = (a->parameters() != NULL)?1:0; + // Try to create an include file + GEN_LOG_DEBUG( "visit_Type %s parameterized: %d\n" + , a->name().c_str(),params); + m_gen.gen_typedef(m_os,a->get_type()); + }) +ASSIGNMENT(VALUE,value,assignment,{ + std::cout<<__FUNCTION__<<" TODO "<name()<name()<name()<name()<name()<name()<as_assignment()); + } +} +/* + * vim: et sw=2 ts=2 list: + */ diff --git a/libgen/lds/asn1_gen_lds.h b/libgen/lds/asn1_gen_lds.h new file mode 100644 index 0000000..cffa172 --- /dev/null +++ b/libgen/lds/asn1_gen_lds.h @@ -0,0 +1,76 @@ +#ifndef GEN_HEADER_LDS_H__ +#define GEN_HEADER_LDS_H__ +#include +#include + + +/** + * When calling the generator, the structure has already been flatten. + * There is no need to recurse over sub types and so on. + */ +class generate_lds : public asn1::generator +{ + public: + + + generate_lds(asn1::module *n,asn1::module::modules_type &m); + + /** + * + */ + void gen_const(std::ostream &os,asn1::node *n); + + + /** + * + */ + void gen_typeref( std::ostream &os + , asn1::typeref &n); + + /** + * + */ + void gen_typedef(std::ostream &os,asn1::typenode *n); + /** + * + */ + void gen_seq( std::ostream &os + , asn1::sequence &n); + + /** + * + */ + void gen_choice( std::ostream &os + , asn1::choice &choice); + + /** + * + */ + void gen_set(std::ostream &os,asn1::set &n); + + /** + * + */ + void gen_enumerated( std::ostream &os + , asn1::enumerated &_enum + ); + + /* + * Ros generation Code + */ + void gen_object_class(std::ostream &os,asn1::classdef &n); + + /** + * + */ + void gen_object(std::ostream &os,asn1::object &n); + /** + * + */ + void gen_module(std::ostream &os,asn1::module *_m); + protected: +}; +/** + * vim:et:sw=2:ts=2:list + */ +#endif diff --git a/libgen/uml/asn1_gen_uml.cpp b/libgen/uml/asn1_gen_uml.cpp new file mode 100644 index 0000000..c73a6ce --- /dev/null +++ b/libgen/uml/asn1_gen_uml.cpp @@ -0,0 +1,1274 @@ +#include +#include +#include +#include +#include "asn1_generator.h" +#include "asn1_gen_uml.h" +#include "adt/asn1_visitor.h" + +static long g_counter = 0; + +/** + * Default Cosntructor + */ +generate_uml::generate_uml(asn1::module *n) : asn1::generator(n) +{} + +generate_uml::generate_uml(asn1::module *n,asn1::module::modules_type &m) + : asn1::generator(n,m) +{ +} + +/** + * Helper function to look for missing prototypes + */ +void generate_uml::gen_missing(std::ostream &os,asn1::typenode *n) +{ + asn1::node::iterator it; + switch (n->type_id()()) + { + case asn1::type::ASN1_SEQUENCE_OF: + case asn1::type::ASN1_SET_OF: + { +#ifdef DEBUG + std::cout<<"Find sequence of or set of:\n"; +#endif + asn1::typenode *type = n->get_eltype(); + if (type !=NULL) + { + if (asn1::typeref *tref = type->as_typeref()) + { + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(tref->get_reference()->name())); + } else + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(type->name())); + } else return; + + } + break; + case asn1::type::ASN1_SEQUENCE: + case asn1::type::ASN1_CHOICE: + { + asn1::constructed *ct = n->as_constructed(); + GEN_LOG_DEBUG("choice or sequence %s\n",n->name().c_str()); + asn1::node::iterator lit = ct->begin(); + for (; lit != ct->end() ; lit++) + { + asn1::field *f = dynamic_cast(*it); + if ( f->get_type() != NULL) { + gen_missing(os,f->get_type()); + } + } + } + return; + break; + case asn1::type::ASN1_NULL: + return; + case asn1::type::ASN1_REFERENCE: + { + asn1::typeref *tref = n->as_typeref(); + // Try to check references + if (tref->parameters() != NULL) + { + asn1::constructed *params = n->parameters(); + std::cout<<"generate_uml::"<<__FUNCTION__<<" Have parameters\n"; +// os<<"//generate_uml::"<<__FUNCTION__<<" "<name()<<" Have parameters\n"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + std::cout<<"generate_uml::"<<__FUNCTION__<<" Parameter:"<<(*p)->name()<<"\n"; + it = std::find_if(m_module->begin(),m_module->end(),asn1::find_node((*p)->name())); + + if (it != m_module->end()) + gen_missing(os,(*it)->as_typenode()); + } + } + // + if (tref->get_reference()) + { + if (std::string("TYPE-IDENTIFIER::&Type").compare(tref->get_reference()->name()) == 0) + { + asn1::constraint::iterator c = tref->constraint_begin(); + if ((*c)->type() == asn1::constraint::EL_TYPE) + { + asn1::node *ctype = (*c)->value(); + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(ctype->name())); + } + } else { + it = std::find_if(m_module->begin(), + m_module->end(), + asn1::find_node(tref->get_reference()->name())); + } + + } else + { + it = std::find_if(m_module->begin(),m_module->end(),asn1::find_node(n->name())); + + } + } + break; + default: + it = std::find_if(m_module->begin(),m_module->end(),asn1::find_node(n->name())); + } +// Found a element to be generated + if ( it != m_module->end()) + { + asn1::assignment *ltype = dynamic_cast(*it); + if ( ltype->is_generated() != true) + { + if (ltype->get_color() == asn1::node::CL_GREEN) + { + ltype->set_generated(true); + GEN_LOG_DEBUG("missing %s\n",ltype->name().c_str()); + switch(ltype->get_type()->type_id()()) + { + case asn1::type::ASN1_REFERENCE: + gen_typeref(os,ltype->get_type()->as_typeref()); + break; + default: + gen_typedef(os,ltype->get_type()->as_typenode()); + } + (*it)->set_color(asn1::node::CL_RED); + } else if (ltype->get_color() == asn1::node::CL_ORANGE) + { + if (ltype->get_type()->type_id()() == asn1::type::ASN1_SEQUENCE || + ltype->get_type()->type_id()() == asn1::type::ASN1_CHOICE + ) + os<<"struct "<cpp_name()<<";"<set_generated(true); + }else { + ltype->set_generated(true); + } + } + } +} + + +/** + * + * + */ +void generate_uml::gen_const(std::ostream &os,asn1::node *type) +{ + switch(type->type_id()()) + { + case asn1::type::ASN1_OBJECT_IDENTIFIER: + { + os<<"identifier_cpp_name(); + os<identifier_cpp_name()<<"\"/>"<identifier_cpp_name()<<"\"/>"<identifier_cpp_name(); + std::cout<<"\n"; std::cout.flush(); + ; + } + os<begin(); + std::string balise; + if (nested ) { + balise = "nestedClassifier"; + } else + balise = "packagedElement"; + os<<"<"<uid(); + os<<"\" xmi:type=\"uml:Class\" name=\""<"; + for (; it != enumt->end(); it++) + { + os<<"uid()<<"\" name=\""; + os<<(*it)->name()<<"\"/>\n"; + } + os<\n "; +} + +// +// gen_typeref +// +void generate_uml::gen_typeref(std::ostream &os,asn1::typeref *type) +{ + std::string type_name; + + if (type ) + { + int par = (type->parameters() == NULL)?0:1; + GEN_LOG_DEBUG("type=%s params=%d\n",type->name().c_str(),par); + + if (type->has_constraints()) + { + asn1::constraint *c = *(type->constraint_begin()); + } + } + if (type->get_reference()) { + //type_name = type->get_reference()->cpp_name(); + type_name = type->cpp_name(); + } else { + type_name = type->cpp_name(); + } + if (type->type_id()() != asn1::type::ASN1_REFERENCE) + { + std::cout<<__FUNCTION__<<"ERROR "<cpp_name()<<" type="<type_id()(); + exit(0); + } + + + gen_missing(os,type); + asn1::node *ns = NULL; + //os<<"typedef "; + os<<"identifier()->uid()<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name()<<"\"/>\n"; + g_counter++; + if (type->tagged()) + { + } else { + // Process untagged elements + asn1::constructed *params = type->parameters(); + if (type_in_imports(type,&ns) ) + { + // imported case + if (type->meta_id()() == asn1::meta::OBJECTCLASS) + { + //os<<"// OBJECT CLASS NOT YET SUPPORTED "<cpp_name()<<" "; + } else if (std::string("OPERATON").compare(type->cpp_name())==0) + { + //os<<"// OBJECT CLASS NOT YET SUPPORTED "<cpp_name()<<" "; + } else + { + //TODO find reference and add it so we can know + //os<<"\t"<cpp_name()<<"::"; + //os<cpp_name()<<" "; + } + } else if (std::string("TYPE_IDENTIFIER").compare(type->cpp_name())==0) { + //os<<" /* def"<cpp_name()<<"*/INTEGER "; + + } else { + // internal case + } + // Buuggeeee + if (std::string("ROS").compare(type->name()) ) + if (params && is_template(params)) + { + asn1::node::iterator begin = params->begin(); + asn1::node::iterator end = params->end(); + os<<"<"; + for (; begin != end ; ++begin) { + if (begin != params->begin()) + os<<","; + os<<(*begin)->cpp_name(); + } + os<<">"; + } + + } + + // os<<"\t\t"<identifier_cpp_name()<<";\n\n"; + +} + + +// +// +// +void generate_uml::gen_typedef(std::ostream &os,asn1::typenode *type) +{ + if (type ) + { + GEN_LOG_DEBUG("type %s ident=%s\n",type->name().c_str(),type->identifier_name().c_str()); + + if (type->has_constraints()) + { + asn1::constraint *c = *(type->constraint_begin()); +// if (c) +// os <name(); + + } + if ( type->identifier() && type->identifier()->parameters()) + { +// os<<" parameterized "; + } + os<<"\n"; + } + + if (type != NULL) + switch (type->type_id()()) + { + case asn1::type::ASN1_REFERENCE: + { + std::cout<<"__FUNCTION__"<<" ERROR "<cpp_name()<name()<<" "; + gen_missing(os,type); + asn1::node *ns = NULL; + //os<<"typedef "; + os<<"AEBW.declare(\""<cpp_name()<<"\",AEBW.Asn1 "; + if (type->tag().m_value != -1) + { + } else { + if (type_in_imports(type,&ns) ) { + if (type->meta_id()() == asn1::meta::OBJECTCLASS) + { + os<<"// OBJECT CLASS NOT YET SUPPORTED "<cpp_name()<<" "; + } else if (std::string("OPERATON").compare(type->cpp_name())==0) + { + os<<"// OBJECT CLASS NOT YET SUPPORTED "<cpp_name()<<" "; + } else + { + os<<"\t"<cpp_name()<<"::"; + os<cpp_name()<<" "; + } + } else + os<<" /**/ "<cpp_name()<<" "; + + } + + } + break; + case asn1::type::ASN1_INTEGER: + { + os<<"identifier()->uid()<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name()<<"\"/>"<as_sequence(); + asn1::node::iterator lit = seq->begin(); + for (; lit != seq->end() ; ++lit) + { + asn1::field *f = dynamic_cast(*lit); + if ( asn1::typenode *tn = f->get_type() ) { + gen_missing(os,tn); + } + } + gen_seq(os,scope,*seq); + os<<"\n"; + return ; + } + break; + case asn1::type::ASN1_SEQUENCE_OF: + { + asn1::node *ns = NULL; + asn1::typenode *subt =type->get_eltype(); + gen_missing(os,subt); + if (type_in_imports(subt,&ns) ) { + os<<"identifier()->uid()<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name()<<"\"/>"<type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + { + std::string scope("\t"); + + subt->name(type->identifier_cpp_name()+"_type"); + gen_seq(os,scope,*subt->as_sequence()); + //os<<";\ntypedef SEQUENCE_OF<"<<(*it)->cpp_name()<<"> "; + os<<"identifier()->uid()<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name()<<"\"/>"<as_typeref()) + { + os<<"identifier()->uid()<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name()<<"\"/>"<identifier()->uid()<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name()<<"\"/>"<as_set(); + asn1::node::iterator lit = settype->begin(); + for (; lit != settype->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if ( asn1::typenode *tn = f->get_type()) { + gen_missing(os,tn); + } + } + gen_set(os,settype); + os<<"\n"; + return ; + } + break; + case asn1::type::ASN1_SET_OF: + { + asn1::typenode *it = type->get_eltype(); + if (it) + gen_missing(os,it); + if (asn1::typeref *tref = it->as_typeref()) + { + os<<"get_reference()->name()<<"\"/>"<cpp_name()<<"\"/>"<as_choice(); + asn1::node::iterator lit = ct->begin(); + for (; lit != ct->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + if ( asn1::typenode *tn = f->get_type() ) { + gen_missing(os,tn); + } + } + gen_choice(os,ct); + os<<"\n"; + return; + } + break; + case asn1::type::ASN1_ENUMERATED: + { + //os<<"typedef "; + gen_enumerated(os,*type->as_enumerated(),type->identifier_cpp_name()); + } + break; + ; + case asn1::type::ASN1_BIT_STRING: + { + os<<"identifier()->uid(); + os<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name(); + os<<"\"/>"<identifier()->uid()<<"\" xmi:type=\"uml:DataType\" name=\""<identifier_cpp_name()<<"\"/>"<identifier_cpp_name()<<";\n\n"; + +} + +/** + * + */ +void generate_uml::gen_seq(std::ostream &os,std::string &scope,asn1::sequence &_type) +{ + asn1::sequence * type = &_type; + asn1::node * n = _type.identifier(); + asn1::node::iterator lit; + asn1::constructed *params = n->parameters(); + std::string balise; + + balise = "packagedElement"; + /* + * Try to handler sequence of sequence + */ + if ( type != NULL) + { + lit = type->begin(); + } + + m_Stack.push_back(n->cpp_name()); + // default constructor + // I should probaly push optionnal attributes and OBEJECTS in a stack and add a initializer here. + std::vector opt_attrs; + for (asn1::node::iterator it = type->begin() + ; it != type->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *attr_type = f->get_type(); + if (attr_type != NULL) + { + asn1::typeref *tref = attr_type->as_typeref(); + if (tref && tref->get_reference() && tref->is_complex()) + { + asn1::reference *r = tref->get_reference(); + std::string lr = r->back().m_identifier; + opt_attrs.push_back((*it)); + } + } + + } + os<<"<"<uid(); + os<<"\" xmi:type=\"uml:Class\" name=\""<cpp_name()<<"\"> \n"; + // Constructor + // Copy constructor + + for (; lit != type->end() ; lit++) + { + asn1::field *f = dynamic_cast(*lit); + gen_composite_attribute(os,scope,f,n->parameters()); + } + + os<<"\n"; + m_Stack.pop_back(); +} + + +// +// +// +void generate_uml::gen_template_params(std::ostream &os,asn1::node *_params) +{ + asn1::constructed *params = _params->as_constructed(); + asn1::node::node_list nl; + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} +// +// +// +void generate_uml::gen_template_signature(std::ostream &os + ,asn1::node *_params) +{ + asn1::constructed *params = _params->as_constructed(); + asn1::node::node_list nl; + + os<<"<"; + for(asn1::node::iterator p = params->begin(); p != params->end() ;++p) + { + if (nl.size()>0) + { + asn1::node::iterator it = std::find_if(nl.begin(),nl.end(),asn1::find_node((*p)->name())); + if (it != nl.end() ) + { + // + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } else { + if (p != params->begin()) os<<","; + os<<" typename "<<(*p)->cpp_name(); + nl.push_back(*p); + } + } + os<<"> "; +} + +/** + * + * + */ +void generate_uml::gen_choice(std::ostream &os,asn1::choice *n,bool nested) +{ + std::string scope(""); + asn1::constructed *type = n->as_constructed(); + asn1::node::iterator it; + std::string balise; + if (nested) { + balise = "nestedClassifier"; + } else { + balise = "packagedElement"; + } + if (type == NULL) + { + type = n->as_constructed(); + } + m_Stack.push_back(n->cpp_name()); + GEN_LOG_DEBUG("node=%s nested=%d\n",n->name().c_str(),nested); + it = type->begin(); + // Handle parameter stuff + if (n->parameters() && is_template(n->parameters())) + { + asn1::node::node_list nl; + asn1::constructed *params = n->parameters(); + // os<<"//"<<__FUNCTION__<<" parameterized\n"; + // Forward declaration for ostream function + os<<"template "; + gen_template_signature(os,params); + os<<" struct "<cpp_name()<<" /* : public asn1::type */ ;\n"; + os<<"template "; + gen_template_signature(os,params); + os<<"\nstd::ostream & operator<<(std::ostream &os,const "<cpp_name(); + gen_template_params(os,params); + os<<" &s) ;\n"; + + // Real declation + os<<"template "; + gen_template_signature(os,params); + } + + //os<<"struct "<cpp_name()<<" /* : public asn1::type */ {\n"; + // os<<" int\t\t"<<"kind_;"<uid(); + os<<"\" xmi:type=\"uml:Class\" name=\""<cpp_name()<<"\">"<end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + gen_composite_attribute(os,scope,f,n->parameters()); + } + // Now add an enum tu identifie type + + os<<""; + m_Stack.pop_back(); +} + +void +generate_uml::gen_composite_attribute_ref(std::ostream &os + , std::string &scope + , asn1::typeref *attribute + , asn1::node *_params) +{ + asn1::constructed *params = _params->as_constructed(); + asn1::reference *ref = attribute->get_reference(); + + if (ref->size() > 1) + { + // find the object and folow the links .... + std::string rname = ref->back().m_identifier; +// os<<"\tasn1::Object * /* GCAT "<begin(), + m_module->end(), + asn1::find_node(ref->name())); + if (refm != m_module->end()) + { + // Here I have the type definition. I should add + //os<<"\t"<cpp_name(); + os<<" type=\""<<(*refm)->uid()<<"\""; + + } else + { + asn1::node *ns = NULL; + if (type_in_imports(ref->name(),&ns) ) { + asn1::node *target = NULL; + get_type_in_module(ns->name(),ref->name(),&target); + asn1::reference::component_const_iterator compit = ref->begin(); + // Check first element of reference + if (target) { + os<<" type=\""<uid()<<"\""; + } + // check if attribute has parameters + if (attribute->parameters() != NULL) + { + os<<"<"; + for ( asn1::node::iterator it = attribute->parameters()->begin() + ; it != attribute->parameters()->end() + ; ++it) + { + asn1::node *ns1 = NULL; + if (it != attribute->parameters()->begin()) + os<<","; + // check namespace + if (type_in_imports((*it)->name(),&ns1) ) { + os<cpp_name()<<"::"<<(*it)->cpp_name(); + } else + os<<(*it)->cpp_name(); + } + os<<">"; + + } + } else if (params) // reference in parameters of definition + { + bool found = false; + for ( asn1::node::iterator it = params->begin() + ; it != params->end(); ++it) + { + if (ref->name().compare((*it)->name())== 0) + { + os<<"\t"<<(*it)->cpp_name(); + found = true; + } + } + + } else + { + // os<<" ERROR "; + } + } + + } +} + + + +void +generate_uml::gen_composite_attribute( std::ostream &os + , std::string &scope + , asn1::field *attribute + , asn1::node *params) +{ + asn1::typenode *attr_type = attribute->get_type(); + if (attr_type != NULL) + { + switch (attr_type->type_id()()) + { + case asn1::type::ASN1_ENUMERATED: + { + gen_enumerated( os + , *attr_type->as_enumerated() + , attribute->cpp_name()+"_t" + , true); + os<<"uid(); + os<<"\" type=\""<identifier()->uid(); + os<<"\" name=\""<cpp_name(); + os<<"\" visibility=\"public\"/>"; + } + break; + case asn1::type::ASN1_SET: + { + os<<"cpp_name(); + os<<"\" visibility=\"public\"/>"; + g_counter++; + } + break; + case asn1::type::ASN1_CHOICE: + { + attr_type->name(attribute->cpp_name()+"_t"); + gen_choice(os,attr_type->as_choice(),true); + os<<"uid(); + os<<"\" type=\""<uid()<<"\" name=\""; + os<cpp_name()<<"\" visibility=\"public\"/>"; + } + break; + case asn1::type::ASN1_SEQUENCE: + { + std::string scope("\t"); + attribute->get_type()->name(attribute->cpp_name()+"_t"); + assert(0); + gen_seq(os,scope,*attribute->get_type()->as_sequence()); + //os<<"\t\t"<<(attribute)->cpp_name()<<" : \"\",\n"; + os<<"uid(); + os<<"\" type=\""<get_type()->uid(); + os<<"\" name=\""<cpp_name(); + os<<"\" visibility=\"public\"/>"; + g_counter++; + } + break; + case asn1::type::ASN1_SELECTION: + { + } + break; + case asn1::type::ASN1_SET_OF: + case asn1::type::ASN1_SEQUENCE_OF: + { + //std::string scope(""); + asn1::typenode *type = attribute->get_type(); + asn1::typenode *subtype = type->get_eltype(); + switch (subtype->type_id()()) + { + case asn1::type::ASN1_SEQUENCE: + subtype->name((attribute)->cpp_name()+std::string("_type")); + gen_seq(os,scope,*subtype->as_sequence()); + os<<"\n"; + os<<"cpp_name()<<"\"/>\n"; + g_counter++; + break; + default: + asn1::node *ns; + if (type_in_imports(subtype,&ns) ) { + os<<"cpp_name()<<"\"/>\n"; + g_counter++; + } else + { + asn1::node *tn; + if (get_type_in_module(m_module->name(),subtype->name(),&tn)) { + os<<"uid()<<"\" visibility=\"public\""<<" name=\""<<(attribute)->cpp_name()<<"\">\n"; + os<<"\n"; + os<<"\n"; + os<<""; + } else + os<<"cpp_name()<<"\"/>\n"; + g_counter++; + } + } + } + break; + case asn1::type::ASN1_REFERENCE: + + { + os<<"as_typeref()) { + // New way to handle reference + gen_composite_attribute_ref(os,scope,ref,params); + } else { + os<<"type=\"\""; + } + os<<" name=\""<cpp_name()<<"\" visibility=\"public\"/>"; + g_counter++; + os<cpp_name(); + os<<"\" type=\"\" visibility=\"public\"/>"; + g_counter++; + os<<"\n"; + } + } + } +} + + + +/** + * + */ +void generate_uml::gen_set(std::ostream &os,asn1::set *n) +{ + std::string scope(""); + asn1::constructed *tp = n->as_constructed(); + asn1::node::iterator it = tp->begin(); + + os<<"cpp_name()<<"\" >\n"; + g_counter++; + for (; it != tp->end() ; it++) + { + asn1::field *f = dynamic_cast(*it); + asn1::typenode *type = f->get_type(); + if (type != NULL) + { + + switch (type->type_id()()) + { + case asn1::type::ASN1_SEQUENCE_OF: + case asn1::type::ASN1_SET_OF: + { + os<<"cpp_name()<<"\" visibility=\"public\"/>"; + g_counter++; + } + break; + default: + os<<"cpp_name()<<"\" visibility=\"public\"/>"; + g_counter++; + os<<"\n"; + } + } + } + os<<"\n"; + +} + + + +void generate_uml::gen_object_class_opt(std::ostream &os,asn1::assignment *n) +{ + asn1::constructed *type = n->get_type()->as_constructed(); + asn1::node::iterator it = type->begin(); + bool opt = false; + std::list l; + for ( ; it != type->end(); ++it) + { + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + if ( ((*it)->flags().m_flags & asn1::node::marker_type::FL_OPTIONAL) ) { + l.push_back(fieldname); + } + } + if (l.size()>0) { + os<<"\tstruct _present { \n"; + for (std::list::const_iterator it = l.begin(); it != l.end(); ++it) + { + if (1) { + os<<"\t\t"; + os<<"unsigned present"<<(*it)<<" : 1;\n"; + }else { + os<<"\t\tunsigned present"<<(*it)<<" : 1\n"; + } + } + os<<"\t} m;\n"; + } +} + +/** + * + * + */ +void generate_uml::gen_object_class_missing(std::ostream &os,asn1::assignment *n) +{ + asn1::constructed *type = n->get_type()->as_constructed(); + asn1::node::iterator it = type->begin(); + + + // cosntructors + + // generate optionnals + + // public methods + for ( ; it != type->end(); ++it) + { + asn1::field *ltype = dynamic_cast(*it); + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + switch(ltype->type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_FTVF: /* Fixed Type Value Field */ + os<get_type()); + break; + case asn1::type::ASN1_CLASSFIELD_TF: /* Type Field */ + os<get_type()->as_constructed(); + asn1::node::iterator it = type->begin(); + + + os<<"uid()<<"\" xmi:type=\"uml:Interface\" name=\"I"<cpp_name()<<"\">\n"; + + // public methods + for ( ; it != type->end(); ++it) + { + asn1::node *ltype = (*it); + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + switch(ltype->type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_FTVF: /* Fixed Type Value Field */ + os<<"uid()<<"\" name=\""<\n"; + break; + case asn1::type::ASN1_CLASSFIELD_TF: /* Type Field */ + os<<"uid()<<"\" name=\"codec"<\n"; + break; + case asn1::type::ASN1_CLASSFIELD_VTVF: /* Variable Type Value Field */ + os<"<get_type()->as_constructed(); + asn1::node::iterator it = type->begin(); + for ( ; it != type->end(); ++it) + { + asn1::classfield *ltype = dynamic_cast(*it); + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + os<<"\t//"<<(*it)->cpp_name()<<" type_id="<<(*it)->type_id()(); + //<type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_FTVF: /* Fixed Type Value Field */ + break; + case asn1::type::ASN1_CLASSFIELD_TF: /* Type Field */ + break; + case asn1::type::ASN1_CLASSFIELD_VTVF: /* Variable Type Value Field */ + break; + case asn1::type::ASN1_CLASSFIELD_FTVSF: /* Fixed Type Value Set Field */ + break; + case asn1::type::ASN1_CLASSFIELD_VTVSF: /* Variable Type Value Set Field*/ + os<get_type()->as_constructed(); + asn1::node::iterator it = type->begin(); + + for ( ; it != type->end(); ++it) + { + asn1::node *ltype = (*it); + std::string fieldname = (*it)->cpp_name(); + fieldname[0] = '_'; + + switch(ltype->type_id()()) + { + case asn1::type::ASN1_CLASSFIELD_FTVF: /* Fixed Type Value Field */ + break; + case asn1::type::ASN1_CLASSFIELD_TF: /* Type Field */ + if ( (ltype->flags().m_flags & asn1::node::marker_type::FL_OPTIONAL) ) + { + os<<"\t if (m.present"<cpp_name(); + os<<"\t"<<" : \"<get_type()->as_constructed(); + + gen_object_class_missing(os,n); + gen_object_class_interface(os,n); + + // generate optionnals + gen_object_class_printf(os,n); + gen_object_class_opt(os,n); + + // public methods + gen_object_class_attributes(os,n); +} +/** + * + * + */ +void generate_uml::gen_object(std::ostream &os,asn1::assignment *n) +{ + asn1::constructed *type = n->get_type()->as_constructed(); + asn1::node::iterator it = type->begin(); +// os<<"// generate_uml::"<<__FUNCTION__<<" "<name()<<"\n"; + os.flush(); + if (!type->name().compare("OPERATION")) + { + gen_object_operation(os,n); + } else + if (!type->name().compare("ERROR")) + { + gen_object_error(os,n); + } else if (!type->name().compare("OBJECT-TYPE")) + { + } +} + + + +/** + * + * + */ +void generate_uml::gen_object_error(std::ostream &os,asn1::node *n) +{ +} + + +void generate_uml::gen_object_operation(std::ostream &os,asn1::node *n) +{ +} + +/** + * + * + */ +void generate_uml::gen_object_operation_package(std::ostream &os,asn1::node *n) +{ +} +void generate_uml::gen_object_connection(std::ostream &os,asn1::node *n) +{ +} + + +class douml_assignment : public assignment_visitor +{ + public: + douml_assignment(std::ostream &_os,generate_uml &_gen) + : m_os(_os) , m_gen(_gen) + { + } +#define ASSIGNMENT(En,Tp,Parent,Code) \ + void visit_##Tp(asn1::Tp##_assignment *a) \ + Code +ASSIGNMENT(TYPEREF,typeref,assignment,{ + m_gen.gen_typeref(m_os,a->get_type()->as_typeref()); + }) +ASSIGNMENT(TYPE,type,assignment,{ + m_gen.gen_typedef(m_os,a->get_type()); + }) +ASSIGNMENT(VALUE,value,assignment,{ + m_gen.gen_const(m_os,a->get_type()); + }) +ASSIGNMENT(VALUESET,valueset,assignment,{ + std::cout<<__FUNCTION__<<" TODO"<name()<name()<name()<imports(); + std::fstream umlos; + std::string umlname = std::string(n->name()+".uml"); + umlos.open(umlname.c_str(),std::fstream::out); + umlos<<""<"; + umlos<<"cpp_name()<cpp_name()<<"\">"<sort_childs(); + asn1::node::iterator it = n->begin(); + + for (; it != n->end() ; it++) + { + asn1::assignment *a = dynamic_cast(*it); + GEN_LOG_DEBUG("Process item %s\n",a->name().c_str()); + if (a->get_type() != NULL) + { + if ( a->is_generated()) + { + GEN_LOG_DEBUG("item %s already generated\n",a->name().c_str()); + continue; + } + douml_assignment douml(umlos,*this); + douml.visit(a); + os<set_color(asn1::node::CL_RED); + } else + { + GEN_LOG_WARN("item %s of undefined type \n",(*it)->name().c_str()); + } + os<"; + umlos<<""; + umlos.close(); +} + +/** +* vim:et:sw=2:ts=2 +*/ diff --git a/libgen/uml/asn1_gen_uml.h b/libgen/uml/asn1_gen_uml.h new file mode 100644 index 0000000..991e5ed --- /dev/null +++ b/libgen/uml/asn1_gen_uml.h @@ -0,0 +1,97 @@ +#ifndef GEN_HEADER_UML_H__ +#define GEN_HEADER_UML_H__ +#include +#include + + +/** + * + */ +class generate_uml : public asn1::generator +{ + public: + + generate_uml(asn1::module *n); + + generate_uml(asn1::module *n,asn1::module::modules_type &m); + + virtual ~generate_uml() {} ; + + + void gen_missing(std::ostream &os,asn1::typenode *n) ; + + /** + * + * + */ + void gen_const(std::ostream &os,asn1::node *n); + + void gen_enumerated( std::ostream &os + , asn1::enumerated &n + , const std::string &name + , bool nested = false); + // + // + // + void gen_typedef(std::ostream &os,asn1::typenode *n); + void gen_typeref(std::ostream &os,asn1::typeref *n); + + /** + * + */ + void gen_seq( std::ostream &os + , std::string &scope + , asn1::sequence &n + ); + + void gen_choice( std::ostream &os + , asn1::choice *n + , bool nested=false); + + void gen_composite_attribute( std::ostream &os + , std::string &scope + , asn1::field *attribute + , asn1::node *params = NULL); + + void gen_composite_attribute_ref( std::ostream &os + , std::string &scope + , asn1::typeref *attribute + , asn1::node *params = NULL); + + void gen_template_params(std::ostream &os,asn1::node *params); + + void gen_template_signature(std::ostream &os,asn1::node *params); + + /** + * + */ + void gen_set( std::ostream &os + , asn1::set *n); + + /* + * Ros generation Code + */ + void gen_object_class(std::ostream &os,asn1::assignment *n); + void gen_object_class_interface(std::ostream &os,asn1::assignment *n); + void gen_object_class_missing(std::ostream &os,asn1::assignment *n); + void gen_object_class_opt(std::ostream &os,asn1::assignment *n); + void gen_object_class_attributes(std::ostream &os,asn1::assignment *n); + + void gen_object_class_printf(std::ostream &os, asn1::assignment *n); + + void gen_object(std::ostream &os,asn1::assignment *n); + void gen_object_error(std::ostream &os,asn1::node *n); + void gen_object_operation(std::ostream &os,asn1::node *n); + void gen_object_operation_package(std::ostream &os,asn1::node *n); + void gen_object_connection(std::ostream &os,asn1::node *n); + /** + * + */ + void gen_module(std::ostream &os,asn1::module *n); + protected: + std::vector m_Stack; +}; +/** + * vim:et:sw=2:ts=2 + */ +#endif diff --git a/libparser/CMakeLists.txt b/libparser/CMakeLists.txt new file mode 100644 index 0000000..b2c9902 --- /dev/null +++ b/libparser/CMakeLists.txt @@ -0,0 +1,60 @@ +PROJECT(libasn1parser) + +IF(CMAKE_CROSSCOMPILING) + SET(IMPORT_EXECUTABLES "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point to the + export file from native build") + INCLUDE(${IMPORT_EXECUTABLES}) +ENDIF(CMAKE_CROSSCOMPILING) + + +# Only for Linux not MAC +IF(APPLE) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG ") +ELSEIF(WIN32) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG ") +ELSE(APPLE) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -std=c++0x") + SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x") +ENDIF(APPLE) + +INCLUDE(${rules_SOURCE_DIR}/flex.cmake) + + +LEXGEN(asn1.l lasn1.cpp) +BISONGEN(asn1.y pasn1.cpp cpp) + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libgen) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../adt) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${aebutils_SOURCE_DIR}) + +IF (NOT CMAKE_CROSSCOMPILING) +ADD_LIBRARY(libasn1p + lasn1.cpp + pasn1.cpp + asn1_parser.cpp + ) +TARGET_LINK_LIBRARIES(libasn1p asn1adt) + + MESSAGE("Export Executables to ${CMAKE_BINARY_DIR}") + EXPORT(TARGETS libasn1p asn1adt FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake + NAMESPACE native-) +ENDIF(NOT CMAKE_CROSSCOMPILING) + +#IF(CMAKE_CROSSCOMPILING) +# SET(asn1p_EXE native-asn1p) +# GET_TARGET_PROPERTY(test ${asn1p_EXE} IMPORTED_LOCATION_DEBUG) +# SET(asn1p_EXE ${test}) +#ELSE(CMAKE_CROSSCOMPILING) +# SET(asn1p_EXE ${CMAKE_CURRENT_BINARY_DIR}/asn1p) +#ENDIF(CMAKE_CROSSCOMPILING) + + +# Install Stuff +#IF (NOT CMAKE_CROSSCOMPILING) +#INSTALL(TARGETS asn1p +# DESTINATION bin/) +#ENDIF(NOT CMAKE_CROSSCOMPILING) + + diff --git a/libparser/asn1.l b/libparser/asn1.l new file mode 100644 index 0000000..c5067d1 --- /dev/null +++ b/libparser/asn1.l @@ -0,0 +1,393 @@ +%{ +#include +#include +#include + +//#include "lasn1.hpp" +#include "asn1_node.h" +#include "asn1_constraint.h" +#include "asn1_module.h" + +/* +%option never-interactive +*/ +#if 0 +#undef YYSTYPE +typedef union +{ + asn1::node *node; + asn1::constraint *constraint; + asn1::module *module; +} YYSTYPE; +#define YYSTYPE_IS_DECLARED 1 +//#define YYSTYPE asn1::node +#define YYPARSER_PARAM yylval +#define YYLEX_PARAM yylval +#define YY_DECL int _asn1_lex(asn1::node *yylval) + asn1::node *node; + asn1::constraint *constraint; + asn1::module *module; + asn1::reference *reference; + asn1::reference::component *ref_comp; + asn1::value *value; + asn1::node::tag_type tag; + asn1::node::marker_type *marker; +} YYSTYPE; +#else +typedef union +{ + asn1::node *node; + asn1::constraint *constraint; + asn1::module *module; + asn1::reference *reference; + asn1::reference::component *ref_comp; +} YYSTYPE; +#define YYSTYPE_IS_DECLARED 1 +#define YY_DECL int _asn1_lex(YYSTYPE *yylval) +#endif + +#include "pasn1.hpp" + +long +asn1_atoi(const char *ptr); + +void _asn1_error(const char *s) { + printf("Failed line: %d %s <%s>\n",yylineno,s,yytext); +#if 1 + exit(1); +#endif +}; + +#define TOK(x) {return x;} +#define REF_TF { yylval->reference = new asn1::typefield_reference(yytext);return T_TYPEFIELDREFERENCE;} +#define REF_VF { yylval->reference = new asn1::valuefield_reference(yytext);return T_VALUEFIELDREFERENCE;} +#define NODE_TOK(x) { yylval->node = new asn1::node(yytext);return x;} + +#define NUM_TOK(x) { asn1::valuetype *vt = new asn1::valuetype(std::string(yytext),NULL);\ + (yylval)->node = vt; \ + asn1::value *v = new asn1::value(asn1::value::VT_INTEGER); \ + v->m_integer = asn1_atoi(yytext);\ + vt->value(v); \ + vt->value_long(asn1_atoi(yytext)); \ + return x;\ + } + +#define NUMV_TOK(x,val) { asn1::valuetype *vt = new asn1::valuetype(std::string(yytext),NULL);\ + (yylval)->node = vt; \ + asn1::value *v = new asn1::value(asn1::value::VT_INTEGER); \ + v->m_integer = val;\ + (yylval)->node->value(v); \ + (yylval)->node->value_long(val); \ + return x;\ + } +#define DOUBLE_TOK(x) { *yylval = new asn1::valuetype(std::string(yytext),NULL);return x;} +%} + +%option prefix="_asn1_" +%option stack +%option yylineno +/* +%option noyywrap stack +%option debug +*/ +%pointer + +%x dash_comment +%x idash_comment +%x cpp_comment +%x quote +%x opaque +%x encoding_control +%x with_syntax +%x object + +/* */ +Digits [0-9]+ +NDigits -{Digits} + +Real [-+]?[0-9]+[.]?([eE][-+]?)?[0-9]+ + + + +Char ([^\n\t\"\'\\]) +Char_Literal "'"({Char}|\")"'" +String_Literal \"({Char}|"'")*\" +HString '[0-9A-F \r\r\v\f\n]+'H +BString '[01 \t\r\v\f\n]+'B +Identifier [a-z][a-zA-Z0-9]*([-][a-zA-Z0-9]+)* +CapitalReference [A-Z][A-Z0-9]*([-][A-Z0-9]+)* +TypeReference [A-Z][A-Za-z0-9]*([-][A-Za-z0-9]+)* + +TypeFieldReference &{TypeReference} +ValueFieldReference &{Identifier} + +nl [\r\n\v\f] + +wsp [\t\r\v\f\n ] + +%% + +-{3,}/[\r\n] /* Comment */ + +-- yy_push_state(dash_comment); +-- yy_push_state(dash_comment); + +{ /* Very special to treat rules for dash_comment rules */ + {nl} yy_pop_state(); + -- yy_pop_state(); + - /* single dash */ + [^\r\v\f\n-]+ /* do nothing */ +} + +"/*" yy_push_state(cpp_comment); + +{ + [^*/<] /* skip */ + "*/" yy_pop_state(); + . /* skip */ +} + +"::=" TOK(T_ASSIGN) + +{BString} TOK(T_bstring) +{Digits} NUM_TOK(T_NUM) +{NDigits} NUM_TOK(T_NUM) + +ABSENT TOK(T_ABSENT) +ABSTRACT TOK(T_ABSTRACT) +ABSTRACT-SYNTAX TOK(T_ABSTRACT_SYNTAX) +ALL TOK(T_ALL) +ANY TOK(T_ANY) +APPLICATION TOK(T_APPLICATION) +AUTOMATIC TOK(T_AUTOMATIC) +BEGIN TOK(T_BEGIN) +BIT TOK(T_BIT) + +BMPString TOK(T_BMPString) +BOOLEAN TOK(T_BOOLEAN) +BY TOK(T_BY) +CHARACTER TOK(T_CHARACTER) +CHOICE TOK(T_CHOICE) +CLASS TOK(T_CLASS) +COMPONENT TOK(T_COMPONENT) +COMPONENTS TOK(T_COMPONENTS) +CONTAINING TOK(T_CONTAINING) +CONSTRAINED TOK(T_CONSTRAINED) +DATE TOK(T_DATE) +DATE-TIME TOK(T_DATE_TIME) +DEFAULT TOK(T_DEFAULT) +DEFINED TOK(T_DEFINED) /* Not reserved word in ASN1 may be old parser (ANY DEFINED BY) */ + +DEFINITIONS TOK(T_DEFINITIONS) +DURATION TOK(T_DURATION) +EMBEDDED +ENCODED TOK(T_ENCODED) +ENCODING-CONTROL TOK(T_ENCODING_CONTROL) +END TOK(T_END) +ENUMERATED TOK(T_ENUMERATED) +EXCEPT TOK(T_EXCEPT) +EXPLICIT TOK(T_EXPLICIT) +EXPORTS TOK(T_EXPORTS) +EXTENSIBILITY TOK(T_EXTENSIBILITY) +EXTERNAL TOK(T_EXTERNAL) +FALSE TOK(T_ASN1_FALSE) +FROM TOK(T_FROM) +GeneralizedTime TOK(T_GeneralizedTime) +GeneralString TOK(T_GeneralizedString) +GraphicString TOK(T_GraphicString) +{HString} TOK(T_hstring) +IA5String TOK(T_IA5String) +IDENTIFIER TOK(T_STR_IDENTIFIER) +IMPLICIT TOK(T_IMPLICIT) +IMPLIED TOK(T_IMPLIED) +IMPORTS TOK(T_IMPORTS) +INCLUDES TOK(T_INCLUDES) +INSTANCE TOK(T_INSTANCE) +INSTRUCTIONS TOK(T_INSTRUCTIONS) +INTEGER TOK(T_INTEGER) +INTERSECTION TOK(T_INTERSECTION) +ISO64String TOK(T_ISO646String) +MAX TOK(T_MAX) +MIN TOK(T_MIN) +MINUS-INFINITY TOK(T_MINUS_INFINITY) +NOT-A-NUMBER TOK(T_NOT_A_NUMBER) +NULL TOK(T_NULL) +NumericString TOK(T_NumericString) +ObjectDescriptor TOK(T_ObjectDescriptorString) +OBJECT TOK(T_OBJECT) +OCTET TOK(T_OCTET) +OF TOK(T_OF) +OID-IRI TOK(T_OID_IRI) +OPTIONAL TOK(T_OPTIONAL) +PATTERN TOK(T_PATTERN) +PDV +PLUS-INFINITY +PRESENT TOK(T_PRESENT) +PrintableString TOK(T_PrintableString) +PRIVATE +REAL TOK(T_REAL) +RELATIVE-OID TOK(T_RELATIVE_OID) +RELATIVE-OID-IRI TOK(T_RELATIVE_OID_IRI) +SEQUENCE TOK(T_SEQUENCE) +SET TOK(T_SET) +SETTINGS TOK(T_SETTINGS) +SIZE TOK(T_SIZE) +STRING TOK(T_STRING) +SYNTAX TOK(T_SYNTAX) +T61String TOK(T_T61String) +TAGS TOK(T_TAGS) +TeletexString TOK(T_TeletexString) +TIME TOK(T_TIME) +TIME-OF-DAY TOK(T_TIME_OF_DAY) +TRUE TOK(T_ASN1_TRUE) +UNION TOK(T_UNION) +UNIQUE TOK(T_UNIQUE) +UNIVERSAL TOK(T_UNIVERSAL) +UniversalString TOK(T_UniversalString) + +UTCTime TOK(T_UTCTime) +UTF8String TOK(T_UTF8String) + +VideotextString TOK(T_VideotextString) +VisibleString TOK(T_VisibleString) +WITH TOK(T_WITH) + + + + +{Identifier} NODE_TOK(T_IDENTIFIER) +{String_Literal} NODE_TOK(T_IDENTIFIER) +{CapitalReference} NODE_TOK(T_CAPITALREFERENCE) +{TypeReference} NODE_TOK(T_TYPEREFERENCE) +{TypeFieldReference} REF_TF +{ValueFieldReference} REF_VF + +[{][\t\r\v\f\n ]*[0-7][,][\t\r\v\f\n ]*[0-9]+[\t\r\v\f\n ]*[}] { + TOK(T_Tuple) +} + + +[{][\t\r\v\f\n ]*[0-9]+[,][\t\r\v\f\n ]*[0-9]+[,][\t\r\v\f\n ]*[0-9]+[,][\t\r\v\f\n ]*[0-9]+[\t\r\v\f\n ]*[}] { + TOK(T_Quadruple) + } + + +"<" TOK(T_LT) +"@" TOK(T_AT) +"!" TOK(T_EXCLAMATION) +"[" TOK(T_LBRACKET) +"]" TOK(T_RBRACKET) +"{" TOK(T_LBRACET) +"}" TOK(T_RBRACET) +")" TOK(T_RPARENTHESES) +"(" TOK(T_LPARENTHESES) +"." TOK(T_POINT) +".." TOK(T_TWOPOINT) +"..." TOK(T_THREEPOINT) +"," TOK(T_COMMA) +";" TOK(T_SIMILICON) +":" TOK(T_COLON) +"|" TOK(T_UNION) +"^" TOK(T_EXCEPT) +"_" TOK(T_USCORE) +{wsp}+ /* ignore whitespace*/ + +{ + {CapitalReference} NODE_TOK(T_CAPITALREFERENCE) + {TypeFieldReference} REF_TF + {ValueFieldReference} REF_VF + "," TOK(T_COMMA) + "}" TOK(T_RBRACET) + "[" TOK(T_LBRACKET) + "]" TOK(T_RBRACKET) + {wsp}+ /* ignore whitespace*/ +} + +{ + INTEGER TOK(T_INTEGER) + {Identifier} NODE_TOK(T_IDENTIFIER) + {String_Literal} NODE_TOK(T_IDENTIFIER) + {CapitalReference} NODE_TOK(T_CAPITALREFERENCE) + {TypeReference} NODE_TOK(T_TYPEREFERENCE) + {TypeFieldReference} REF_TF + {ValueFieldReference} REF_VF + "{" TOK(T_LOBJBRACET) + "}" TOK(T_RBRACET) + "<" TOK(T_LT) + "@" TOK(T_AT) + "!" TOK(T_EXCLAMATION) + "[" TOK(T_LBRACKET) + "]" TOK(T_RBRACKET) + ")" TOK(T_RPARENTHESES) + "(" TOK(T_LPARENTHESES) + "." TOK(T_POINT) + ".." TOK(T_TWOPOINT) + "..." TOK(T_THREEPOINT) + "," TOK(T_COMMA) + ";" TOK(T_SIMILICON) + ":" TOK(T_COLON) + "|" TOK(T_UNION) + "^" TOK(T_EXCEPT) + {wsp}+ /* ignore whitespace*/ + +} + + +{ + + . /**/ + END unput('D'); unput('N'); unput('E'); yy_pop_state(); + } + +%% +#if 0 +itu-t NUMV_TOK(T_NUM,0) +iso NUMV_TOK(T_NUM,1) +joint-iso-itu-t NUMV_TOK(T_NUM,2) +joint-iso-ccitt NUMV_TOK(T_NUM,2) +#endif +void enable_with_syntax() +{ + yy_push_state(with_syntax); +} +void disable_with_syntax() +{ + yy_pop_state(); +} + +void enable_encoding_control() +{ + yy_push_state(encoding_control); +} + +void enable_object() +{ + yy_push_state(object); +} +void disable_object() +{ + yy_pop_state(); +} + + + +long +asn1_atoi(const char *ptr) +{ + long ret; + return atol(ptr); +} + +double +asn1_atod(const char *ptr) +{ + double ret; + errno = 0; + ret = strtod(ptr,0); + if (errno) + { + std::cerr<<" Value out range : "< +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include "asn1_node.h" +#include "asn1_constraint.h" +#include "asn1_reference.h" +#include "asn1_value.h" +#include "asn1_parser.h" + +typedef union +{ + asn1::node *node; + asn1::constraint *constraint; + asn1::module *module; + asn1::reference *reference; + asn1::reference::component *ref_comp; + asn1::value *value; + asn1::node::tag_type tag; + asn1::node::marker_type *marker; + asn1::syntax_parser::fragment *fragment; + asn1::classfield *classfield; + asn1::parameter *parameter; + asn1::assignment *assignment; +} YYSTYPE; +#define YYSTYPE_IS_DECLARED 1 + +#if defined(__MINGW32__) +# define SIZE_T_SPECIFIER "%Iu" +#elif defined(__GNUC__) || defined(__APPLE__) +# define SIZE_T_SPECIFIER "%zu" +#else +# define SIZE_T_SPECIFIER "%ld" +#endif +extern void _asn1_error( const char *s); +extern int _asn1_lex(YYSTYPE *yylval); +extern void enable_with_syntax(void); +extern void enable_encoding_control(void); +extern void disable_with_syntax(void); +extern void enable_object(void); +extern void disable_object(void); +//#include "lasn1.cpp" + +static +asn1::parser *gParser = asn1::parser::instance(); + +#if defined(__GNUC__) && defined(DEBUG) +#define ASN_LOG_DEBUG(fmt,args...) do {\ + char _lbuf[256]; \ + if ( gLog.is_open()) { \ + gLog<<"DEBUG "; \ + sprintf(_lbuf,fmt,##args); gLog<<_lbuf; \ + sprintf(_lbuf," (asn1.y : %d)\n",__LINE__); gLog<<_lbuf; \ + } else if (gParser->debug_console() ) { \ + fprintf(stderr,"asn1_parser (DEBUG): "); \ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (asn1.y : %d)\n",__LINE__);\ + } \ +} while (0) + +#define ASN_LOG_WARNING(fmt,args...) do {\ + char _lbuf[256]; \ + if (gLog.is_open()) { \ + gLog<<"WARN "; \ + sprintf(_lbuf,fmt,##args); gLog<<_lbuf; \ + sprintf(_lbuf," (asn1.y : %d)\n",__LINE__); gLog<<_lbuf; \ + } \ + fprintf(stderr,"asn1_parser (WARNI): "); \ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (asn1.y : %d)\n",__LINE__);\ +} while (0) + +#define ASN_LOG_ERROR(fmt,args...) do {\ + char _lbuf[256]; \ + if ( gLog.is_open()) { \ + gLog<<"ERROR "; \ + sprintf(_lbuf,fmt,##args); gLog<<_lbuf; \ + sprintf(_lbuf," (asn1.y : %d)\n",__LINE__); gLog<<_lbuf; \ + } \ + fprintf(stderr,"asn1_parser (ERROR): "); \ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (asn1.y : %d)\n",__LINE__);\ +} while (0) + +static std::fstream gLog; + +void open_log(const std::string &fn) +{ + struct stat st; + // Check if gLog directory exists + if (stat("log",&st) == -1 ) { +#ifdef WIN32 + mkdir("log"); +#else + mkdir("log",0777); +#endif + } + // + std::string _logname("log/"); _logname.append(fn); _logname.append(".parser.log"); + if ( gLog.is_open()) + { + std::cerr<<"open_log "< OidMapType; +typedef OidMapType::iterator OidMapIterator; +typedef OidMapType::const_iterator OidMapConstIterator; + +static OidMapType oid_map; + +static asn1::module * get_current_module ( void ) +{ + asn1::parser *p = asn1::parser::instance(); + return (asn1::module *) p->module(); +} +static asn1::reference * current_ref; +static asn1::classdef *gCurrentClassDef = NULL; + +%} + +%token T_ABSENT +%token T_ABSTRACT +%token T_ABSTRACT_SYNTAX +%token T_ALL +%token T_ANY +%token T_APPLICATION +%token T_ASN1_TRUE +%token T_ASN1_FALSE +%token T_ASSIGN +%token T_AT +%token T_AUTOMATIC +%token T_BEGIN +%token T_BIT +%token T_BOOLEAN +%token T_BY +%token T_CAPITALREFERENCE +%token T_CHARACTER +%token T_CHOICE +%token T_CLASS +%token T_COLON +%token T_COMPONENT +%token T_COMPONENTS +%token T_CONTAINING +%token T_DATE +%token T_DATE_TIME +%token T_CONSTRAINED +%token T_DEFAULT +%token T_DEFINITIONS +%token T_DURATION +%token T_ENCODED +%token T_ENCODING_CONTROL +%token T_END +%token T_EXPLICIT +%token T_EXCEPT +%token T_EXCLAMATION +%token T_EXPORTS +%token T_EXTENSIBILITY +%token T_EXTERNAL +%token T_IDENTIFIER +%token T_IMPLICIT +%token T_IMPLIED +%token T_INCLUDES +%token T_INSTANCE +%token T_INSTRUCTIONS +%token T_INTEGER +%token T_INTERSECTION +%token T_LT +%token T_MAX +%token T_MIN +%token T_MINUS_INFINITY +%token T_NOT_A_NUMBER +%token T_NULL +%token T_NUM +%token T_OCTET +%token T_OPTIONAL +%token T_OF +%token T_OID_IRI +%token T_OBJECT +%token T_Quadruple +%token T_POINT +%token T_PATTERN +%token T_PRESENT +%token T_PRIVATE +%token T_REAL +%token T_RELATIVE_OID +%token T_RELATIVE_OID_IRI +%token T_SIMILICON +%token T_SEQUENCE +%token T_SET +%token T_SETTINGS +%token T_SIZE +%token T_STRING +%token T_SYNTAX +%token T_Tuple +%token T_UNION +%token T_UNIVERSAL +%token T_UNIQUE +%token T_STR_IDENTIFIER +%token T_TYPEREFERENCE +%token T_TYPEFIELDREFERENCE +%token T_VALUEFIELDREFERENCE +%token T_DEFINED +%token T_TAGS +%token T_UTCTime +%token T_GeneralizedTime +%token T_GeneralizedString +%token T_GraphicString +%token T_BMPString +%token T_IA5String +%token T_ISO646String +%token T_NumericString +%token T_ObjectDescriptorString +%token T_PrintableString +%token T_TeletexString +%token T_TIME +%token T_TIME_OF_DAY +%token T_T61String +%token T_UniversalString +%token T_UTF8String +%token T_VideotextString +%token T_VisibleString +%token T_FROM +%token T_IMPORTS +%token T_ENUMERATED +%token T_PLUS +%token T_MINUS +%token T_LPARENTHESES +%token T_RPARENTHESES +%token T_LBRACET +%token T_LOBJBRACET +%token T_RBRACET +%token T_LBRACKET +%token T_RBRACKET +%token T_COMMA +%token T_TWOPOINT +%token T_THREEPOINT +%token T_WITH +%token T_USCORE +%token T_bstring +%token T_hstring + +%type explicit_implicit opt_explicit_implicit +%type tag_class +%type tag +%type tag_type +%type opt_tag + +%type definitions +%type alternative_type +%type component_type +%type component_type_lists +%type constant_list +%type constant +%type opt_component_type_lists +%type extension_and_exception +%type exception_spec +%type at_notation_list +%type at_notation_element +%type opt_constraint_def +%type constraint_def +%type contents_constraint +%type general_constraint_def +%type user_defined_constraint +%type subtype_constraint_def +%type set_of_constraints +%type value_range +%type component_relation_constraint +%type constraint_range_spec +%type constraint_subtype_element +%type constraint_spec_subtype_element +%type inner_type_constraint +%type table_constraint +%type simple_table_constraint +%type opt_presence_constraint +%type component_id_list + +%type contained_subtype +%type opt_imports +%type imports_def +%type import_item +%type identifier +%type opt_identifier +%type oclass_field +%type pos_neg_identifier +%type definitions_id +%type referenced_type +%type token +%type type_constant_list +%type type_constant +%type type +%type type_reference +%type type_declaration +%type builtin_type +%type defined_type +%type type_assign_right +%type type_assign_right_tag +%type type_assign_right_tag_default +%type constant_set_def +%type object_assignment +%type type_assignment +%type complex_type_reference +%type complex_type_reference_amp_list +%type complex_type_reference_element +%type value_assignment +%type object_set_assignment +%type object_class_reference +%type obj_constant_list +%type obj_constant +%type defined_object +%type definition_module +%type object_defn +%type parameterized_value +%type parameterized_objectset +%type primitive_field_reference +%type field_name +%type pos_num +%type neg_num +%type pos_neg_num +%type component_value +%type component_value_list +%type value +%type value_reference +%type character_string_def +%type restricted_character_string_def +%type unrestricted_character_string_def +%type restricted_character_string_value +%type defined_value +%type builtin_value +%type value_from_object +%type value_set +%type object_set +%type object +%type defined_object_class +%type set_def +%type set_value +%type sequence_def +%type choice_def +%type defined_syntax_list +%type parameter_list +%type parameter_args +%type parameter_arg +%type act_parameter_args +%type act_parameter_arg +%type default_syntax +%type defined_syntax +%type defined_syntax_token +%type general_string_def +%type element_set_specs +%type element_set_spec +%type integer_def +%type real_def +%type enumerated_def +%type boolean_def +%type time_def +%type any_def +%type octet_string_def +%type object_def +%type object_class_def +%type bit_string_def +%type bit_element_def +%type bit_element_list +%type export_element export_list +%type with_components_list +%type with_components_element +%type which_list +%type default +%type opt_default + +%type opt_token syntax_token_list + +%name-prefix="_asn1_" +%pure-parser + + +%% + +definition_files:definitions + { + asn1::module *m = get_current_module ( ); + ASN_LOG_DEBUG("definition_files: got definition" ); + } + | definition_files definitions + { + asn1::module *m = get_current_module ( ); + ASN_LOG_DEBUG("definition_files: got 1 definition" ); + } +; + + +/** + * export rules + */ +opt_exports: + | exports_def +; + +exports_def: + T_EXPORTS { + asn1::parser *p = asn1::parser::instance(); + $$ = get_current_module(); + $$->enter_context(new asn1::exports()); + } export_list T_SIMILICON + { + ASN_LOG_DEBUG("exports_def: got exports" ); + asn1::node *res = $2->leave_context(); + $$ =res; + } + | T_EXPORTS T_ALL T_SIMILICON + { + ASN_LOG_DEBUG("exports_def: got exports ALL" ); + asn1::exports *exp = new asn1::exports(); + exp->all(true); + $$ = exp; + } + | T_EXPORTS T_SIMILICON + { + ASN_LOG_DEBUG("exports_def: got exports nothing" ); + } +; + +export_list: export_element + { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + ASN_LOG_DEBUG("export_list: CM %s Got Item: %s" + , m->name().c_str() + , $1->name().c_str()); + m->enter_symbol($1,$1->type_id()()); + } + | export_list T_COMMA export_element + { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + ASN_LOG_DEBUG("import_list: CM %s Got Item 1: %s" + , m->name().c_str() + , $3->name().c_str()); + m->enter_symbol($3,$3->type_id()()); + } +; + +export_element: T_TYPEREFERENCE + { + ASN_LOG_DEBUG("export_element: got typeref" ); + $$ = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + delete $1; + } + | T_TYPEREFERENCE T_LBRACET T_RBRACET + { + ASN_LOG_DEBUG("export_element: got typeref {}" ); + $$ = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + delete $1; + } + | T_IDENTIFIER + { + ASN_LOG_DEBUG("export_element: got identifier" ); + $$ = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + delete $1; + } +; + +/** + * + */ +opt_imports: /* Empty*/ + { + $$ = NULL; + } + | imports_def { + $$ = $1; + } +; + +imports_def: + T_IMPORTS + { + asn1::parser *p = asn1::parser::instance(); + $$ = get_current_module(); + $$->enter_context(new asn1::import_list()); + } import_set T_SIMILICON + { + asn1::node *res = $2->leave_context(); + $$ =res; + } + | T_IMPORTS T_FROM T_SIMILICON { + $$ = NULL; + } + ; + +import_set: + import { + ASN_LOG_DEBUG("import_set got import"); + } + | import_set import { + ASN_LOG_DEBUG("import_set: 1 got import"); + } +; + +import: + { + $$ = get_current_module(); + ASN_LOG_DEBUG("import: start Module %s " + ,$$->name().c_str() + ); + $$->enter_context(new asn1::import("IMPORT")); + } + import_list + { + $$ = $1->leave_context(); + } T_FROM definitions_id + { + + asn1::module *m = get_current_module(); + ASN_LOG_DEBUG("import: Module %s Got import %s " + ,m->name().c_str() + ,$5->name().c_str()); + $3->identifier($5); + $3->name($5->name()); + m->enter_symbol($3,$3->type_id()()); + } +; + +import_list: + import_item { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + ASN_LOG_DEBUG("import_list: CM %s Got Item: %s" + , m->name().c_str() + , $1->name().c_str()); + m->enter_symbol($1,$1->type_id()()); + } + | import_list T_COMMA import_item { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + ASN_LOG_DEBUG("import_list: CM %s Got Item 1: %s" + , m->name().c_str() + , $3->name().c_str()); + m->enter_symbol($3,$3->type_id()()); + } +; + +import_item: + T_TYPEREFERENCE { + ASN_LOG_DEBUG("import_item: %s typeref",$1->name().c_str()); + $$ = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + delete $1; + } + | T_TYPEREFERENCE T_LBRACET T_RBRACET { + ASN_LOG_DEBUG("import_item: %s parameterized typeref",$1->name().c_str()); + $$ = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + delete $1; + } + | identifier + { + ASN_LOG_DEBUG("import_item: %s identifier what is it? value",$1->name().c_str()); + $$ = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name(),asn1::reference::component::Lowercase) + ); + delete $1; + } + | T_CAPITALREFERENCE { + ASN_LOG_DEBUG("import_item: %s CAPITAL what is it?",$1->name().c_str()); + $$ = new asn1::typeref($1->name(), + new asn1::objectclass_reference($1->name()) + ); + delete $1; + } + | T_CAPITALREFERENCE T_LBRACET T_RBRACET { + ASN_LOG_DEBUG("import_item: %s CAPITAL {} what is it?",$1->name().c_str()); + $$ = new asn1::typeref($1->name(), + new asn1::objectclass_reference($1->name()) + ); + delete $1 ; + } +; +/** + * main definition entry + */ +definitions: definitions_id + T_DEFINITIONS opt_explicit_implicit opt_tags_def T_ASSIGN T_BEGIN /* imports_def */ + { + asn1::parser *p = asn1::parser::instance(); + $$ = p->module($1->name().c_str()); + $$->tag($3); +#ifdef DEBUG + if (! gLog.is_open()) + open_log($1->name()); +#endif + ASN_LOG_DEBUG("definitions: start 1 size=%zu %s def=%s pn=%s" + ,$$->size() + ,$$->name().c_str() + ,$1->name().c_str() + ,p->module()->name().c_str() + ); + } + definition_module T_END { + asn1::parser *p = asn1::parser::instance(); + ASN_LOG_DEBUG("definitions: 1 size=" SIZE_T_SPECIFIER " %s cm=%s" + ,$8->size() + ,$8->name().c_str() + ,p->module()->name().c_str() + ); + asn1::module *m = $8; + close_log(); + } +; + +definition_module: opt_exports opt_imports + { + asn1::import_list *i = dynamic_cast($2); + asn1::exports *e = dynamic_cast($2); + asn1::module *m = get_current_module(); + m->imports(i); + m->exports(e); + } type_constant_list + { + $$ = $4; + } + ; + +opt_tags_def: /* Empty */ + | T_TAGS + { + ASN_LOG_DEBUG("opt_tags_def just TAGS"); + } + | T_TAGS opt_defs + { + ASN_LOG_DEBUG("opt_tags_def "); + } +; + +opt_defs: opt_def + | opt_defs opt_def +; + +opt_def: T_EXTENSIBILITY { + ASN_LOG_DEBUG("opt_def EXTENSIBILITY"); + } + | T_IMPLIED { + ASN_LOG_DEBUG("opt_def IMPLIED"); + } +; + +opt_identifier: { $$ = NULL;} + | identifier + { + $$ = $1; + } +; +identifier: T_IDENTIFIER + {$$ = $1;} +; + +pos_num: T_NUM { + ASN_LOG_DEBUG("pos_num got Num: %s",$1->name().c_str()); + $$=$1; + $$->type_id(asn1::type::ASN1_INTEGER); + } + | T_PLUS T_NUM { + $$=$2; + $$->type_id(asn1::type::ASN1_INTEGER); + } + +; + +neg_num: T_MINUS T_NUM { + $$ = $2; + $$->type_id(asn1::type::ASN1_INTEGER); + } +; + +pos_neg_num: pos_num { + $$ = $1; + $$->meta_id(asn1::meta::VALUE); + } + | neg_num { + $$ = $1; + $$->meta_id(asn1::meta::VALUE); + } +; + +pos_neg_identifier: + pos_num { + $$ = $1; + } + | neg_num { + $$ = $1; + } + | identifier { + ASN_LOG_ERROR("pos_neg_identifier: MUST BE TRANSFORMED TO valuetype%s",$1->cpp_name().c_str()); + $$ = $1; + $$->type_id(asn1::type::ASN1_REFERENCE); + $$->meta_id(asn1::meta::VALUE); + } +; + +constant: T_LPARENTHESES pos_neg_num T_RPARENTHESES + { + $$ = $2; + } + | T_IDENTIFIER T_LPARENTHESES pos_neg_num T_RPARENTHESES + { + $$ = $3; + $$->name($1->name()); + delete $1; + } +; + +constant_list: + constant { + ASN_LOG_DEBUG("constant_list: %s",$1->cpp_name().c_str()); + asn1::module *m= get_current_module(); + m->enter_symbol($1,$1->type_id()()); + } + | constant_list T_COMMA constant { + ASN_LOG_DEBUG("constant_list 1: %s",$3->cpp_name().c_str()); + asn1::module *m= get_current_module(); + m->enter_symbol($3,$3->type_id()()); + } +; + +obj_constant: pos_num { + ASN_LOG_DEBUG("obj_constant: %s",$1->cpp_name().c_str()); + $$ = $1; + } + | T_IDENTIFIER T_LPARENTHESES T_NUM T_RPARENTHESES { + ASN_LOG_DEBUG("obj_constant 1: %s",$1->cpp_name().c_str()); + $$ = $3; + oid_map[$1->name()] = dynamic_cast($3); + $$->name($1->name()); + $$->type_id(asn1::type::ASN1_INTEGER); + delete($1); + } +/* predefined identifiers +itu-t NUMV_TOK(T_NUM,0) +iso NUMV_TOK(T_NUM,1) +joint-iso-itu-t NUMV_TOK(T_NUM,2) +joint-iso-ccitt NUMV_TOK(T_NUM,2) +*/ + | T_IDENTIFIER { + OidMapIterator it = oid_map.find($1->name()) ; + if ( !$1->name().compare("itu-t")) + { + asn1::value *v = new asn1::value(asn1::value::VT_INTEGER); + asn1::valuetype *vt = new asn1::valuetype($1->name(),v); + $$->type_id(asn1::type::ASN1_INTEGER); + vt->value_long(0); + $$ = vt; + delete($1); + } else if ( !$1->name().compare("iso")) + { + asn1::value *v = new asn1::value(asn1::value::VT_INTEGER); + asn1::valuetype *vt = new asn1::valuetype($1->name(),v); + $$->type_id(asn1::type::ASN1_INTEGER); + vt->value_long(1); + $$ = vt; + delete($1); + } else if ( !$1->name().compare("joint-iso-itu-t")) + { + asn1::value *v = new asn1::value(asn1::value::VT_INTEGER); + asn1::valuetype *vt = new asn1::valuetype($1->name(),v); + $$->type_id(asn1::type::ASN1_INTEGER); + vt->value_long(2); + $$ = vt; + delete($1); + } else if ( !$1->name().compare("joint-iso-ccitt")) + { + asn1::value *v = new asn1::value(asn1::value::VT_INTEGER); + asn1::valuetype *vt = new asn1::valuetype($1->name(),v); + $$->type_id(asn1::type::ASN1_INTEGER); + vt->value_long(2); + $$ = vt; + delete($1); + } else if (it != oid_map.end()) + { + ASN_LOG_DEBUG("obj_constant IDENTIFIER found in map %s",$1->cpp_name().c_str()); + $$ = it->second; + } else + { + ASN_LOG_ERROR("obj_constant IDENTIFIER 3 must be referenced: %s",$1->cpp_name().c_str()); + $$ = $1; + } + } +; + +obj_constant_list: + obj_constant { + ASN_LOG_DEBUG("obj_constant_list: %s",$1->cpp_name().c_str()); + asn1::module *m = get_current_module(); + m->enter_context(new asn1::object_identifier()); + m->enter_symbol($1,$1->type_id()()); + $$ = $1; + } + | obj_constant_list obj_constant { + ASN_LOG_DEBUG("obj_constant_list: append: $1=%s %s",$1->cpp_name().c_str(),$2->cpp_name().c_str()); + asn1::module *m = get_current_module(); + m->enter_symbol($2,$2->type_id()()); + } +; + +tag_class: + { + $$.m_class = asn1::node::tag_type::TC_CONTEXT_SPECIFIC;} + | T_UNIVERSAL { + $$.m_class = asn1::node::tag_type::TC_UNIVERSAL; + } + | T_PRIVATE { + $$.m_class = asn1::node::tag_type::TC_PRIVATE; + } + | T_APPLICATION { + $$.m_class = asn1::node::tag_type::TC_APPLICATION; + } +; + +tag_type: + tag_class T_NUM { + asn1::node *n = $2; + asn1::valuetype *vt = dynamic_cast(n); + $$ = $1; + $$.m_mode = asn1::node::tag_type::TM_DEFAULT; + $$.m_value = vt->value_long(); + delete $2; + } +; + +tag: + tag_type { + $$ = $1; + $$.m_set = true; + } + | T_LBRACKET tag_type T_RBRACKET { + ASN_LOG_DEBUG("tag: tag_type 1 [%d,%ld] ",$2.m_class,$2.m_value); + $$ = $2; + $$.m_set = true; + } + | tag_type explicit_implicit { + ASN_LOG_DEBUG("tag: tag_type [%d,%ld] explicit_implicit %d",$1.m_class,$1.m_value,$2.m_mode); + $$ = $1; + $$.m_mode = $2.m_mode; + $$.m_set = true; + } + | T_LBRACKET tag_type T_RBRACKET explicit_implicit { + ASN_LOG_DEBUG("tag: tag_type 1 [%d,%ld] explicit_implicit %d",$2.m_class,$2.m_value,$4.m_mode); + $$ = $2; + $$.m_mode = $4.m_mode; + $$.m_set = true; + + } +; + +opt_tag: + { + $$.m_class = asn1::node::tag_type::TC_NOCLASS; + $$.m_mode = asn1::node::tag_type::TM_DEFAULT; + $$.m_value = -1; + $$.m_set = false; + } + | tag { + ASN_LOG_DEBUG("opt_tag: tag cls=%d mode=%d val=%ld",$1.m_class,$1.m_mode,$1.m_value); + $$ = $1; + $$.m_set = true; + } +; + +default: T_DEFAULT value { + ASN_LOG_DEBUG("default: with value"); + $$ = new asn1::node::marker_type(asn1::node::marker_type::FL_DEFAULT); + aeb::intrusive_ptr p($2->value()); + $$->m_value1 = p; + } + +; + +opt_default: + { + ASN_LOG_DEBUG("opt_default: none"); + $$ = new asn1::node::marker_type(); + } + | default { + ASN_LOG_DEBUG("opt_default: default"); + $$ = $1 ; + } + | T_OPTIONAL { + ASN_LOG_DEBUG("opt_default: optional"); + $$ = new asn1::node::marker_type(asn1::node::marker_type::FL_OPTIONAL); + } +; + + +integer_def: + T_INTEGER { + $$ = new asn1::integer(); + $$->meta_id(asn1::meta::TYPE); + } + | T_INTEGER T_LBRACET { + asn1::module *m= get_current_module(); + m->enter_context(new asn1::integer()); + $$ = m; + } constant_list T_RBRACET { + $$ = $3->leave_context(); + ASN_LOG_DEBUG("integer_def has constant_list"); + $$->meta_id(asn1::meta::TYPE); + } +; + + +real_def: + T_REAL { + $$ = new asn1::real(); + } +; + +boolean_def: T_BOOLEAN + { $$ = new asn1::boolean();} +; + +time_def: T_UTCTime + {$$ = new asn1::utctime();} + | T_GeneralizedTime + {$$ = new asn1::generalizedtime();} +; + +/* See X.682 */ +general_constraint_def: + user_defined_constraint { + ASN_LOG_DEBUG("general_constraint_def: user_defined_constraint %s",($1==NULL)?"none":$1->name().c_str()); + } + | table_constraint { + ASN_LOG_DEBUG("general_constraint_def: table_constraint %s",$1->name().c_str()); + } + | contents_constraint { + ASN_LOG_DEBUG("general_constraint_def: content_constraint %s ",$1->name().c_str()); + } +; + +user_defined_constraint: + T_CONSTRAINED T_BY T_LBRACET T_RBRACET { + ASN_LOG_DEBUG("user_defined_constraint constraint by empty"); + $$ = new asn1::ctype_ctdby(); + } + | T_CONSTRAINED T_BY T_LBRACET type T_RBRACET { + ASN_LOG_DEBUG("user_defined_constraint contrained by type: %s",$4->name().c_str()); + $$ = new asn1::ctype_ctdby(); + $$->value($4); + } +; + +table_constraint: + simple_table_constraint { + ASN_LOG_DEBUG("table_constraint:simple_table_constraint TODO %s" + , $1->value()->name().c_str()); + } + | component_relation_constraint { + ASN_LOG_DEBUG("component_relation_constraint TODO"); +} +; + +simple_table_constraint: + T_LBRACET type_reference T_RBRACET { + // The rules is wrong. According to X.681 simple_table_constraint ::= ObjectSet + // and ObjectSet ::= { ObjectSetSpec} + // and ObjectSetSpec = RootElementSetSpec, ... + ASN_LOG_DEBUG("simple_table_constraint {typeref=%s} CHECK constraint type",$2->name().c_str()); + //$$ = new asn1::constraint("VALUE",asn1::constraint::EL_VALUE); + //TODO Is the line below correct ? + //$$->value($2); + $$ = new asn1::celt_type($2->as_typeref()); + asn1::module *m = get_current_module(); + $2->set_parent(m->current_context()); + } +; + +component_relation_constraint: simple_table_constraint T_LBRACET at_notation_list T_RBRACET + { + ASN_LOG_DEBUG("component_relation_constraint %s {@ %s}",$1->name().c_str(),$3->name().c_str()); + $$ = new asn1::ca_crc(); + $$->append($1); + $$->append($3); + } +; + +at_notation_list: at_notation_element { + ASN_LOG_WARNING("at_notation_list: simple TODO "); + } + | at_notation_list T_COMMA at_notation_element { + ASN_LOG_WARNING("at_notation_list: TODO "); + } +; + +at_notation_element: + T_AT component_id_list { + ASN_LOG_DEBUG("at_notation_element: TODO @ %s",$2->name().c_str()); + $$ = new asn1::constraint("VALUE",asn1::constraint::EL_VALUE); + $2->meta_id(asn1::meta::VALUE); + $$->value($2); + } + | T_AT T_POINT component_id_list { + ASN_LOG_DEBUG("at_notation_element: point TODO"); + $$ = new asn1::constraint("VALUE",asn1::constraint::EL_VALUE); + $3->meta_id(asn1::meta::VALUE); + $$->value($3); +} +; + +component_id_list: + T_IDENTIFIER { + ASN_LOG_DEBUG("component_id_list: TODO @ %s",$1->name().c_str()); + + } + | component_id_list T_POINT T_IDENTIFIER { + ASN_LOG_ERROR("component_id_list: TODO @. %s ",$3->name().c_str()); + } +; + +contents_constraint: T_CONTAINING type_reference { + ASN_LOG_DEBUG("contents_contraint %s ",$2->name().c_str()); + $$ = new asn1::ctype_ctng(); + $$->value($2); + } + | T_ENCODED T_BY T_IDENTIFIER { + ASN_LOG_DEBUG("contents_contraint 1 %s ",$3->name().c_str()); + $$ = new asn1::celt_encodedby(); + } + | T_CONTAINING type_reference T_ENCODED T_BY T_IDENTIFIER { + ASN_LOG_DEBUG("contents_contraint 2 %s ",$2->name().c_str()); + $$ = new asn1::ctype_ctng(); + $$->value($2); + } +; + +constraint_def: subtype_constraint_def + { + $$ = $1; + ASN_LOG_DEBUG("constraint_def subtype_constraint_def type=%d %s",$$->type(),$$->name().c_str()); + } + /* Found in X.682 45.6*/ + /* Rule in set of constraint + | T_LPARENTHESES element_set_specs exception_spec T_RPARENTHESES + { + printf("constraint_def 1\n"); + } + | T_LPARENTHESES general_constraint_def exception_spec T_RPARENTHESES + { + printf("constraint_def\n"); + $$ = $2; + } + */ +; + +subtype_constraint_def: + set_of_constraints { + ASN_LOG_DEBUG("subtype_constraint_def: set_of_constraints"); + if ($1->size() == 1) + { + // There is only one constraint, erase set and return element + $$ = *($1->begin()); + delete($1); + } else + $$ = $1; + } + | T_SIZE T_LPARENTHESES element_set_specs T_RPARENTHESES { + ASN_LOG_DEBUG("subtype_constraint_def: T_SIZE %s",$3->name().c_str()); + $$ = new asn1::ctype_size(); + $$->append($3); + } + +; + +set_of_constraints: + T_LPARENTHESES element_set_specs exception_spec T_RPARENTHESES + { + ASN_LOG_DEBUG("set_of_constraints 1 ( %s)",$2->name().c_str()); + $$ = new asn1::ca_set(); + $$->append($2); + } + | T_LPARENTHESES general_constraint_def exception_spec T_RPARENTHESES + { + ASN_LOG_DEBUG("set_of_constraints 2 ( )"); + $$ = new asn1::ca_set(); + $$->append($2); + } + | set_of_constraints T_LPARENTHESES general_constraint_def exception_spec T_RPARENTHESES + { + ASN_LOG_DEBUG("set_of_constraints 3 set ( gen) REWORK"); + $$ = $1; + $$->append($3); + } + | set_of_constraints T_LPARENTHESES element_set_specs exception_spec T_RPARENTHESES + { + ASN_LOG_DEBUG("set_of_constraints 4 set (elem ) REWORK"); + $$ = $1; + $$->append($3); + } +; + +element_set_specs: + T_THREEPOINT { + ASN_LOG_DEBUG("element_set_specs ... "); + $$ = new asn1::celt_ext(); + } + | element_set_spec { + if ($1!= NULL) { + ASN_LOG_DEBUG("element_set_specs got one not null %s",$1->name().c_str()); + } else { + ASN_LOG_DEBUG("element_set_specs got NULL "); + } + $$ = $1; + } + | element_set_spec T_COMMA T_THREEPOINT { + ASN_LOG_DEBUG("element_set_specs , ... "); + $$ = $1; + $$->append(new asn1::celt_ext()); + } + | element_set_spec T_COMMA T_THREEPOINT T_COMMA element_set_spec { + ASN_LOG_DEBUG("element_set_specs , ... , set_spec "); + $$ = $1; + $$->append(new asn1::celt_ext()); + $$->append($5); + } +; + + +element_set_spec: + constraint_subtype_element { + ASN_LOG_DEBUG("element_set_spec: constraint_subtype_element (%s)",($1 == NULL)?"none":$1->name().c_str()); + $$ = $1; + } + | T_ALL T_EXCEPT constraint_subtype_element { + ASN_LOG_DEBUG("element_set_spec: ALL EXCEPT constraint_subtype_element"); + $$ = new asn1::ca_aex(); + $$->append($3); + } + | element_set_spec T_UNION constraint_subtype_element { + ASN_LOG_DEBUG("element_set_spec: UNION constraint_subtype_element"); + $$ = $1; + if ($$ != NULL) { + ASN_LOG_DEBUG("element_set_spec: UNION $1 is not NULL"); + if ($1->type() == asn1::constraint::CA_UNI) { + $$ = $1 ; + $$->append($3); + } else { + $$ = new asn1::ca_uni(); + $$->append($1); + $$->append($3); + } + } else { + ASN_LOG_ERROR("element_set_spec: UNION $1 is NULL"); + $$ = $3; + } + } + | element_set_spec T_INTERSECTION constraint_subtype_element { + ASN_LOG_DEBUG("element_set_spec: INTERSECTION constraint_subtype_element"); + $$ = $1; + $$->append($3); + } + | constraint_subtype_element T_EXCEPT constraint_subtype_element { + ASN_LOG_DEBUG("element_set_spec: EXCEPT constraint_subtype_element"); + $$ = $1; + $$->append($3); + } +; + +constraint_subtype_element: + constraint_spec_subtype_element T_LPARENTHESES + { + ASN_LOG_DEBUG("constraint_subtype_element start in constraint "); + } + element_set_specs T_RPARENTHESES + { + /* This rule is not correct. It should be an ObjectSetElements */ + $1->append($4); + ASN_LOG_DEBUG("constraint_subtype_element end type_reference 1 %s",$1->name().c_str()); + $$ = $1; + } + | T_LPARENTHESES element_set_specs T_RPARENTHESES + { + /* This rule is not correct. It should be an ObjectSetElements */ + ASN_LOG_DEBUG("TODO: constraint_subtype_element (element_set_specs %s)",$2->name().c_str()); + $$ = $2; + } + | referenced_type + { + /* This rule is not correct. It should be an ObjectSetElements */ + ASN_LOG_ERROR("TODO: constraint_subtype_element reference type"); + $$ = new asn1::celt_type(); + $$->value($1); + } + | T_LOBJBRACET defined_syntax_list T_RBRACET { + ASN_LOG_ERROR("TODO: constraint_subtype_element defined syntax list"); + $$ = new asn1::celt_value(); + $$->value($2); + } + | value + { + ASN_LOG_DEBUG("constraint_subtype_element value"); + $$ = new asn1::celt_value(); + $$->value($1); + } + | T_PATTERN value + { + ASN_LOG_DEBUG("constraint_subtype_element pattern value"); + $$ = new asn1::celt_value(); + $$->value($2); + } + | value_range { + ASN_LOG_DEBUG("constraint_subtype_element value_range"); + $$ = $1; + } + | contained_subtype + { + ASN_LOG_DEBUG("TODO: constraint_subtype_element contained_subtype"); + } + | inner_type_constraint + { + ASN_LOG_DEBUG("constraint_subtype_element inner_type_contraint"); + } + | T_TYPEREFERENCE + { + ASN_LOG_DEBUG("constraint_subtype_element type_reference X.680 4.7.6=%s",$1->name().c_str()); + $$ = new asn1::celt_type(); + asn1::typeref *tref = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + delete $1; + $$->value(tref); + } + | parameterized_objectset + { + ASN_LOG_DEBUG("constraint_subtype_element objectset=%s",$1->name().c_str()); + $$ = new asn1::celt_value(); + $$->value($1); + } + | type + { + ASN_LOG_DEBUG("constraint_subtype_element type %s",$1->name().c_str()); + $$ = new asn1::celt_type(); + $$->value($1); + } +; + +contained_subtype: T_INCLUDES T_TYPEREFERENCE { + $$ = new asn1::constraint("INCLUDE TYPE",asn1::constraint::EL_TYPE); + asn1::typeref *tref = new asn1::typeref($2->name(), + new asn1::simple_reference($2->name()) + ); + delete $2; + $$->value(tref); + } +; + +constraint_spec_subtype_element: + T_SIZE { + ASN_LOG_DEBUG("constraint_spec_subtype_element T_SIZE"); + $$ = new asn1::ctype_size(); + } + | T_FROM { + ASN_LOG_DEBUG("constraint_spec_subtype_element T_FROM"); + $$ = new asn1::ctype_from(); + } +; + +inner_type_constraint: + T_WITH T_COMPONENT set_of_constraints { + ASN_LOG_DEBUG("inner_type_constraint WITH_COMPONENTS "); + $$ = new asn1::ctype_wcomp(); + $$->append($3); + } + | T_WITH T_COMPONENTS T_LBRACET with_components_list T_RBRACET { + ASN_LOG_DEBUG("inner_type_constraint WITH_COMPONENTS 1 "); + $$ = $4; + } +; + + +with_components_list: + with_components_element { + ASN_LOG_DEBUG("with_components_list: 1 "); + $$ = new asn1::ctype_wcomps(); + $$->append($1); + } + | with_components_list T_COMMA with_components_element { + ASN_LOG_DEBUG("with_components_list: 2 "); + $1->append($3); + $$ = $1; + } +; + +with_components_element: + T_THREEPOINT { + ASN_LOG_DEBUG("with_components_element: 1 extensible "); + $$ = new asn1::celt_ext(); + } + | T_IDENTIFIER opt_constraint_def opt_presence_constraint { + ASN_LOG_DEBUG("with_components_element: 2 "); + if ($2 != NULL) + { + ASN_LOG_DEBUG("with_components_element: 2 have opt contraint %s",$1->name().c_str()); + $$ = $2; + } else if ($3 != NULL) { + ASN_LOG_DEBUG("with_components_element: 3 have presence contraint %s",$1->name().c_str()); + $$ = $3; + $$->value($1); + } + } +; + +opt_presence_constraint: /* NULL */ + { $$ = NULL; } + | T_PRESENT { + ASN_LOG_DEBUG("opt_presence_constraint: PRESENT "); + $$ = new asn1::constraint("PRESENCE",asn1::constraint::EL_TYPE); + $$->presence(asn1::constraint::PRESENT); + } + | T_ABSENT { + ASN_LOG_DEBUG("opt_presence_constraint: ABSENT "); + $$ = new asn1::constraint("PRESENCE",asn1::constraint::EL_TYPE); + $$->presence(asn1::constraint::ABSENT); + } + | T_OPTIONAL { + ASN_LOG_DEBUG("opt_presence_constraint: OPTIONAL "); + $$ = new asn1::constraint("PRESENCE",asn1::constraint::EL_TYPE); + $$->presence(asn1::constraint::OPTIONAL_); + } +; + +opt_constraint_def: /* NULL */ + { $$ = NULL; } + | constraint_def + { + ASN_LOG_DEBUG("opt_constraint_def: %s",$1->name().c_str()); + $$ = $1; + asn1::parser::instance()->constraint_complet($1); + } +; + +opt_component_type_lists: /* NULL */ + { $$ = NULL; } + | component_type_lists + { + $$ = $1; + } +; + +component_type_lists: component_type + { + asn1::parser::instance()->got_component_type($1); + } + | component_type_lists T_COMMA component_type + { + asn1::parser::instance()->got_component_type($3); + } +; + + +component_type: T_IDENTIFIER type opt_default /*NamedType*/ + { + ASN_LOG_DEBUG("component_type: (%s) type %s flags=%d" + , $1->name().c_str() + , $2->name().c_str() + , ($3==NULL)?0:$3->m_flags); + + asn1::module *m = get_current_module(); + $2->set_parent(m->current_context()); + $$ = new asn1::field($1->name(),$2); + $$->flags($3); + if ($2->type_id()() == asn1::type::ASN1_SEQUENCE + || $2->type_id()() == asn1::type::ASN1_CHOICE + || $2->type_id()() == asn1::type::ASN1_ENUMERATED + ) + { + $2->name($1->name()+"_t"); + } + delete ($1); + + } + | type opt_default /*type_assign*/ /* Needs to be checked */ + { + asn1::module *m = get_current_module(); + ASN_LOG_DEBUG("component_type: Should go type=%s",$1->name().c_str()); + std::string ano("anonymous"); + ano = ano+$1->cpp_name(); + $$ = new asn1::field(ano.c_str(),$1); + $1->set_parent(m->current_context()); + $$->flags($2); + } + | T_COMPONENTS T_OF type_assign_right_tag_default + { + ASN_LOG_DEBUG("component_type: component of %s",$3->name().c_str()); + $$ = new asn1::components_of($3); + } + | extension_and_exception + { + ASN_LOG_DEBUG("component_type: extension and exception %s",$1->name().c_str()); + $$ = $1; + } +; + +character_string_def: restricted_character_string_def + { + $$ = $1; + } + | unrestricted_character_string_def + { + $$ = $1; + } +; + +restricted_character_string_def: T_BMPString + { $$ = new asn1::bmpstring(); } + | general_string_def + {$$ = $1;} + | T_GraphicString + { $$ = new asn1::graphicstring(); } + | T_IA5String + {$$ = new asn1::ia5string();} + | T_ISO646String + { $$ = new asn1::iso646string(); } + | T_NumericString + { $$ = new asn1::numericstring(); } + | T_PrintableString + { $$ = new asn1::printablestring(); } + | T_TeletexString + { $$ = new asn1::teletexstring(); } + | T_T61String + {$$ = new asn1::node("STRING",asn1::type::ASN1_STRING_T61String);} + | T_UniversalString + { $$ = new asn1::universalstring(); } + | T_UTF8String + { $$ = new asn1::utf8string(); } + | T_VideotextString + { $$ = new asn1::videotexstring(); } + | T_VisibleString + {$$ = new asn1::visiblestring(); } + | T_ObjectDescriptorString + {$$ = new asn1::objectdescriptor_string(); } +; + +restricted_character_string_value: T_LBRACET rcsv_char_syms T_RBRACET { + ASN_LOG_ERROR("retricted_character_string_value 1: TODO"); + } + | rcsv_quadruple { + ASN_LOG_ERROR("retricted_character_string_value 2: TODO"); + } + | rcsv_tuple { + ASN_LOG_ERROR("retricted_character_string_value 3: TODO"); + } +; + +rcsv_char_syms: rcsv_char_sym { + } + | rcsv_char_syms T_COMMA rcsv_char_sym { + } +; + +rcsv_char_sym: rcsv_quadruple { + ASN_LOG_DEBUG("rcvs_char_sym: "); + } + | rcsv_tuple { + ASN_LOG_DEBUG("rcvs_char_sym: "); + } +; + +rcsv_quadruple: T_LBRACET T_NUM T_COMMA T_NUM T_COMMA T_NUM T_COMMA T_NUM T_RBRACET { + ASN_LOG_DEBUG("rcvs_quadruple: "); + } + | T_Quadruple + { + ASN_LOG_DEBUG("rcvs_quadruple 1: "); + } +; + +rcsv_tuple: T_LBRACET T_NUM T_COMMA T_NUM T_RBRACET { + ASN_LOG_DEBUG("rcvs_tuple: "); + } + | T_Tuple + { + ASN_LOG_DEBUG("rcvs_quadruple: "); + } + +unrestricted_character_string_def: T_CHARACTER T_STRING + { $$ = new asn1::node("STRING",asn1::type::ASN1_STRING);} +; + +general_string_def: T_GeneralizedString + { $$ = new asn1::node("STRING",asn1::type::ASN1_STRING);} +; + +octet_string_def: T_OCTET T_STRING { + $$ = new asn1::octet_string(); + } +; + +bit_element_def: T_IDENTIFIER T_LPARENTHESES T_NUM T_RPARENTHESES + { + ASN_LOG_DEBUG("bit_element_def: %s",$1->name().c_str()); + $3->name($1->name()); + delete $1; + $$ = $3; + } + | T_THREEPOINT + { + ASN_LOG_DEBUG("bit_element_def: %s is extension_filed ",$1->name().c_str()); + //$$ = new asn1::node("THREEPOINT",asn1::type::ASN1_EXTENSIBLE); + $$ = new asn1::extension_field(); + } + | T_IDENTIFIER + { + ASN_LOG_ERROR("bit_element_def: value reference %s should return valuetype",$1->name().c_str()); + $$ = $1; + $$->meta_id(asn1::meta::VALUE); + } +; + +bit_element_list: bit_element_def + { + asn1::module *m= get_current_module(); + m->enter_symbol($1,$1->type_id()()); + } + | bit_element_list T_COMMA bit_element_def + { + ASN_LOG_DEBUG("bit_element_list: %s %s",$1->name().c_str(),$3->name().c_str()); + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + m->enter_symbol($3,$3->type_id()()); + } +; + +bit_string_def: + T_BIT T_STRING + { + $$ = new asn1::bit_string(); + } + | T_BIT T_STRING T_LBRACET + { + asn1::module *m= get_current_module(); + m->enter_context(new asn1::bit_string()); + $$ = m; + } constant_list T_RBRACET { + $$ = $4->leave_context(); + } +; + +enumerated_def: T_ENUMERATED T_LBRACET + { + ASN_LOG_DEBUG("enumerated_def: begin "); + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + m->enter_context(new asn1::enumerated()); + $$ = m; + } bit_element_list T_RBRACET + { + ASN_LOG_DEBUG("enumerated_def: end "); + asn1::module *m = (asn1::module *)$3; + asn1::node *res = m->leave_context(); + $$ = res; + } +; + + +object_def: T_OBJECT T_STR_IDENTIFIER + { + ASN_LOG_DEBUG("\nobject_def OBJECT IDENTIFIER type"); + $$ = new asn1::object_identifier(); + } +; + +/** + * + */ +object_class_def: + T_CLASS T_LBRACET + { + ASN_LOG_DEBUG("\nobject_class_def start"); + asn1::module *m= get_current_module(); + m->enter_context(new asn1::classdef() ); + $$ = m; + } + oclass_field_list + { + asn1::module *m = (asn1::module *)$3; + asn1::node *res = m->leave_context(); + ASN_LOG_DEBUG("object_class_def: end %s %s", res->name().c_str() + ,$3->name().c_str()); + $$ = res; + gCurrentClassDef = dynamic_cast(res); + gCurrentClassDef->sort_fields(); + res->meta_id(asn1::meta::OBJECTCLASS); + } T_RBRACET opt_with_syntax + { + $$ = $5; + } +; + +opt_with_syntax: + | T_WITH T_SYNTAX T_LBRACET + { + ASN_LOG_DEBUG("\nwith syntax start skip..."); + enable_with_syntax(); + gCurrentClassDef->start_syntax(); + } syntax_token_list T_RBRACET + { + disable_with_syntax(); + ASN_LOG_DEBUG("with syntax end skip..."); + if ( $5 == NULL) + { + ASN_LOG_ERROR("with syntax end skip $5 IS NULL "); + } + gCurrentClassDef->set_nfa($5); + } +; + +syntax_token_list: /* NULL*/ + { + ASN_LOG_DEBUG("syntax_token_list: NULL"); + $$ = NULL; + } + | token syntax_token_list + { + if ($1 != NULL && $2 != NULL) + { + ASN_LOG_DEBUG("syntax_token_list: 1 token %s append %s",$1->name().c_str(),$2->name().c_str()); + asn1::classdef::fragment *f = gCurrentClassDef->parse_token($1); + $$ = f; + $$ = gCurrentClassDef->parse_append($$,$2); + } else if ($1 != NULL) + { + asn1::classdef::fragment *f = gCurrentClassDef->parse_token($1); + ASN_LOG_DEBUG("syntax_token_list: 1 token %s $2 is NULL",f->name().c_str()); + $$ = f; + } else + { + ASN_LOG_DEBUG("syntax_token_list: token NULL"); + } + } + | opt_token syntax_token_list + { + /* ASN_LOG_DEBUG("syntax_token_list: [ ] "); */ + if ($1 != NULL && $2 != NULL) + { + ASN_LOG_DEBUG("syntax_token_list: [ %s ] %s",$1->name().c_str(),$2->name().c_str()); + asn1::classdef::fragment *f = gCurrentClassDef->parse_append($1,$2); + $$ = f; + } else if ($1 != NULL) + { + /* TODO May be this is a match*/ + ASN_LOG_DEBUG("syntax_token_list: [ %s ] $1 is not NULL ",$1->name().c_str()); + //asn1::classdef::fragment *f = gCurrentClassDef->parse_optional($1); + $$ = $1; + } else if ($2 != NULL) + { + ASN_LOG_DEBUG("syntax_token_list: [ ] $2 is not NULL "); + $$ = $2; + } else + { + ASN_LOG_ERROR("syntax_token_list: [ ] $1==NULL && $2 == NULL "); + } + } +; +/** + { $$ = NULL;} + */ +opt_token : + T_LBRACKET syntax_token_list T_RBRACKET + { + ASN_LOG_DEBUG("opt_token : [ %s ] ",$2->name().c_str()); + asn1::classdef::fragment *f = gCurrentClassDef->parse_optional($2); + $$ = f; + } +; + +token: T_CAPITALREFERENCE { + ASN_LOG_DEBUG("token: capitalReference : %s",$1->name().c_str()); + } + | T_TYPEFIELDREFERENCE { + ASN_LOG_DEBUG("token: value FieldReference : %s",$1->name().c_str()); + $$ = new asn1::typeref($1); + } + | T_VALUEFIELDREFERENCE { + ASN_LOG_DEBUG("token: value FieldReference : %s",$1->name().c_str()); + $$ = new asn1::typeref($1); + } + | T_COMMA { + ASN_LOG_ERROR("token: comma"); + } +; + +opt_unique: /* Empty */ + | T_UNIQUE { + ASN_LOG_DEBUG("opt_unique: UNIQUE TO BE CODED NOT IMPORTANT"); + + } +; + +oclass_field_list: + oclass_field { + asn1::parser::instance()->got_class_field($1); + } + | oclass_field_list T_COMMA oclass_field { + asn1::parser::instance()->got_class_field($3); + } +; + +oclass_field: T_TYPEFIELDREFERENCE opt_default + { + ASN_LOG_DEBUG("oclass_field: typefieldref TF %s",$1->name().c_str()); + $$ = new asn1::classfield_tf($1->name()); + delete ($1); + $$->flags($2); + } + | T_VALUEFIELDREFERENCE type_assign_right opt_unique opt_default + { + asn1::module *m = get_current_module(); + ASN_LOG_DEBUG("oclass_field: valuefieldref FTVF %s",$1->name().c_str()); + $$ = new asn1::classfield_ftvf($1->name(),$2->as_typenode()); + delete ($1); + $2->set_parent(m->current_context()); + $$->flags($4); + } + | T_VALUEFIELDREFERENCE field_name opt_default + { + asn1::module *m = get_current_module(); + ASN_LOG_DEBUG("oclass_field: valuefieldref VTVF %s",$1->name().c_str()); + $$ = new asn1::classfield_vtvf($1->name()); + $$->set_reference($2); + $2->set_parent(m->current_context()); + delete ($1); + $$->flags($3); + } + | T_VALUEFIELDREFERENCE defined_object_class opt_default + { + ASN_LOG_DEBUG("oclass_field: valuefieldref %s",$1->name().c_str()); + $$ = new asn1::classfield_of($1->name()); + delete ($1); + $$->flags($3); + } + | T_TYPEFIELDREFERENCE field_name opt_default + { + asn1::module *m = get_current_module(); + ASN_LOG_DEBUG("oclass_field: typefieldref %s",$1->name().c_str()); + $$ = new asn1::classfield_vtvsf($1->name()); + delete ($1); + $$->set_reference($2); + $2->set_parent(m->current_context()); + $$->flags($3); + } + | T_TYPEFIELDREFERENCE type opt_default + { + ASN_LOG_DEBUG("oclass_field: typefieldref %s",$1->name().c_str()); + asn1::module *m = get_current_module(); + $$ = new asn1::classfield_ftvsf($1->name(),$2->as_typenode()); + delete ($1); + $2->set_parent(m->current_context()); + $$->flags($3); + } + | T_TYPEFIELDREFERENCE defined_object_class opt_default + { + asn1::module *m = get_current_module(); + ASN_LOG_DEBUG("oclass_field: typefieldref %s",$1->name().c_str()); + asn1::typeref *_ref = new asn1::typeref($2,asn1::meta::TYPE); + _ref->set_parent(m->current_context()); + $$ = new asn1::classfield_osf($1->name(),_ref); + $$->flags($3); + } +; + +defined_object_class: + object_class_reference { + ASN_LOG_DEBUG("defined_object_class: object_class_reference"); + $$ = $1; + } +; + +/* + * ObjectSet rules X.681 pg 30 + */ +object_set: + T_LBRACET {ASN_LOG_DEBUG("object_set::Start");enable_object();} element_set_specs {disable_object();} T_RBRACET + { + ASN_LOG_DEBUG("object_set::TODO 1 %s",$3->name().c_str() ); + $$ = $3; + } + | T_LOBJBRACET element_set_specs T_RBRACET + { + ASN_LOG_DEBUG("object_set::TODO 2 %s",$2->name().c_str()); + $$ = $2; + } +; + + +/** + * + */ +type_reference: T_TYPEREFERENCE + { + if (! gLog.is_open() ) { + open_log($1->name()); + } + ASN_LOG_DEBUG("type_reference: %s",$1->name().c_str()); + $$ = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + delete $1; + } + | T_CAPITALREFERENCE + { // object reference + $$ = new asn1::typeref($1->name(), + new asn1::objectclass_reference($1->name()) + ); + delete $1; + } +; + +value_reference: T_IDENTIFIER + { + ASN_LOG_DEBUG("value_reference: Got ValueReference %s",$1->name().c_str()); + $$ = new asn1::typeref($1->name() + , new asn1::simple_reference($1->name() + , asn1::reference::component::Lowercase) + ); + delete $1; + } + ; +/** + * + */ +nstd_marker: + { + } +; + +type_declaration: + nstd_marker type_assign_right + { + ASN_LOG_DEBUG("type_declaration: nstd_marker:%s",$2->name().c_str()); + $$ = $2; + } +; + + + +type_assign_right: defined_type + { + ASN_LOG_DEBUG("type_assign_right: defined_type:%s",$1->name().c_str()); + $$ = $1; + $$->type_id(asn1::type::ASN1_REFERENCE); + $$->meta_id(asn1::meta::TYPEREF); + } + | builtin_type { + ASN_LOG_DEBUG("type_assign_right: builtin :%s",$1->name().c_str()); + $$ = $1; + } +; + +type_assign_right_tag: type_assign_right opt_constraint_def { + ASN_LOG_DEBUG("type_assign_right_tag: %s + opt_constraint_def %s",$1->name().c_str(), + ($2==NULL)?"none":$2->name().c_str()); + $$ = $1; + if ($2 != NULL) + $$->as_typenode()->constraint($2); + } + | tag type_assign_right opt_constraint_def { + ASN_LOG_DEBUG("type_assing_right_tag: tag type=%s opt_constaint_def",$2->name().c_str()); + $$ = $2; + if ($2 != NULL) + $$->as_typenode()->constraint($3); + $$->tag($1); + } +; + +type_assign_right_tag_default: + type_assign_right_tag opt_default { + ASN_LOG_DEBUG("type_assign_right_tag_default: + opt_default "); + $$=$1; + $$->flags($2); + } +; + +sequence_def: T_SEQUENCE T_LBRACET T_RBRACET + { + asn1::module *m= get_current_module(); + m->enter_context(new asn1::sequence() ); + asn1::node *res = m->leave_context(); + $$ = res; + $$->meta_id(asn1::meta::TYPE); + } + | T_SEQUENCE T_LBRACET + { + ASN_LOG_DEBUG("sequence_def start -- with component_type_lists "); + asn1::module *m= get_current_module(); + m->enter_context(new asn1::sequence() ); + $$ = m; + } + opt_component_type_lists T_RBRACET + { + ASN_LOG_DEBUG("sequence_def: end %s" + ,$3->name().c_str()); + asn1::module *m = (asn1::module *)$3; + asn1::node *res = m->leave_context(); + $$ = res; + $$->meta_id(asn1::meta::TYPE); + } + | T_SEQUENCE T_OF opt_identifier opt_tag type_declaration + { + ASN_LOG_DEBUG("seq_of type_declaration "); + asn1::node *ident = NULL; + $$ = new asn1::sequence_of($5); + if ( $3 == NULL) + { + std::string ano("anonymous_seqof"); + ident = new asn1::node(ano.c_str()); + $5->identifier(ident); + } else + { + ident = $3; + $5->identifier($3); + } + asn1::module *m = get_current_module(); + $5->set_parent(m->current_context()); + if (m->current_context() == NULL) + { + ASN_LOG_ERROR("seq_of opt_i opt_taf type_decl NOT GOOD"); + } + ident->set_parent(m->current_context()); + if ($4 != NULL) + $5->tag($4); + $$->meta_id(asn1::meta::TYPE); + } + | T_SEQUENCE opt_constraint_def T_OF opt_identifier type_assign_right + { + $$ = new asn1::sequence_of($5); + if ( $4 == NULL) + { + std::string ano("anonymous_seqofc"); + $5->identifier(new asn1::node(ano.c_str()) ); + } else + $5->identifier($4); + asn1::module *m = get_current_module(); + $5->set_parent(m->current_context()); + $$->as_typenode()->constraint($2); + $$->meta_id(asn1::meta::TYPE); + } +; + +set_def: + T_SET T_LBRACET { + asn1::module *m = get_current_module(); + m->enter_context(new asn1::set()); + $$ = m; + } + /*type_assign_list T_RBRACET */ + opt_component_type_lists T_RBRACET + { + asn1::module *m = get_current_module(); + asn1::node *res = m->leave_context(); + $$=res; + $$->meta_id(asn1::meta::TYPE); + } + | T_SET T_OF type_assign_right { + $$ = new asn1::set_of($3); + $$->meta_id(asn1::meta::TYPE); + asn1::module *m = get_current_module(); + $3->set_parent(m->current_context()); + std::string ano("anonymous_setof"); + asn1::node *ident = new asn1::node(ano.c_str()); + $3->identifier(ident); + ident->set_parent(m->current_context()); + } + | T_SET T_OF T_IDENTIFIER type_assign_right { + $$ = new asn1::set_of($3); + $$->meta_id(asn1::meta::TYPE); + asn1::module *m = get_current_module(); + $4->set_parent(m->current_context()); + $4->identifier($3); + } + | T_SET opt_constraint_def T_OF type_assign_right { + $$ = new asn1::set_of($4); + if ($2) $$->as_typenode()->constraint($2); + asn1::module *m = get_current_module(); + if (m) + $4->set_parent(m->current_context()); + $$->meta_id(asn1::meta::TYPE); + std::string ano("anonymous_setofc"); + $4->identifier(new asn1::node(ano.c_str()) ); + } + | T_SET opt_constraint_def T_OF T_IDENTIFIER type_assign_right { + $$ = new asn1::set_of($5); + asn1::module *m = get_current_module(); + if (m) + $5->set_parent(m->current_context()); + if ($2) $$->as_typenode()->constraint($2); + $$->meta_id(asn1::meta::TYPE); + $5->identifier($4); + }; +; + +choice_def: T_CHOICE T_LBRACET + { + asn1::module *m = get_current_module(); + m->enter_context( new asn1::choice()); + $$ = m; + } + /*type_assign_list */ alternative_type_lists T_RBRACET + { + asn1::module *m = get_current_module(); + asn1::node *res = m->leave_context(); + $$ = res; + $$->meta_id(asn1::meta::TYPE); + } +; + +alternative_type_lists: alternative_type + { + asn1::parser::instance()->got_alternative_choice($1); + } + | alternative_type_lists T_COMMA alternative_type + { + asn1::parser::instance()->got_alternative_choice($3); + } +; + +alternative_type: + T_IDENTIFIER type + { + asn1::module *m = get_current_module(); + ASN_LOG_DEBUG("altenative_type: ident %s type %s",$1->name().c_str(),$2->name().c_str()); + $$ = new asn1::field($1->name(),$2); + $2->set_parent(m->current_context()); + if ($2->type_id()() == asn1::type::ASN1_SET_OF + || $2->type_id()() == asn1::type::ASN1_SEQUENCE_OF + ) + { + asn1::typenode *subtype = $2->as_typenode()->get_eltype(); + if (subtype && subtype->identifier()->get_parent() == NULL) + { + ASN_LOG_ERROR("altenative_type: ident %s type %s",$1->name().c_str(),$2->name().c_str()); + } + $2->name($1->name()+"_t"); + } + delete($1); + } + | extension_and_exception + { + ASN_LOG_DEBUG("altenative_type: extension and exception %s",$1->name().c_str()); + $$ = $1; + } + | type + { + asn1::module *m = get_current_module(); + ASN_LOG_WARNING("altenative_type: type =%s anonymous CHOICE attribute _%s(_t) %d",$1->name().c_str(),$1->name().c_str(),$1->type_id()()); + std::string nm("_"); + nm = nm+$1->name(); + $$ = new asn1::field(nm.c_str(),$1); + $1->set_parent(m->current_context()); + if ($1->type_id()() == asn1::type::ASN1_SEQUENCE + || $1->type_id()() == asn1::type::ASN1_CHOICE + ) + { + $1->name($$->name()+"_t"); + } + } +; + +any_def: T_ANY + { + $$ = new asn1::any(); + } + | T_ANY T_DEFINED T_BY T_IDENTIFIER { + ASN_LOG_DEBUG("any_def: DEPRECATED any defined by"); + $$ = new asn1::any(); + delete $4; + } +; + +type: opt_tag builtin_type opt_constraint_def { + ASN_LOG_DEBUG("type: opt_tag builtin_type %s %s" + ,$2->name().c_str() + ,($3 != NULL)?$3->name().c_str():"No constraint" + ); + $$= $2; + if ($3 != NULL) + { + $$->as_typenode()->constraint($3); + } + $$->tag($1); + } + | opt_tag referenced_type opt_constraint_def { + ASN_LOG_DEBUG( "type: opt_tag referenced_type %s %s" + , $2->name().c_str() + , ($3 != NULL)?$3->name().c_str():"No constraint" + ); + $$ = $2; + if ($3 != NULL) + $$->as_typenode()->constraint($3); + $$->tag($1); + } +; + +builtin_type: boolean_def + {$$ = $1;} + /** + * Enum Int and bit String have someting in common. They can contain a list of literals + */ + | integer_def { $$ = $1; } + | enumerated_def {$$ = $1;} + | bit_string_def {$$ = $1;} + | real_def {$$ = $1;} + | time_def { $$ = $1;} + | octet_string_def {$$ =$1;} + | object_def {$$ = $1;} + | object_class_def {$$ = $1;} + | character_string_def + { + $$ =$1; + } + | sequence_def { $$ = $1;} + | choice_def { $$ = $1;} + | any_def {$$ = $1;} + | set_def {$$ = $1;} + | T_EXTERNAL { + $$ = new asn1::external(); + } + | T_RELATIVE_OID { + ASN_LOG_DEBUG("builtin_type: relative_OID"); + $$ = new asn1::relative_oid(); + } + | T_NULL {$$ =new asn1::null();} +; + +/** + * Don't used type_reference as defined_type already references it + */ +referenced_type: defined_type + { + // defined_type is of type asn1::typeref + if ($1 != NULL) + { + $$ = $1; + // Should not be required + $$->type_id(asn1::type::ASN1_REFERENCE); + $$->meta_id(asn1::meta::TYPEREF); + ASN_LOG_DEBUG("referenced_type: defined_type %s",$1->name().c_str()); + } else { + ASN_LOG_ERROR("referenced_type: defined_type NULL %lx",(long)$1); + } + } + | identifier T_LT type + { + ASN_LOG_DEBUG("referenced_type got selection type %s",$1->name().c_str()); + $$ = new asn1::selection($1->name(),$3);; + delete($1); + } + ; + +field_name: T_TYPEFIELDREFERENCE + { + ASN_LOG_WARNING("field_name : %s",$1->name().c_str()); + $$ = $1; + } + | field_name T_POINT T_TYPEFIELDREFERENCE + { + ASN_LOG_WARNING("field_name 2 %s . %s ",$1->name().c_str(),$3->name().c_str()); + $$->add_components($3->get_components()); + delete($3); + } + | field_name T_POINT T_VALUEFIELDREFERENCE + { + ASN_LOG_WARNING("field_name 3 %s %s",$1->name().c_str(),$3->name().c_str()); + $$->add_components($3->get_components()); + delete($3); + } +; + +/* TypeAssignment X.680 TypeAssignment -> typereference "::=" Type */ +type_assignment: T_TYPEREFERENCE T_ASSIGN type_assign_right_tag + { + // Set parent of type. + asn1::module *m= get_current_module(); + $3->set_parent(m); + + if ($3->type_id()() == asn1::type::ASN1_CHOICE) { + ASN_LOG_DEBUG("type is CHOICE set name to %s_t",$1->cpp_name().c_str()); + $3->name($1->cpp_name()+"_t"); + } +#ifdef DEBUG + if ($3 == NULL) {printf("ERROR type is NULL"); } + ASN_LOG_DEBUG("\ntype_assignment : T_TYPEREFERENCE %s en tant que: %s %d\n", + $1->name().c_str() + ,$3->name().c_str() + ,$3->type_id()()); +#endif + if ( ($3->type_id() >= asn1::type::ASN1_SEQUENCE ) && + ($3->type_id() <= asn1::type::ASN1_TYPE_MAX)) + { + $$ = new asn1::type_assignment($1->name()); + } else if ($3->type_id() == asn1::type::ASN1_VALUESET) + { + $$ = new asn1::valueset_assignment($1->name()); + } else if ($3->type_id() == asn1::type::ASN1_REFERENCE) + { + /* THIS IS WRONG A::= B Is a TYPE definition + * B Is Ref and A Is new Type */ + $$ = new asn1::typeref_assignment($1->name()); + //$$ = new asn1::type_assignment($1->name()); + } + $$->type_node($3); + $3->identifier($$); + delete($1); + } + | type_reference parameter_list T_ASSIGN type_assign_right_tag + { + ASN_LOG_DEBUG("type_assignment : type_reference %s {} en tant que:",$1->name().c_str()); + ASN_LOG_DEBUG(""); + // Set parent of type. + asn1::module *m= get_current_module(); + $4->set_parent(m); + + if ( ($4->type_id() >= asn1::type::ASN1_SEQUENCE ) && + ($4->type_id() <= asn1::type::ASN1_TYPE_MAX)) + { + $$ = new asn1::type_assignment($1->name()); + } else if ($4->type_id() == asn1::type::ASN1_VALUESET) + { + std::cerr<<"p "<<$1->name()<name()); + //$$->set_reference($1->get_reference()); + } else if ($4->type_id() == asn1::type::ASN1_REFERENCE) + { + $$ = new asn1::typeref_assignment($1->name()); + } + $4->identifier($$); + $$->type_node($4); + $$->parameters($2->as_parameters()); + delete($1); + + } + | T_CAPITALREFERENCE T_ASSIGN type_assign_right_tag + { + ASN_LOG_DEBUG("\ntype_assignement: T_CAPITALREFERENCE Object Class or type %s meta=%d" + ,$1->name().c_str() + ,$3->meta_id()() + ); + ASN_LOG_DEBUG(""); + // Set parent of type. + asn1::module *m= get_current_module(); + $3->set_parent(m); + // $1 is either object class assignment or type assignment + switch($3->meta_id()()) + { +#define ASSIGNMENT(tp,cls,parent) \ + case asn1::meta::tp: \ + $$ = new asn1::cls##_assignment($1->name()); \ + break; + default: + ; +#include "adt/asn1_meta.inc" + } + $3->identifier($$); + //$$ = $1; + $$->type_node($3); + } +; + +parameter_list: T_LBRACET { + asn1::module *m = get_current_module(); + m->enter_context(new asn1::parameters()); + $$ = m; + ASN_LOG_DEBUG("parameter_list enter (params ...)"); + } parameter_args T_RBRACET + { + asn1::module *m = (asn1::module *)$2; + asn1::node *res = m->leave_context(); + ASN_LOG_DEBUG("parameter_list leave (params %s)",res->name().c_str()); + $$ = res; + } +; + +parameter_args: parameter_arg + { + ASN_LOG_DEBUG("parameter_args: %s",$1->cpp_name().c_str()); + asn1::parser::instance()->got_parameter($1); + } + | parameter_args T_COMMA parameter_arg + { + ASN_LOG_DEBUG("parameter_args: %s",$3->cpp_name().c_str()); + asn1::parser::instance()->got_parameter($3); + } +; + +parameter_arg: + type_reference { + ASN_LOG_DEBUG("parameter_arg 0: %s(tp=%d)",$1->name().c_str(),$1->type_id()()); + $$ = new asn1::parameter(NULL,$1->as_typeref()); + } + | type_reference T_COLON type_reference { + ASN_LOG_DEBUG("parameter_arg 1: %s(tp=%d) : %s(tp=%d)",$1->name().c_str(),$1->type_id()(), + $3->name().c_str(),$3->type_id()()); + $$ = new asn1::parameter($1,$3->as_typeref()); + } + | type_reference T_COLON value_reference { + ASN_LOG_DEBUG("parameter_arg 2: %s(tp=%d) : %s(tp=%d)",$1->name().c_str(),$1->type_id()(), + $3->name().c_str(),$3->type_id()()); + $$ = new asn1::parameter($1,$3->as_typeref()); + } + | type T_COLON type_reference { + ASN_LOG_DEBUG("parameter_arg 3: %s(tp=%d) : %s(tp=%d)",$1->name().c_str(),$1->type_id()(), + $3->name().c_str(),$3->type_id()()); + $$ = new asn1::parameter($1,$3->as_typeref()); + } + | type T_COLON value_reference { + ASN_LOG_DEBUG("parameter_arg 4: %s(tp=%d):%s",$1->name().c_str(),$1->type_id()(),$3->name().c_str()); + $$ = new asn1::parameter($1,$3->as_typeref()); + } +; +/** +| type_reference T_COLON T_IDENTIFIER { + ASN_LOG_DEBUG("parameter_arg 2: %s:%s",$1->name().c_str(),$3->name().c_str()); + $$ = $1; + $$->identifier($3); + } +*/ + +act_parameter_args:act_parameter_arg + { + ASN_LOG_DEBUG("act_parameter_args %s",$1->name().c_str()); + asn1::parser::instance()->got_act_parameter($1); + $$ = $1; + } + | act_parameter_args T_COMMA act_parameter_arg + { + ASN_LOG_DEBUG("act_parameter_args next %s",$3->name().c_str()); + asn1::parser::instance()->got_act_parameter($3); + } +; + +act_parameter_arg: type + { + if ($1 != NULL) + { + ASN_LOG_DEBUG("act_parameter_arg:type declaration:%s",$1->name().c_str()); + } else { + ASN_LOG_DEBUG("act_parameter_arg:type declaration: without identifier"); + } + $$ = $1; + } + | value_set + { + ASN_LOG_DEBUG("act_parameter_arg : value_set"); + $$= new asn1::valueset($1); + } + | object_set + { + ASN_LOG_DEBUG("act_parameter_arg : object_set %s",$1->name().c_str()); + $$= new asn1::objectset($1); + } + | value + { + ASN_LOG_DEBUG("act_parameter_arg: value "); + $$ = $1; + } + | type_reference { + ASN_LOG_DEBUG("act_parameter_arg:reference %s",$1->name().c_str()); + } + /* + | defined_object_class + | object + + */ +; + +/* */ +value_assignment: + T_IDENTIFIER T_OBJECT T_STR_IDENTIFIER T_ASSIGN T_LBRACET + obj_constant_list T_RBRACET + { + ASN_LOG_DEBUG( "value_assignment : ident %s OID " + , $1->name().c_str() + ); + asn1::module *m = get_current_module(); + asn1::node *i = m->leave_context(); + i->meta_id(asn1::meta::VALUE); + i->set_parent(m->current_context()); + $$ = new asn1::value_assignment($1->name()); + i->identifier($$); + $$->type_node(i); + delete ($1); + } + | identifier T_TYPEREFERENCE T_ASSIGN T_LBRACET + obj_constant_list T_RBRACET + { + ASN_LOG_WARNING("value_assignment : ident %s type=%s OID 1 TO BE FINALIZED",$1->name().c_str(),$2->name().c_str()); + asn1::module *m = get_current_module(); + asn1::node *i = m->leave_context(); + i->set_parent(m->current_context()); + $$ = new asn1::value_assignment($1->name()); + i->identifier($$); + $$->type_node(i); + // Missing typeref somewhere + } + | identifier T_TYPEREFERENCE T_ASSIGN T_LBRACET restricted_character_string_value T_RBRACET { + ASN_LOG_WARNING("value_assignment : ident %s type=%s STR value=%s TO BE FINALIZED",$1->name().c_str(),$2->name().c_str(),$5->name().c_str()); + asn1::node *i = new asn1::node("CONST STRING",asn1::meta::VALUE); + i->type_id(asn1::type::ASN1_OBJECT_IDENTIFIER); + $$ = new asn1::value_assignment($1->name()); + $5->identifier($$); + i->identifier($$); + $$->type_node(i); + $2->type_id(asn1::type::ASN1_REFERENCE); + delete($1); + } + | identifier restricted_character_string_def T_ASSIGN restricted_character_string_value + { + ASN_LOG_WARNING("value_assignment : ident type=%s string" + , $1->name().c_str()); + asn1::node *i = new asn1::node("CONST STRING",asn1::meta::VALUE); + i->type_id(asn1::type::ASN1_STRING); + $$ = new asn1::value_assignment($1->name()); + $4->identifier($$); + i->identifier($$); + $$->type_node(i); + $$->value(new asn1::value(asn1::value::VT_STRING)); + delete($1); + } + | identifier T_INTEGER T_ASSIGN value { + ASN_LOG_WARNING("value_assignment : ident %s type INTEGER value=%s TO BE FINALIZED",$1->name().c_str(),$4->name().c_str()); + asn1::node *i = $4; + $$ = new asn1::value_assignment($1->name()); + i->identifier($$); + $$->type_node(i); //TODO remove + $$->meta_id(asn1::meta::VALUE); + $$->value($4->value()); + delete($1); + } + | identifier T_TYPEREFERENCE T_ASSIGN value { + ASN_LOG_WARNING("value_assignment : ident %s type=%s value=%s TO BE FINALIZED",$1->name().c_str(),$2->name().c_str(),$4->name().c_str()); + asn1::node *tr = new asn1::typeref( new asn1::simple_reference($2->name())); + delete($2); + $$ = new asn1::value_assignment($1->name()); + tr->identifier($$); + $$->type_node(tr); + if ($4->meta_id()() == asn1::meta::VALUE) + { + $$->value($4->value()); + } + delete($1); + } + | identifier T_TYPEREFERENCE T_ASSIGN T_LBRACET value T_RBRACET { + /* Needed for Attribute-ASN1Module.asn1 line 205 */ + ASN_LOG_WARNING("value_assignment : N ident %s type=%s value=%s TO BE FINALIZED",$1->name().c_str(),$2->name().c_str(),$5->name().c_str()); + asn1::node *tr = new asn1::typeref( new asn1::simple_reference($2->name())); + delete($2); + $$ = new asn1::value_assignment($1->name()); + tr->identifier($$); + tr->meta_id(asn1::meta::TYPEREF); + tr->type_id(asn1::type::ASN1_REFERENCE); + $$->type_node(tr); + if ($5->meta_id()() == asn1::meta::VALUE) + { + $$->value($5->value()); + } + delete($1); + } +/* +*/ +; + +/** + * value_range rules + */ +value_range: + value constraint_range_spec value { + ASN_LOG_DEBUG("value_range %s .. %s",$1->name().c_str(),$3->name().c_str()); + asn1::constraint_range *cr = dynamic_cast($2); + cr->set_min_max($1,$3); + $$ = $2; + } +; + +constraint_range_spec : T_TWOPOINT { + ASN_LOG_DEBUG("constraint_range_spec .. "); + $$= new asn1::celt_range(); + } + | T_TWOPOINT T_LT { + ASN_LOG_DEBUG("constraint_range_spec ..< "); + $$= new asn1::celt_rlrange(); + } + | T_LT T_TWOPOINT { + ASN_LOG_DEBUG("constraint_range_spec < .. "); + $$= new asn1::celt_llrange(); + } + | T_LT T_TWOPOINT T_LT { + ASN_LOG_DEBUG("constraint_range_spec <..< "); + $$= new asn1::celt_ulrange(); + } +; + +/** + * + */ +value: builtin_value { + ASN_LOG_DEBUG( "value: builtin_value : %s id=%d" + , ($1 != NULL)?$1->cpp_name().c_str():"null" + , ($1 != NULL)?$1->type_id()(): -1 + ); + $$ = $1; + $$->meta_id(asn1::meta::VALUE); + } + /* ReferencedValue */ + | defined_value + { + ASN_LOG_DEBUG("value: defined_value .."); + $$->meta_id(asn1::meta::VALUE); + asn1::value *v = new asn1::value($1->name()); + $$->value(v); + $$ = $1; + } + | value_from_object { + ASN_LOG_DEBUG("value: value_from_object .."); + $$ = $1; + $$->meta_id(asn1::meta::VALUE); + } +; +/* Refuse empty builtin value + ASN_LOG_WARNING("builtin_value: NONE return NULL"); + $$=NULL; + } + */ +builtin_value: + /* Boolean value*/ + T_ASN1_TRUE { + ASN_LOG_DEBUG("builtin_value: Boolean Value TRUE "); + $$ = new asn1::valuetype( new asn1::value(asn1::value::VT_TRUE)); + } + | T_ASN1_FALSE { + ASN_LOG_DEBUG("builtin_value: Boolean Value FALSE "); + $$ = new asn1::valuetype(new asn1::value(asn1::value::VT_FALSE)); + } + | T_NULL { + ASN_LOG_DEBUG("builtin_value: NullValue NULL "); + $$ = new asn1::valuetype(new asn1::value(asn1::value::VT_NULL)); + } + | pos_neg_num { + ASN_LOG_DEBUG("builtin_value: IntegerValue pos_neg_num %s",$1->name().c_str()); + $$ = $1; + } + | T_IDENTIFIER T_COLON value { + ASN_LOG_DEBUG("builtin_value: ChoiceValue identifier:value %s:%s (%d)" + , $1->name().c_str() + , $3->name().c_str() + , $3->type_id()() + ); + asn1::valuetype *vt = new asn1::valuetype(std::string($1->name()),NULL); + vt->type_id(asn1::type::ASN1_CHOICE); + vt->identifier($1); + asn1::value *v = new asn1::value(asn1::value::VT_COLON); + v->m_node = $3; + vt->value(v); + $$ = vt; + } + | set_value { + /* SET_value can actually be an oid or {component_list } + * VALUESET is element_set_specs !!! + */ + ASN_LOG_ERROR("builtin_value: set_value %s id=%d wrong VT_VALUESET for set" + ,$1->name().c_str() + ,$1->type_id()() + ); + if ($1->is_object_identifier()) + { + $$ = $1; + } else + { + asn1::valuetype *vt = new asn1::valuetype(std::string($1->name()),NULL); + asn1::value *v = new asn1::value(asn1::value::VT_SETVALUE); + v->m_node = $1; + vt->value(v); + $$ = vt; + } + } + | T_bstring { + ASN_LOG_ERROR("builtin_value got binary string"); + $$ = new asn1::valuetype(new asn1::value(asn1::value::VT_BITVECTOR)); + } + | T_hstring { + ASN_LOG_ERROR("builtin_value got hstring string"); + $$ = new asn1::valuetype(new asn1::value(asn1::value::VT_BITVECTOR)); + } + | T_MIN { + $$ = new asn1::valuetype(new asn1::value(asn1::value::VT_MIN)); + } + | T_MAX { + $$ = new asn1::valuetype(new asn1::value(asn1::value::VT_MAX)); + } + | T_Quadruple { + ASN_LOG_WARNING("builtin_value got quadruple TO BE CODED"); + $$ = new asn1::valuetype(std::string("Quadrupple"),NULL); + } + | T_Tuple { + ASN_LOG_WARNING("builtin_value got tuple TO BE CODED"); + $$ = new asn1::valuetype(std::string("TUPLE"),NULL); + } +; + +defined_value: + identifier { + asn1::value *v = new asn1::value(asn1::value::VT_REFERENCED); + v->m_string = $1->name(); + $$ = new asn1::valuetype($1->name(),v); + ASN_LOG_DEBUG("defined_value: %s",$1->name().c_str()); + delete $1; + } + | parameterized_value { + ASN_LOG_DEBUG("defined_value: parameterized_value %s",$1->name().c_str()); + $$ = $1; + } +; + +parameterized_value: + identifier T_LBRACET { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + m->enter_context(new asn1::act_parameters()); + $$ = m; + ASN_LOG_DEBUG("parameterized_value enter %s (params ...)",$1->name().c_str()); + } act_parameter_args T_RBRACET + { + asn1::module *m = (asn1::module *)$3; + asn1::node *res = m->leave_context(); + ASN_LOG_DEBUG("parameterized_value leave (params %s)",res->name().c_str()); + $$ = $1; + $$->parameters(res->as_parameters()); + } +; + +parameterized_objectset: + T_TYPEREFERENCE T_LOBJBRACET { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + m->enter_context(new asn1::act_parameters()); + $$ = m; + ASN_LOG_DEBUG("parameterized_objectset enter %s (params ...)",$1->name().c_str()); + } act_parameter_args T_RBRACET + { + asn1::module *m = (asn1::module *)$3; + asn1::node *res = m->leave_context(); + ASN_LOG_DEBUG("parameterized_objectset leave (params %s { %s })",$1->name().c_str(),res->name().c_str()); + $$ = $1; + $$->parameters(res->as_constructed()); + } +; + + + + +value_from_object: + T_CAPITALREFERENCE T_POINT field_name { + ASN_LOG_WARNING("value_from_object(0) Capital INCOMPLETE %s.%s", + $1->name().c_str() + , $3->name().c_str()); + //asn1::reference *ref = new asn1::objectclass_reference($1->name()); + //$$ = new asn1::typeref(ref); + $$ = $1; + } + | T_TYPEREFERENCE T_POINT field_name { + ASN_LOG_DEBUG("value_from_object(1) Reference %s.%s", + $1->name().c_str() + , $3->name().c_str()); + asn1::typeref *tref = new asn1::typeref($1->name(), + new asn1::simple_reference($1->name()) + ); + tref->get_reference()->add_components($3->get_components()); + $$ = tref; + delete $1; + } + | identifier T_POINT primitive_field_reference { + ASN_LOG_WARNING("value_from_object(2) Identifier INCOMPLETE %s.%s" + , $1->name().c_str() + , $3->m_identifier.c_str()); + $$ = $1; + delete $3; + } +; +/* value set */ +constant_set_def: + type_reference defined_type T_ASSIGN value_set { + ASN_LOG_ERROR("constant_set_def:%s",$1->name().c_str()); + $$ = new asn1::valueset_assignment($1->name()); + $$->type_node($2); + $2->identifier($$); + $2->as_typenode()->constraint($4); + delete($1); + } + | type_reference builtin_type T_ASSIGN value_set { + ASN_LOG_ERROR("constant_set_def:%s of type: %s",$1->name().c_str(),$2->cpp_name().c_str()); + $$ = new asn1::valueset_assignment($1->name()); + //$$->set_reference($1->get_reference()); + $$->type_node($2); + $2->identifier($$); + //$$->constraint($4); + $2->as_typenode()->constraint($4); + delete($1); + } +; + + +defined_type: /* * More complex types */ + complex_type_reference T_LBRACET { + ASN_LOG_DEBUG("defined_type: 1 %s start (params:...)",$1->name().c_str()); + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + m->enter_context(new asn1::act_parameters()); + $$ = m; + } + act_parameter_args T_RBRACET { + asn1::module *m = (asn1::module *)$3; + asn1::node *res = m->leave_context(); + ASN_LOG_DEBUG( "defined_type: 1 end (params: %s) %p" + , res->name().c_str() + , res->as_constructed() + ); + $$ = new asn1::typeref($1); + $$->act_parameters(res->as_constructed()); + } + | complex_type_reference { + ASN_LOG_DEBUG("defined_type: complex_type_reference <%s>",$1->name().c_str()); + $$ = new asn1::typeref($1); + } +; + +complex_type_reference: + T_TYPEREFERENCE { + /* simple_defined_type reference */ + $$ = new asn1::simple_reference($1->name()); + delete($1); + } + | T_TYPEREFERENCE T_POINT type_reference { + /* External reference : Module reference . type_reference */ + $$ = new asn1::reference(); + asn1::reference::component c; + c.m_identifier =$1->name(); + c.type = asn1::reference::component::Uppercase; + $$->add_component(c); + delete($1); + c.m_identifier = $3->name(); + $$->add_component(c); + delete $3; + + } + | object_class_reference T_POINT type_reference { + $$ = $1; + ASN_LOG_DEBUG("complex_type_reference: %s . %s",$1->name().c_str(),$3->name().c_str()); + asn1::reference::component c; + c.m_identifier = $3->name(); + c.type = asn1::reference::component::Uppercase; + $1->add_component(c); + delete $3; + } + | T_TYPEREFERENCE T_POINT T_IDENTIFIER { + /* External reference : Module reference . value_reference */ + $$ = new asn1::reference(); + asn1::reference::component c; + c.m_identifier =$1->name(); + c.type = asn1::reference::component::Uppercase; + $$->add_component(c); + delete($1); + c.m_identifier = $3->name(); + c.type = asn1::reference::component::Lowercase; + $$->add_component(c); + delete $3; + } + | object_class_reference + { + ASN_LOG_DEBUG("complex_type_reference: %s ",$1->name().c_str()); + $$ = $1; + } + | object_class_reference T_POINT {current_ref = $1;} complex_type_reference_amp_list { + $$ = $1; + ASN_LOG_DEBUG("complex_type_reference: %s .& %s",$1->name().c_str(),$4->m_identifier.c_str()); + delete $4; + } +; + +complex_type_reference_amp_list: + complex_type_reference_element { + ASN_LOG_DEBUG("complex_type_reference_apm_list 1: %s ",$1->m_identifier.c_str()); + current_ref->add_component(*$1); + } + | complex_type_reference_amp_list T_POINT complex_type_reference_element { + ASN_LOG_DEBUG("complex_type_reference_apm_list 2: should add %s ",$3->m_identifier.c_str()); + // Its' a ref_comp + current_ref->add_component(*$3); + } +; + +complex_type_reference_element: primitive_field_reference + ; +primitive_field_reference: + T_TYPEFIELDREFERENCE + { + ASN_LOG_DEBUG("primitive_field_reference: TYPEFIELDREFRENE %s",$1->name().c_str()); + asn1::reference::component *c = new asn1::reference::component; + c->m_identifier =$1->name(); + c->type = asn1::reference::component::AmpUppercase; + delete $1; + $$ = c; + } + | T_VALUEFIELDREFERENCE + { + ASN_LOG_DEBUG("primitive_field_reference: VALUEREFERENCE %s",$1->name().c_str()); + asn1::reference::component *c = new asn1::reference::component; + c->m_identifier =$1->name(); + c->type = asn1::reference::component::AmpLowercase; + delete $1; + $$ = c; + } +; + +object_class_reference: T_CAPITALREFERENCE /* X.681 7.1 */ + { + ASN_LOG_DEBUG("object_class_reference: %s",$1->name().c_str()); + + $$ = new asn1::objectclass_reference($1->name()); + delete($1); + } +; + +// Be carefull value_set and set_value are two different things . +// I don't think that enter context is required. As element_set_specs is a constraint. +value_set: T_LBRACET + { + ASN_LOG_DEBUG("value_set start"); + } + element_set_specs T_RBRACET + { + /** + */ + ASN_LOG_DEBUG("value_set END"); + $$ = $3; + } +; + +/** + * In term of BRACET cant be a set or an OID + * -> set_value which_list = component_value_list + * -> OID obj_constant_list + * -> constraint ? why + */ +set_value: T_LBRACET { + ASN_LOG_DEBUG("set_value start"); + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + //m->enter_context("set_value",asn1::type::INVALID); + m->enter_context(new asn1::constructed(std::string("set_value 1"))); + $$ = m; + } + which_list T_RBRACET + { + + asn1::module *m = (asn1::module *)$2; + asn1::node *res = m->leave_context(); + $$ = res; + if ($3 != NULL && $3->type_id()() == asn1::type::ASN1_OBJECT_IDENTIFIER) + { + $$ = $3; + $$->type_id(asn1::type::ASN1_OBJECT_IDENTIFIER); + $$->meta_id(asn1::meta::VALUE); + $$->name("OBJECT_IDENTIFIER"); + delete res; + ASN_LOG_DEBUG("set_value end GOT OID %d",$3->type_id()()); + } else if ($3 != NULL && $3->type_id()() == asn1::type::ASN1_REFERENCE) + { + $$->meta_id(asn1::meta::VALUE); + res->as_typenode()->constraint(*($3->as_typeref()->constraint_begin())); + delete $3; + ASN_LOG_DEBUG("set_value end GOT VALUE probably ref"); + assert( 0 && "set_value list contains reference ! is this possible ?"); + } else { + $$->meta_id(asn1::meta::VALUE); + ASN_LOG_DEBUG("set_value end GOT VALUE NULL"); + } + } +; + +which_list: obj_constant_list { + // node + ASN_LOG_DEBUG("which_list obj_constant_list"); + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + asn1::node *ids = m->leave_context(); + $$ = ids; + } + | opt_component_value_list { + // node + ASN_LOG_DEBUG("which_list component_value"); + $$ = NULL; + } +; +opt_component_value_list: /* Empty */ + | component_value_list { + ASN_LOG_DEBUG("opt_component_value_list"); + } +; +component_value_list:component_value { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + m->enter_symbol($1,$1->type_id()()); + $$ = $1; + } + | component_value_list T_COMMA component_value { + asn1::parser *p = asn1::parser::instance(); + asn1::module *m= (asn1::module *) p->module(); + m->enter_symbol($3,$3->type_id()()); + $$ = $1; + } +; + +component_value: T_IDENTIFIER value { + ASN_LOG_ERROR("component_value Should be Named Not anonymous got value =%s ",$1->name().c_str()); + } +; + +/** + * + */ +extension_and_exception: + T_THREEPOINT { + ASN_LOG_DEBUG("extension_and_exception (...)"); + $$ = new asn1::extension_field(); + } + | T_THREEPOINT exception_spec { + ASN_LOG_WARNING("extension_and_exception (...) and missing exception_spec"); + $$ = new asn1::extension_field(); + $$->meta_id(asn1::meta::TYPE); + // $$->value($2); + } +; + + +exception_spec: /* Empty */ + { $$ = NULL; } + | T_EXCLAMATION defined_value { + ASN_LOG_DEBUG("exception_spec: %s",$2->name().c_str()); + $$ = $2; + } + | T_EXCLAMATION type_reference T_COLON value + { + ASN_LOG_DEBUG("exception_spec: ! %s : %s",$2->name().c_str(),$4->name().c_str()); + $$ = $2; + } + | T_EXCLAMATION pos_neg_identifier { + ASN_LOG_DEBUG("exception_spec: ! %s",$2->name().c_str()); + $$ = $2; +} +; + +object_set_assignment: + type_reference parameter_list defined_object_class T_ASSIGN { + ASN_LOG_DEBUG("object_set_assignment parameterized start %s",$1->name().c_str()); + } + object_set + { + ASN_LOG_DEBUG("object_set_assignment parameterized end %s",$1->name().c_str()); + $$ = new asn1::objectset_assignment($1->name()); + $$->parameters($2->as_parameters()); + asn1::objectset *objs = new asn1::objectset($6); + asn1::typeref *typeref = new asn1::typeref($3); + objs->set_classref(typeref); + objs->name($1->name()); + objs->identifier($$); + $$->type_node(objs); + delete($1); + } + | + type_reference defined_object_class T_ASSIGN { + ASN_LOG_DEBUG("object_set_assignment start %s",$1->name().c_str()); + } + object_set + { + ASN_LOG_DEBUG("object_set_assignment end %s",$1->name().c_str()); + asn1::typeref *typeref = new asn1::typeref($2); + $$ = new asn1::objectset_assignment($1->name()); + asn1::objectset *objs = new asn1::objectset($5); + objs->identifier($$); + objs->name($1->name()); + objs->set_classref(typeref); + $$->type_node(objs); + delete($1); + } +; + + +/* + * + */ +object_assignment: + identifier defined_type T_ASSIGN + { + ASN_LOG_DEBUG("\nobject_assignment start 1 object:%s class:%s",$1->name().c_str(),$2->name().c_str()); + + $$ = get_current_module(); + $$->enter_context(new asn1::object()); + } + object + { + asn1::node *res = $4->leave_context(); + $$ = new asn1::object_assignment($1->name()); + res->identifier($$); + $2->type_node(res); + $$->type_node($2); + delete($1); + ASN_LOG_DEBUG("object_assignment end"); + } + | identifier T_LBRACET { /*3*/ + ASN_LOG_DEBUG("object_assignment: start %s {params}",$1->cpp_name().c_str()); + asn1::module *m= get_current_module(); + m->enter_context(new asn1::parameters()); + $$ = m; + } parameter_args T_RBRACET + { /*6*/ + ASN_LOG_DEBUG("object_assignment: %s",$1->cpp_name().c_str()); + asn1::module *m = (asn1::module *)$3; + asn1::node *res = m->leave_context(); + } object_class_reference T_ASSIGN { /*9*/ + ASN_LOG_DEBUG("\nobject_assignment with params start object:%s class:%s" + ,$1->name().c_str() + ,$7->name().c_str()); + asn1::module *m= get_current_module(); + $$= m; + m->enter_context(new asn1::object()); + } object { + ASN_LOG_DEBUG("object_assignment: end %s {params}",$1->cpp_name().c_str()); + $$ = new asn1::object_assignment($1->name()); + asn1::node *res = $9->leave_context(); + res->identifier($$); + res->meta_id(asn1::meta::OBJECT); + asn1::typeref *ref = new asn1::typeref($7,asn1::meta::TYPE); + ref->type_node(res); + $$->type_node(ref); + $$->parameters($4->as_parameters()); + delete($1); + } +; + +object: + defined_object { + $$ = $1; + } + | object_defn { + $$ = $1; + } +; + + + +defined_object: + T_IDENTIFIER { + } +; + +object_defn: + default_syntax { + ASN_LOG_DEBUG("object_defn: default_syntax"); + $$ = $1; + } + | defined_syntax { + ASN_LOG_DEBUG("object_defn: defined_syntax"); + $$ = $1; + } +; + +default_syntax: { + $$ = NULL; + } +; + +defined_syntax: + T_LBRACET defined_syntax_list T_RBRACET { + ASN_LOG_DEBUG("defined_syntax: defined_syntax_list"); + $$ =$2; + } +; + +defined_syntax_list: + defined_syntax_token { + ASN_LOG_DEBUG("defined_syntax_list got item :%s",$1->name().c_str()); + asn1::module *m = get_current_module ( ); + m->enter_symbol($1,$1->type_id()()); + } + | defined_syntax_list defined_syntax_token { + ASN_LOG_DEBUG("defined_syntax_list got item 1"); + asn1::module *m = get_current_module ( ); + m->enter_symbol($2,$2->type_id()()); + } +; + +defined_syntax_token: + object_set { + ASN_LOG_DEBUG("defined_syntax_token object_set:"); + $$= new asn1::objectset($1); + } + | value { + ASN_LOG_DEBUG("defined_syntax_token value:%s type id=%d",$1->name().c_str(),$1->type_id()()); + $$ = $1; + } + | type + { + $$ = $1; + if ($$->type_id()() == asn1::type::ASN1_SET_OF + && $$->identifier() == NULL) + { + $$->identifier(new asn1::node("anonmyous")); + } + ASN_LOG_DEBUG("defined_syntax_token type %s",$1->name().c_str()); + } + | T_OPTIONAL { + ASN_LOG_DEBUG("defined_syntax_token OPTIONAL"); + $$ = new asn1::node("OPTIONAL",asn1::type::INVALID); + } + | T_BY { + ASN_LOG_DEBUG("defined_syntax_token BY"); + $$ = new asn1::node("BY",asn1::type::INVALID); + } + | T_SYNTAX { + $$ = new asn1::node("SYNTAX",asn1::type::INVALID); + } + | type_reference { + ASN_LOG_DEBUG("defined_syntax_token type_reference %s",$1->name().c_str()); + $$ = $1; + } + | T_TYPEREFERENCE T_POINT type_reference { + /* External reference : Module reference . type_reference */ + asn1::reference *r = $3->as_typeref()->get_reference(); + asn1::module *mod = get_current_module(); + asn1::import *imp = mod->get_import($1->name()); + // If import does not exists, add it to module + if ( ! imp) + { + ASN_LOG_DEBUG( "defined_syntax_token type_reference No import:%s" + , $1->name().c_str()); + imp = new asn1::import($1->name()); + imp->identifier($1); + mod->imports()->append(imp); + } + // Simple reference + asn1::typeref *tref = new asn1::typeref($3->name(), r); + // If reference not in import add one in import too + if (! imp->get_item($3->name() ) ) + { + imp->append(tref->clone()); + } + $$ = tref; + delete $3; + } +; + +/* + * + */ + +type_constant: + type_assignment { + ASN_LOG_DEBUG("type_constant: Got type_assignment "); + $$ = $1; + } + | value_assignment { + ASN_LOG_DEBUG("type_constant: Got value assignement "); + $$ = $1; + } + | object_assignment { + ASN_LOG_DEBUG("type_constant: Got object assignement "); + $$ =$1; + } + | object_set_assignment { + ASN_LOG_DEBUG("type_constant: object_set_assignment"); + $$ =$1; + } + | constant_set_def { + ASN_LOG_DEBUG("type_constant: constant_set_def"); + $$ = $1; + } + | T_ENCODING_CONTROL T_CAPITALREFERENCE { + ASN_LOG_DEBUG("type_constant: encoding control start enable ignored for now"); + enable_encoding_control(); + } + { + ASN_LOG_DEBUG("type_constant: encoding control ignored for now"); + $$ = NULL; + } + + +; + +type_constant_list: type_constant + { + asn1::parser *p = asn1::parser::instance(); + $$ = p->module(NULL); + ASN_LOG_DEBUG("Got type_constant_list: %s type_constant %s" + ,$$->name().c_str() + ,$1->name().c_str()); + $$->add_type( $1->as_assignment()); + } + | type_constant_list type_constant + { + if ($2 != NULL) { + ASN_LOG_DEBUG("type_constant_list %s append:%s" + , $1->name().c_str() + , $2->name().c_str() + ); + $$->add_type( $2->as_assignment()); + } else + ASN_LOG_DEBUG("type_constant_list append NOTHING "); + $$ =$1; + } +; + +definitions_id: + type_reference T_LBRACET { + // Special case + if (! gLog.is_open()) + open_log($1->name()); + ASN_LOG_DEBUG("definitions_id :%s",$1->name().c_str()); + asn1::parser *p = asn1::parser::instance(); + asn1::module *m = NULL; + if (p->begin() == p->end()) + { + m= p->module($1->name().c_str()); + } else + { + m= p->module(); + } + $$ = m; + } obj_constant_list T_RBRACET + { + ASN_LOG_DEBUG("Go definitions ID %s",static_cast($1)->name().c_str()); + asn1::node *ids = $3->leave_context(); + $$ = $1; + $$->type_node(ids); + } + | T_IDENTIFIER T_LBRACET T_RBRACET + { $$ = $1;} + | T_TYPEREFERENCE + { + // Special case + if (! gLog.is_open()) + open_log($1->name()); + ASN_LOG_DEBUG("definitions_id :%s",$1->name().c_str()); + $$ = $1; + } + | T_CAPITALREFERENCE + { + // Special case + if (! gLog.is_open()) + open_log($1->name()); + $$ = $1; + } +; + +opt_explicit_implicit: { + $$.m_mode = asn1::node::tag_type::TM_DEFAULT; + } + | explicit_implicit { + $$ = $1; + } +; + +explicit_implicit: T_EXPLICIT { + $$.m_mode = asn1::node::tag_type::TM_EXPLICIT; + } + | T_IMPLICIT { + $$.m_mode = asn1::node::tag_type::TM_IMPLICIT; + } + | T_AUTOMATIC { + ASN_LOG_DEBUG("explicit_implicit: TM_AUTOMATIC"); + $$.m_mode = asn1::node::tag_type::TM_AUTOMATIC; + } +; + +%% +/* + vim:et:sw=2:ts=2: +*/ + diff --git a/libparser/asn1_parser.cpp b/libparser/asn1_parser.cpp new file mode 100644 index 0000000..95cf42a --- /dev/null +++ b/libparser/asn1_parser.cpp @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__APPLE__) || defined(HAVE_UNISTD_H) || defined(__GNUC__) +// for access function I need unistd +#include +#endif +#if defined (_WIN32) +#include +#define access _access_s +#define F_OK 0 +#endif + +#include "asn1_node.h" +#include "asn1_module.h" +#include "asn1_constraint.h" +#include "asn1_reference.h" +#include "asn1_value.h" + +#include "asn1_parser_listener.h" +#include "asn1_parser.h" + +extern int _asn1_parse(); +extern FILE *_asn1_in; +extern "C" int _asn1_wrap(void); +extern "C" int _asn1_lineno; +asn1::parser * +asn1::parser::m_instance = NULL; + +/** + * wrap function to handle multiple file parsing other than through stdin + */ +int _asn1_wrap() +{ + asn1::parser *asn1p = asn1::parser::instance(); + std::string fullname; + // If they are files to parse, return 0, but first, + // close the current in, and open the new one + if ((asn1p->file_mode() ) && _asn1_in != NULL) + { + fclose(_asn1_in); + _asn1_in = NULL; + } else if (!asn1p->file_mode()) + { + return 1; + } + // Only process files if specified + if (asn1p->files().size() > 0) + { + if (asn1p->includes().size() > 0) { + std::list::iterator it; + for ( it = asn1p->includes().begin() + ; it != asn1p->includes().end(); ++it) + { + fullname = (*it) + asn1p->files().back(); + if (!access(fullname.c_str(),F_OK)) + { + break; + } + } + } + if (fullname.size() > 0) + { + _asn1_in = fopen(fullname.c_str(),"r"); + if (_asn1_in != NULL) + { + std::cout<<"New File : "<files().pop_back(); + return 0; + } else { + return 1; + } + } else + return 1; + } + return 1; +} + + +namespace asn1 +{ + +// +struct got_constraint +{ + got_constraint(asn1::constraint *c) : m_c(c) {}; + void operator ()(parser_listener *l) + { + l->onConstraint(m_c); + } + asn1::constraint *m_c; +}; + +// +struct create_module +{ + create_module(asn1::module *m) : m_c(m) {}; + void operator ()(parser_listener *l) + { + l->onModule(m_c); + } + asn1::module *m_c; +}; + + + +/** + * + */ +asn1::module * +parser::module(const char *n ) +{ + iterator it; + if (m_modules.size() == 0) + { + //std::cerr<<"parser::module Create module new 0 :"<name()<(m->current_context()); + asn1::set *set = dynamic_cast(m->current_context()); + + if (seq && c->get_parent() == NULL) + { + c->set_parent(seq); + } + if (seq) + { + seq->add_component(c); + } else if (set) + { + c->set_parent(set); + set->append(c); + } else + { + } +} +/** + * Called for each alternative choice + */ +void parser::got_alternative_choice(asn1::node *c) +{ + asn1::module *m = m_modules.back(); + asn1::choice *s = dynamic_cast(m->current_context()); + + if (c->get_parent() == NULL) + { + c->set_parent(s); + } + s->add_alternative(c); +} +// +void +parser::got_class_field(asn1::classfield *c) +{ + asn1::module *m = m_modules.back(); + asn1::classdef *s = dynamic_cast(m->current_context()); + + if (c->get_parent() == NULL) + { + c->set_parent(s); + } + s->add_field(c); +} + + +void +parser::got_parameter(asn1::parameter *p) +{ + asn1::module *m = m_modules.back(); + asn1::parameters *pl = dynamic_cast(m->current_context()); + if (p->get_parent() == NULL) + { + p->set_parent(pl); + } + pl->add_parameter(p); +} + +void +parser::got_act_parameter(asn1::node *c) +{ + asn1::module *m = m_modules.back(); + asn1::act_parameters *pl = dynamic_cast(m->current_context()); + if (c->get_parent() == NULL) + { + c->set_parent(pl); + } + pl->add_parameter(c); +} + +int +parser::parse() +{ + if ( file_mode() ) + { + _asn1_in = NULL; + if ( !_asn1_wrap() ) + { + _asn1_parse(); + return 0; + } else + { + return 1; + } + } else if (! file_mode()) + { + _asn1_parse(); + return 0; + } + { + return 1; + } +} + +} diff --git a/libparser/asn1_parser.h b/libparser/asn1_parser.h new file mode 100644 index 0000000..0e418fc --- /dev/null +++ b/libparser/asn1_parser.h @@ -0,0 +1,107 @@ +#ifndef ASN1_PARSER_H__ +#define ASN1_PARSER_H__ + +#include "asn1_node.h" +#include "asn1_module.h" +#include "asn1_parser_listener.h" + +namespace asn1 { + +class asn1_parser_listener; + +class parser +{ + public: + typedef std::vector modules_type; + typedef std::vector::iterator iterator; + + typedef std::list listener_list; + + typedef std::list string_list; + + static parser *instance() + { + if (m_instance == NULL) + { + m_instance = new parser(); + } + return m_instance; + } + + inline iterator begin() {return m_modules.begin();} + inline iterator end() {return m_modules.end();} + + asn1::module * module(const char *n = NULL); + + modules_type &modules() { return m_modules;}; + + /** + * + */ + void register_listener(parser_listener *l); + + /** + * Entry point to notify listeners that a constraint definition + * has occured. + */ + void constraint_complet(asn1::constraint *c); + + /** + * Called for each component in a sequence + */ + void got_component_type(asn1::node *c); + /** + * Called for each alternative choice + */ + void got_alternative_choice(asn1::node *c); + /** + * Called for each alternative choice + */ + void got_class_field(asn1::classfield *c); + + void got_parameter(asn1::parameter *p); + + void got_act_parameter(asn1::node *n); + + int parse(); + + inline bool debug_console() const + { return m_debug_console ; } + + inline void debug_console(bool b) + { m_debug_console = true; } + inline string_list &includes() { return m_includes; } + inline string_list &files() { return m_files; } + inline bool file_mode() { return m_file_mode;} + inline void set_file_mode(bool fm) + { m_file_mode = fm;} + private: + parser() + : m_file_mode(false) , m_root(NULL) + {}; + parser(const parser &p) + {}; + parser &operator =(const parser &p) { return *this;}; + + + private: + modules_type m_modules; + static parser *m_instance; + + protected: + bool m_debug_console; + node *m_root; + listener_list m_listeners; + string_list m_includes; + string_list m_files; + bool m_file_mode; +}; + +//parser::m_instance = NULL; +} + +/* + * vim:et:sw=2:ts=2 + */ + +#endif diff --git a/libparser/asn1_parser_listener.h b/libparser/asn1_parser_listener.h new file mode 100644 index 0000000..27587d7 --- /dev/null +++ b/libparser/asn1_parser_listener.h @@ -0,0 +1,27 @@ +#ifndef ASN1_PARSER_LISTENER_H +#define ASN1_PARSER_LISTENER_H + +namespace asn1 +{ + +/** + * @brief This class is an interface that is used by the parser. It allows an application + * to listen to some events from the parser. + * Example: a contraints has been parsed + * a typedefinition is completed + * a component of a set or sequence has been parser. + */ +class parser_listener +{ + public: + parser_listener () {}; + + // Constraint + virtual void onConstraint(asn1::constraint *c) {}; + + virtual void onModule(asn1::module *m) {}; + protected: +}; + +} +#endif /*ASN1_PARSER_LISTENER_H*/ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..2746367 --- /dev/null +++ b/main.cpp @@ -0,0 +1,375 @@ +#include +#include +#include +#include +#include + +// For open / close +#include +#include +#include + +#include "asn1_generator.h" +#include "asn1_gen_cpp.h" +#include "asn1_gen_hpp.h" +#include "js/asn1_gen_js.h" +#include "uml/asn1_gen_uml.h" +#include "lds/asn1_gen_lds.h" +#include "asn1_gen_codec_cpp.h" +#include "asn1_gen_auto_tag.h" +#include "asn1_gen_optimizer.h" +#include "libparser/asn1_parser.h" +#include "asn1_gen_constraints.h" + +#include "optionparser.h" + +/** + * Global Variables for the parser / lexer + */ + + +enum optionIndex { + UNKNOWN, HELP + ,UML,ERULE + ,FICHIER,OUTPUT,INCLUDE + ,PLANG,COMMENT,CODEC,OPTSPLIT,OPTDBG,OPT_END}; +/*----------------------------------------------------------------------------*/ +const option::Descriptor usage[] = { + {UNKNOWN, 0, "", "", option::Arg::None,"Welcome to asn1p compiler (c) aeb" + " 2016-2018 " BUILD_TYPE " " BUILD_VERSION "\n" + "Usage asn1p [options]\n\texample:" + " asn1p -e ber -f toto.asn1 -I[path]\n"}, + {HELP, 0, "h", "help",option::Arg::None,"--help,-h \tPrint help and quit."}, + {UML, 0, "u", "uml", option::Arg::Optional,"--uml,-u \tGenerate UML model of asn1 model."}, + {ERULE, 0, "e", "ecoding_rule", option::Arg::Required,"--encoding_rule ,-e \t Encoding rules to use" + " accepted ER: ber,per,oer,jer,xer "}, + {FICHIER, 0, "f", "file", option::Arg::Required,"--file,-f \tAsn1 input file to parse"}, + {OUTPUT, 0, "o", "ouput", option::Arg::Required,"--output,-o \toutput file without extension to be generated"}, + {INCLUDE, 0, "I", "include", option::Arg::Required,"--include,-I\tInclude path to look for other asn1 files."}, + {PLANG, 0, "l", "language", option::Arg::Required,"--language,-l\t" + "Programming language cpp, uml, javascript, lds, sql [default: cpp]"}, + {COMMENT, 0, "n", "comment", option::Arg::Required,"--comment,-n\t" + "(true or ON)/(false or OFF) generate comment in source def true"}, + {CODEC, 0, "c", "codec", option::Arg::Required,"--codec,-c\tCodecs" + " functions ON or OFF [default: OFF]" + }, + {OPTSPLIT, 0, "s", "split", option::Arg::None,"--split,-s\t" + " put codec code in separated cpp files. Needed for huge definitions" + }, + {OPTDBG, 0, "d", "debug", option::Arg::Required,"--debug,-d\tconsole=1 " + " msg=1 debug messages in code parser=<1-8> parser debug traces"}, + {0,0,0,0,0,0} +}; + +struct language_config +{ + language_config() + : m_cpp(true) + , m_uml(true) + , m_javascript(false) + , m_lds(false) + , m_java(false) + , m_csharp(true) + , m_sql(true) + , m_c(false) + {}; +#define WITH_PLANG(nm) \ + bool with_##nm() { return m_##nm; } ; \ + void with_##nm(bool b) { m_##nm = b ; } ; + WITH_PLANG(cpp) + WITH_PLANG(javascript) + WITH_PLANG(lds) + WITH_PLANG(java) + WITH_PLANG(csharp) + WITH_PLANG(sql) + WITH_PLANG(c) + WITH_PLANG(uml) +#undef WITH_PLANG + // generator configuration flags + bool m_cpp; + bool m_uml; + bool m_javascript; + bool m_lds; + bool m_java; + bool m_csharp; + bool m_sql; + bool m_c; +}; + + +/** + * Main entry point + */ +int main(int argc,char **argv) +{ + std::map module_map; + std::string umlname; + asn1::parser::iterator it; + asn1::parser *p = asn1::parser::instance(); + asn1::generator_config g_config; + language_config l_config; + gen_constraints constraints; + // Option stuff must go here + option::Stats stats(usage,argc-1,&argv[1]); + //const int max(stats.options_max); + option::Option options[OPT_END*3],buffer[OPT_END*4]; + option::Parser parser(usage,argc-1,&argv[1],options,buffer); + + p->register_listener(&constraints); + if (parser.error()) { + return 1; + } + if (options[HELP] ) + { + option::printUsage(std::cout,usage); + return 1; + } + if (options[INCLUDE]) + { + for ( option::Option *opts = options[INCLUDE] + ; opts; opts = opts->next()) + { + if (opts->arg) + p->includes().push_back(std::string(opts->arg)); + } + } + if (options[OPTSPLIT]) + { + g_config.with_split_cpp(true); + } + /** + * Codecs included in structures + */ + if (options[CODEC]) + { + for (option::Option *opts = options[CODEC] ;opts; opts = opts->next()) + { + while (* opts->arg == ' ') opts->arg++; + if (opts->arg && + (! strcmp(opts->arg,"false") || !strcmp(opts->arg,"OFF"))) + { + g_config.with_codec(false); + } else if (opts->arg && + (! strcmp(opts->arg,"true") || !strcmp(opts->arg,"ON"))) + { + g_config.with_codec(true); + } else + { + std::cerr<<"Wrong argument for CODEC"<next()) + { + while (* opts->arg == ' ') opts->arg++; + if (opts->arg && ! strcmp(opts->arg,"uml")) + { l_config.with_uml(true); continue; } + + if (opts->arg && ! strcmp(opts->arg,"cpp")) + { l_config.with_cpp(true); continue; } + + if (opts->arg && ! strcmp(opts->arg,"javascript")) + { l_config.with_javascript(true); continue; } + + if (opts->arg && ! strcmp(opts->arg,"lds")) + { l_config.with_lds(true); continue; } + + + std::cerr<<"Unsuported language. "<arg<next()) + { + /* remove spaces */ + while (* opts->arg == ' ') opts->arg++; + if (opts->arg && ! strcmp(opts->arg,"ber")) + { g_config.with_ber(true); continue; } + + if (opts->arg && ! strcmp(opts->arg,"jer")) + { g_config.with_jer(true); continue; } + + if (opts->arg && ! strcmp(opts->arg,"oer")) + { g_config.with_oer(true); continue; } + + if (opts->arg && ! strcmp(opts->arg,"per")) + { g_config.with_per(true); continue; } + + if (opts->arg && ! strcmp(opts->arg,"xer")) + { g_config.with_xer(true); continue; } + + + std::cerr<<"Unsuported encoding rule. <"<arg<<">"<next()) + { + if (opts->arg && ! strcmp(opts->arg,"msg=1")) + { g_config.with_source_debug(true); continue; } + + + if (opts->arg && ! strcmp(opts->arg,"console=1")) + { std::cout<<"TODO"<arg && ! strncmp(opts->arg,"parser=",7)) + { std::cout<<"TODO parser debug level"; continue; } + + std::cerr<<"Unsuported option "<arg<next()) + { + if (opts->arg && ( + (! strcmp(opts->arg,"false") ||!strcmp(opts->arg,"OFF")) )) + { + g_config.with_source_comment(false); + } + } + } + + if (options[FICHIER] ) + { + for ( option::Option *opts = options[FICHIER] + ; opts; opts = opts->next()) + { + if (opts->arg) + p->files().push_back(std::string(opts->arg)); + } + p->set_file_mode(true); + std::cout<<"Main: start with wrap feature"<parse()) + { + std::cout<<"Main: start with wrap failed "<parse(); + } + + if (options[UML] && options[UML].arg != NULL) { + umlname = std::string(options[UML].arg); + std::cout<<"Will generate : "<begin(); it != p->end(); it++ ) + { + std::fstream os; + std::fstream osauto; + std::string fname = (*it)->cpp_name() + std::string(".h"); + std::string fcname = (*it)->name() + std::string(".cpp"); + std::string jsname = (*it)->name() + std::string(".js"); + std::string autoname = (*it)->name() + std::string(".auto"); + asn1::gen_auto_tag gen_auto((*it),p->modules()); + + // If OUTPUT option is set, only generate the specified module + if (options[OUTPUT] && (options[OUTPUT].arg != NULL )) + { + bool found = false; + for ( option::Option *opts = options[OUTPUT] + ; opts; opts = opts->next()) + { + if (! (*it)->name().compare(opts->arg)) + { + found = true; + break; + } + } + if (!found ) + continue; + } + // Launch optimization + asn1::gen_optimizer ogen((*it),p->modules()); + ogen.set_config(g_config); + ogen.gen(std::cout,".optimize" ); + // Do automatic tagging + osauto.open(autoname.c_str(),std::fstream::out); + gen_auto.gen(osauto,".auto"); + osauto.close(); + // + if (l_config.with_javascript()) + { + os.open(jsname.c_str(),std::fstream::out); + std::cout<<"\n*\n*Process javascript generation for Definition :"; + std::cout<<(*it)->name()<<"\n*"<modules()); + // Generate automatic tag. + // This class goes through the module for automatic tagging + gen.gen(os,".js"); + os.close(); + + } else if (options[UML] ) + { + std::fstream umlos; + std::cout<<"\n*\n*Process uml generation for Definition :"; + std::cout<<(*it)->name()<<"\n*"<modules()); + gen_uml.gen(umlos,".uml"); + umlos.close(); + } else + { + os.open(fname.c_str(),std::fstream::out); + std::cout<<"\n*\n*Process cpp generation for Definition :"; + std::cout<<(*it)->name()<<"\n*"<modules()); + gen.set_config(g_config); + gen.gen(os,".hpp"); + os.close(); + + // Reset generated flag + asn1::node::iterator nit = (*it)->begin(); + for (; nit != (*it)->end() ; nit++) + { + (*nit)->set_generated(false); + } + // Generate codec cod + os.open(fcname.c_str(),std::fstream::out); + generate_codec_cpp genc((*it),p->modules(),constraints); + genc.set_config(g_config); + genc.gen(os,".cpp"); + os.close(); + } + if (l_config.with_lds()) + { + std::string ldsname = (*it)->name() + std::string(".lds"); + os.open(ldsname.c_str(),std::fstream::out); + generate_lds genlds((*it),p->modules()); + std::cout<<"\n*\n*Process lds generation for Definition :"; + std::cout<<(*it)->name()<<"\n*"< +#include +#include +#include +#include +#include "rtasn1/asn1_config.h" + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "rtasn1/asn1_codec_jer.h" + +#include "MEDIA_GATEWAY_CONTROL.h" +#include "MEDIA_GATEWAY_CONTROL_codec.hpp" + +using namespace MEDIA_GATEWAY_CONTROL; + +void test_message() { + asn1::streams::ber ctx; + asn1::streams::jer ctx_jer; + IP4Address ip4; + Message m,mjer; + m.version = 2; + ip4.address = std::string("0345"); + ip4.portNumber.get() = 1045; + Transaction trans; + CommandRequest cr; + ActionRequest ar; + TerminationID tid; + WildcardField wf; wf = std::string("*"); + ar.contextId = 0xFFFFFFFF; + tid.id = std::string("100"); + cr.command.get_addReq().terminationID.push_back(tid); + tid.id = std::string("101"); + tid.wildcard.push_back(wf); + tid.wildcard.push_back(wf); + cr.command.get_addReq().terminationID.push_back(tid); + ar.commandRequests.push_back(cr); + //m.mId.ip4Address = ip4; + //m.mId.kind_ = MId::typeof_ip4Address; + //m.mId.set_tag(asn1::tag(asn1::types::CONTEXT_SPECIFIC,MId::typeof_ip4Address)); + //m.mId.set_tag(asn1::tag(asn1::types::CONTEXT_SPECIFIC,0)); + m.mId.set_ip4Address ( ip4 ); + trans.get_transactionRequest().transactionId = 5; + trans.get_transactionRequest().actions.push_back(ar); + m.messageBody.get_transactions().push_back(trans); + //m.messageBody.get_transactions().push_back(trans); +#if 0 + // This should be possible as well; + mIP4Address &ip4 = m.mId.get_ip4Addres(); + ip4.address = std::string("0345"); + ip4.portNumber.get() = 1045; +#endif + std::cout<<"Message:\n"<"< + *
  • It is a header-only library. Just \#include "optionparser.h" and you're set. + *
  • It is freestanding. There are no dependencies whatsoever, not even the + * C or C++ standard library. + *
  • It has a usage message formatter that supports column alignment and + * line wrapping. This aids localization because it adapts to + * translated strings that are shorter or longer (even if they contain + * Asian wide characters). + *
  • Unlike getopt() and derivatives it doesn't force you to loop through + * options sequentially. Instead you can access options directly like this: + *
      + *
    • Test for presence of a switch in the argument vector: + * @code if ( options[QUIET] ) ... @endcode + *
    • Evaluate --enable-foo/--disable-foo pair where the last one used wins: + * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode + *
    • Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): + * @code int verbosity = options[VERBOSE].count(); @endcode + *
    • Iterate over all --file=<fname> arguments: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + *
    • If you really want to, you can still process all arguments in order: + * @code + * for (int i = 0; i < p.optionsCount(); ++i) { + * Option& opt = buffer[i]; + * switch(opt.index()) { + * case HELP: ... + * case VERBOSE: ... + * case FILE: fname = opt.arg; ... + * case UNKNOWN: ... + * @endcode + *
    + * @n + * Despite these features the code size remains tiny. + * It is smaller than uClibc's GNU getopt() and just a + * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n + * (This does not include the usage formatter, of course. But you don't have to use that.) + * + * @par Download: + * Tarball with examples and test programs: + * optionparser-1.3.tar.gz @n + * Just the header (this is all you really need): + * optionparser.h + * + * @par Changelog: + * Version 1.3: Compatible with Microsoft Visual C++. @n + * Version 1.2: Added @ref option::Option::namelen "Option::namelen" and removed the extraction + * of short option characters into a special buffer. @n + * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached + * rather than separate. This is what GNU getopt() does and how POSIX recommends + * utilities should interpret their arguments.@n + * Version 1.1: Optional mode with argument reordering as done by GNU getopt(), so that + * options and non-options can be mixed. See + * @ref option::Parser::parse() "Parser::parse()". + * + * @par Feedback: + * Send questions, bug reports, feature requests etc. to: optionparser-feedback (a) lists.sourceforge.net + * @htmlonly @endhtmlonly + * + * + * @par Example program: + * (Note: @c option::* identifiers are links that take you to their documentation.) + * @code + * #include + * #include "optionparser.h" + * + * enum optionIndex { UNKNOWN, HELP, PLUS }; + * const option::Descriptor usage[] = + * { + * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n" + * "Options:" }, + * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." }, + * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." }, + * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n" + * " example --unknown -- --this_is_no_option\n" + * " example -unk --plus -ppp file1 file2\n" }, + * {0,0,0,0,0,0} + * }; + * + * int main(int argc, char* argv[]) + * { + * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present + * option::Stats stats(usage, argc, argv); + * option::Option options[stats.options_max], buffer[stats.buffer_max]; + * option::Parser parse(usage, argc, argv, options, buffer); + * + * if (parse.error()) + * return 1; + * + * if (options[HELP] || argc == 0) { + * option::printUsage(std::cout, usage); + * return 0; + * } + * + * std::cout << "--plus count: " << + * options[PLUS].count() << "\n"; + * + * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next()) + * std::cout << "Unknown option: " << opt->name << "\n"; + * + * for (int i = 0; i < parse.nonOptionsCount(); ++i) + * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; + * } + * @endcode + * + * @par Option syntax: + * @li The Lean Mean C++ Option Parser follows POSIX getopt() conventions and supports + * GNU-style getopt_long() long options as well as Perl-style single-minus + * long options (getopt_long_only()). + * @li short options have the format @c -X where @c X is any character that fits in a char. + * @li short options can be grouped, i.e. -X -Y is equivalent to @c -XY. + * @li a short option may take an argument either separate (-X foo) or + * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by + * registering @c X as a long option (in addition to being a short option) and + * enabling single-minus long options. + * @li an argument-taking short option may be grouped if it is the last in the group, e.g. + * @c -ABCXfoo or -ABCX foo (@c foo is the argument to the @c -X option). + * @li a lone minus character @c '-' is not treated as an option. It is customarily used where + * a file name is expected to refer to stdin or stdout. + * @li long options have the format @c --option-name. + * @li the option-name of a long option can be anything and include any characters. + * Even @c = characters will work, but don't do that. + * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous. + * You can set a minimum length for abbreviations. + * @li [optional] long options may begin with a single minus. The double minus form is always + * accepted, too. + * @li a long option may take an argument either separate ( --option arg ) or + * attached ( --option=arg ). In the attached form the equals sign is mandatory. + * @li an empty string can be passed as an attached long option argument: --option-name= . + * Note the distinction between an empty string as argument and no argument at all. + * @li an empty string is permitted as separate argument to both long and short options. + * @li Arguments to both short and long options may start with a @c '-' character. E.g. + * -X-X , -X -X or --long-X=-X . If @c -X + * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases. + * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must + * be attached. + * @li the special option @c -- (i.e. without a name) terminates the list of + * options. Everything that follows is a non-option argument, even if it starts with + * a @c '-' character. The @c -- itself will not appear in the parse results. + * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to + * a preceding argument-taking option, will terminate the option list and is the + * first non-option argument. All following command line arguments are treated as + * non-option arguments, even if they start with @c '-' . @n + * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is + * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n + * You can enable the GNU behaviour by passing @c true as first argument to + * e.g. @ref option::Parser::parse() "Parser::parse()". + * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but + * aren't, are NOT treated as non-option arguments. They are treated as unknown options and + * are collected into a list of unknown options for error reporting. @n + * This means that in order to pass a first non-option + * argument beginning with the minus character it is required to use the + * @c -- special option, e.g. + * @code + * program -x -- --strange-filename + * @endcode + * In this example, @c --strange-filename is a non-option argument. If the @c -- + * were omitted, it would be treated as an unknown option. @n + * See @ref option::Descriptor::longopt for information on how to collect unknown options. + * + */ + +#ifndef OPTIONPARSER_H_ +#define OPTIONPARSER_H_ + +/** @brief The namespace of The Lean Mean C++ Option Parser. */ +namespace option +{ + +#ifdef _MSC_VER +#include +#pragma intrinsic(_BitScanReverse) +struct MSC_Builtin_CLZ +{ + static int builtin_clz(unsigned x) + { + unsigned long index; + _BitScanReverse(&index, x); + return 32-index; // int is always 32bit on Windows, even for target x64 + } +}; +#define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x) +#endif + +class Option; + +/** + * @brief Possible results when checking if an argument is valid for a certain option. + * + * In the case that no argument is provided for an option that takes an + * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent. + */ +enum ArgStatus +{ + //! The option does not take an argument. + ARG_NONE, + //! The argument is acceptable for the option. + ARG_OK, + //! The argument is not acceptable but that's non-fatal because the option's argument is optional. + ARG_IGNORE, + //! The argument is not acceptable and that's fatal. + ARG_ILLEGAL +}; + +/** + * @brief Signature of functions that check if an argument is valid for a certain type of option. + * + * Every Option has such a function assigned in its Descriptor. + * @code + * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... }; + * @endcode + * + * A CheckArg function has the following signature: + * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode + * + * It is used to check if a potential argument would be acceptable for the option. + * It will even be called if there is no argument. In that case @c option.arg will be @c NULL. + * + * If @c msg is @c true and the function determines that an argument is not acceptable and + * that this is a fatal error, it should output a message to the user before + * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you + * will get duplicate messages). + * + * See @ref ArgStatus for the meaning of the return values. + * + * While you can provide your own functions, + * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice: + * + * @li @c Arg::None @copybrief Arg::None + * @li @c Arg::Optional @copybrief Arg::Optional + * + */ +typedef ArgStatus (*CheckArg)(const Option& option, bool msg); + +/** + * @brief Describes an option, its help text (usage) and how it should be parsed. + * + * The main input when constructing an option::Parser is an array of Descriptors. + + * @par Example: + * @code + * enum OptionIndex {CREATE, ...}; + * enum OptionType {DISABLE, ENABLE, OTHER}; + * + * const option::Descriptor usage[] = { + * { CREATE, // index + * OTHER, // type + * "c", // shortopt + * "create", // longopt + * Arg::None, // check_arg + * "--create Tells the program to create something." // help + * } + * , ... + * }; + * @endcode + */ +struct Descriptor +{ + /** + * @brief Index of this option's linked list in the array filled in by the parser. + * + * Command line options whose Descriptors have the same index will end up in the same + * linked list in the order in which they appear on the command line. If you have + * multiple long option aliases that refer to the same option, give their descriptors + * the same @c index. + * + * If you have options that mean exactly opposite things + * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same + * @c index, but distinguish them through different values for @ref type. + * That way they end up in the same list and you can just take the last element of the + * list and use its type. This way you get the usual behaviour where switches later + * on the command line override earlier ones without having to code it manually. + * + * @par Tip: + * Use an enum rather than plain ints for better readability, as shown in the example + * at Descriptor. + */ + const unsigned index; + + /** + * @brief Used to distinguish between options with the same @ref index. + * See @ref index for details. + * + * It is recommended that you use an enum rather than a plain int to make your + * code more readable. + */ + const int type; + + /** + * @brief Each char in this string will be accepted as a short option character. + * + * The string must not include the minus character @c '-' or you'll get undefined + * behaviour. + * + * If this Descriptor should not have short option characters, use the empty + * string "". NULL is not permitted here! + * + * See @ref longopt for more information. + */ + const char* const shortopt; + + /** + * @brief The long option name (without the leading @c -- ). + * + * If this Descriptor should not have a long option name, use the empty + * string "". NULL is not permitted here! + * + * While @ref shortopt allows multiple short option characters, each + * Descriptor can have only a single long option name. If you have multiple + * long option names referring to the same option use separate Descriptors + * that have the same @ref index and @ref type. You may repeat + * short option characters in such an alias Descriptor but there's no need to. + * + * @par Dummy Descriptors: + * You can use dummy Descriptors with an + * empty string for both @ref shortopt and @ref longopt to add text to + * the usage that is not related to a specific option. See @ref help. + * The first dummy Descriptor will be used for unknown options (see below). + * + * @par Unknown Option Descriptor: + * The first dummy Descriptor in the list of Descriptors, + * whose @ref shortopt and @ref longopt are both the empty string, will be used + * as the Descriptor for unknown options. An unknown option is a string in + * the argument vector that is not a lone minus @c '-' but starts with a minus + * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n + * Note that the dummy descriptor's @ref check_arg function @e will be called and + * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL + * the parsing will be aborted with Parser::error()==true. @n + * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's + * @ref index @e will be used to pick the linked list into which + * to put the unknown option. @n + * If there is no dummy descriptor, unknown options will be dropped silently. + * + */ + const char* const longopt; + + /** + * @brief For each option that matches @ref shortopt or @ref longopt this function + * will be called to check a potential argument to the option. + * + * This function will be called even if there is no potential argument. In that case + * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty + * string. + * + * See @ref CheckArg for more information. + */ + const CheckArg check_arg; + + /** + * @brief The usage text associated with the options in this Descriptor. + * + * You can use option::printUsage() to format your usage message based on + * the @c help texts. You can use dummy Descriptors where + * @ref shortopt and @ref longopt are both the empty string to add text to + * the usage that is not related to a specific option. + * + * See option::printUsage() for special formatting characters you can use in + * @c help to get a column layout. + * + * @attention + * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8" + * prefix to make sure string literals are properly encoded. + */ + const char* help; +}; + +/** + * @brief A parsed option from the command line together with its argument if it has one. + * + * The Parser chains all parsed options with the same Descriptor::index together + * to form a linked list. This allows you to easily implement all of the common ways + * of handling repeated options and enable/disable pairs. + * + * @li Test for presence of a switch in the argument vector: + * @code if ( options[QUIET] ) ... @endcode + * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins: + * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode + * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): + * @code int verbosity = options[VERBOSE].count(); @endcode + * @li Iterate over all --file=<fname> arguments: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + */ +class Option +{ + Option* next_; + Option* prev_; +public: + /** + * @brief Pointer to this Option's Descriptor. + * + * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used + * for unknown options. + * + * @attention + * @c desc==NULL signals that this Option is unused. This is the default state of + * elements in the result array. You don't need to test @c desc explicitly. You + * can simply write something like this: + * @code + * if (options[CREATE]) + * { + * ... + * } + * @endcode + * This works because of operator const Option*() . + */ + const Descriptor* desc; + + /** + * @brief The name of the option as used on the command line. + * + * The main purpose of this string is to be presented to the user in messages. + * + * In the case of a long option, this is the actual @c argv pointer, i.e. the first + * character is a '-'. In the case of a short option this points to the option + * character within the @c argv string. + * + * Note that in the case of a short option group or an attached option argument, this + * string will contain additional characters following the actual name. Use @ref namelen + * to filter out the actual option name only. + * + */ + const char* name; + + /** + * @brief Pointer to this Option's argument (if any). + * + * NULL if this option has no argument. Do not confuse this with the empty string which + * is a valid argument. + */ + const char* arg; + + /** + * @brief The length of the option @ref name. + * + * Because @ref name points into the actual @c argv string, the option name may be + * followed by more characters (e.g. other short options in the same short option group). + * This value is the number of bytes (not characters!) that are part of the actual name. + * + * For a short option, this length is always 1. For a long option this length is always + * at least 2 if single minus long options are permitted and at least 3 if they are disabled. + * + * @note + * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this + * length is incorrect, because this case will be misinterpreted as a long option and the + * name will therefore extend to the string's 0-terminator or a following '=" character + * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you + * really need to distinguish the case of a long and a short option, compare @ref name to + * the @c argv pointers. A long option's @c name is always identical to one of them, + * whereas a short option's is never. + */ + int namelen; + + /** + * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option + * is invalid (unused). + * + * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided + * you arrange your types properly) switch on type() without testing validity first. + * @code + * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 }; + * enum OptionIndex { FOO }; + * const Descriptor usage[] = { + * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 }, + * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 }, + * { 0, 0, 0, 0, 0, 0 } }; + * ... + * switch(options[FOO].last()->type()) // no validity check required! + * { + * case ENABLED: ... + * case DISABLED: ... // UNUSED==DISABLED ! + * } + * @endcode + */ + int type() const + { + return desc == 0 ? 0 : desc->type; + } + + /** + * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option + * is invalid (unused). + */ + int index() const + { + return desc == 0 ? -1 : desc->index; + } + + /** + * @brief Returns the number of times this Option (or others with the same Descriptor::index) + * occurs in the argument vector. + * + * This corresponds to the number of elements in the linked list this Option is part of. + * It doesn't matter on which element you call count(). The return value is always the same. + * + * Use this to implement cumulative options, such as -v, -vv, -vvv for + * different verbosity levels. + * + * Returns 0 when called for an unused/invalid option. + */ + int count() + { + int c = (desc == 0 ? 0 : 1); + Option* p = first(); + while (!p->isLast()) + { + ++c; + p = p->next_; + }; + return c; + } + + /** + * @brief Returns true iff this is the first element of the linked list. + * + * The first element in the linked list is the first option on the command line + * that has the respective Descriptor::index value. + * + * Returns true for an unused/invalid option. + */ + bool isFirst() const + { + return isTagged(prev_); + } + + /** + * @brief Returns true iff this is the last element of the linked list. + * + * The last element in the linked list is the last option on the command line + * that has the respective Descriptor::index value. + * + * Returns true for an unused/invalid option. + */ + bool isLast() const + { + return isTagged(next_); + } + + /** + * @brief Returns a pointer to the first element of the linked list. + * + * Use this when you want the first occurrence of an option on the command line to + * take precedence. Note that this is not the way most programs handle options. + * You should probably be using last() instead. + * + * @note + * This method may be called on an unused/invalid option and will return a pointer to the + * option itself. + */ + Option* first() + { + Option* p = this; + while (!p->isFirst()) + p = p->prev_; + return p; + } + + /** + * @brief Returns a pointer to the last element of the linked list. + * + * Use this when you want the last occurrence of an option on the command line to + * take precedence. This is the most common way of handling conflicting options. + * + * @note + * This method may be called on an unused/invalid option and will return a pointer to the + * option itself. + * + * @par Tip: + * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you + * can assign them the same Descriptor::index to get them into the same list. Distinguish them by + * Descriptor::type and all you have to do is check last()->type() to get + * the state listed last on the command line. + */ + Option* last() + { + return first()->prevwrap(); + } + + /** + * @brief Returns a pointer to the previous element of the linked list or NULL if + * called on first(). + * + * If called on first() this method returns NULL. Otherwise it will return the + * option with the same Descriptor::index that precedes this option on the command + * line. + */ + Option* prev() + { + return isFirst() ? 0 : prev_; + } + + /** + * @brief Returns a pointer to the previous element of the linked list with wrap-around from + * first() to last(). + * + * If called on first() this method returns last(). Otherwise it will return the + * option with the same Descriptor::index that precedes this option on the command + * line. + */ + Option* prevwrap() + { + return untag(prev_); + } + + /** + * @brief Returns a pointer to the next element of the linked list or NULL if called + * on last(). + * + * If called on last() this method returns NULL. Otherwise it will return the + * option with the same Descriptor::index that follows this option on the command + * line. + */ + Option* next() + { + return isLast() ? 0 : next_; + } + + /** + * @brief Returns a pointer to the next element of the linked list with wrap-around from + * last() to first(). + * + * If called on last() this method returns first(). Otherwise it will return the + * option with the same Descriptor::index that follows this option on the command + * line. + */ + Option* nextwrap() + { + return untag(next_); + } + + /** + * @brief Makes @c new_last the new last() by chaining it into the list after last(). + * + * It doesn't matter which element you call append() on. The new element will always + * be appended to last(). + * + * @attention + * @c new_last must not yet be part of a list, or that list will become corrupted, because + * this method does not unchain @c new_last from an existing list. + */ + void append(Option* new_last) + { + Option* p = last(); + Option* f = first(); + p->next_ = new_last; + new_last->prev_ = p; + new_last->next_ = tag(f); + f->prev_ = tag(new_last); + } + + /** + * @brief Casts from Option to const Option* but only if this Option is valid. + * + * If this Option is valid (i.e. @c desc!=NULL), returns this. + * Otherwise returns NULL. This allows testing an Option directly + * in an if-clause to see if it is used: + * @code + * if (options[CREATE]) + * { + * ... + * } + * @endcode + * It also allows you to write loops like this: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + */ + operator const Option*() const + { + return desc ? this : 0; + } + + /** + * @brief Casts from Option to Option* but only if this Option is valid. + * + * If this Option is valid (i.e. @c desc!=NULL), returns this. + * Otherwise returns NULL. This allows testing an Option directly + * in an if-clause to see if it is used: + * @code + * if (options[CREATE]) + * { + * ... + * } + * @endcode + * It also allows you to write loops like this: + * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) + * fname = opt->arg; ... @endcode + */ + operator Option*() + { + return desc ? this : 0; + } + + /** + * @brief Creates a new Option that is a one-element linked list and has NULL + * @ref desc, @ref name, @ref arg and @ref namelen. + */ + Option() : + desc(0), name(0), arg(0), namelen(0) + { + prev_ = tag(this); + next_ = tag(this); + } + + /** + * @brief Creates a new Option that is a one-element linked list and has the given + * values for @ref desc, @ref name and @ref arg. + * + * If @c name_ points at a character other than '-' it will be assumed to refer to a + * short option and @ref namelen will be set to 1. Otherwise the length will extend to + * the first '=' character or the string's 0-terminator. + */ + Option(const Descriptor* desc_, const char* name_, const char* arg_) + { + init(desc_, name_, arg_); + } + + /** + * @brief Makes @c *this a copy of @c orig except for the linked list pointers. + * + * After this operation @c *this will be a one-element linked list. + */ + void operator=(const Option& orig) + { + init(orig.desc, orig.name, orig.arg); + } + + /** + * @brief Makes @c *this a copy of @c orig except for the linked list pointers. + * + * After this operation @c *this will be a one-element linked list. + */ + Option(const Option& orig) + { + init(orig.desc, orig.name, orig.arg); + } + +private: + /** + * @internal + * @brief Sets the fields of this Option to the given values (extracting @c name if necessary). + * + * If @c name_ points at a character other than '-' it will be assumed to refer to a + * short option and @ref namelen will be set to 1. Otherwise the length will extend to + * the first '=' character or the string's 0-terminator. + */ + void init(const Descriptor* desc_, const char* name_, const char* arg_) + { + desc = desc_; + name = name_; + arg = arg_; + prev_ = tag(this); + next_ = tag(this); + namelen = 0; + if (name == 0) + return; + namelen = 1; + if (name[0] != '-') + return; + while (name[namelen] != 0 && name[namelen] != '=') + ++namelen; + } + + static Option* tag(Option* ptr) + { + return (Option*) ((unsigned long long) ptr | 1); + } + + static Option* untag(Option* ptr) + { + return (Option*) ((unsigned long long) ptr & ~1ull); + } + + static bool isTagged(Option* ptr) + { + return ((unsigned long long) ptr & 1); + } +}; + +/** + * @brief Functions for checking the validity of option arguments. + * + * @copydetails CheckArg + * + * The following example code + * can serve as starting place for writing your own more complex CheckArg functions: + * @code + * struct Arg: public option::Arg + * { + * static void printError(const char* msg1, const option::Option& opt, const char* msg2) + * { + * fprintf(stderr, "ERROR: %s", msg1); + * fwrite(opt.name, opt.namelen, 1, stderr); + * fprintf(stderr, "%s", msg2); + * } + * + * static option::ArgStatus Unknown(const option::Option& option, bool msg) + * { + * if (msg) printError("Unknown option '", option, "'\n"); + * return option::ARG_ILLEGAL; + * } + * + * static option::ArgStatus Required(const option::Option& option, bool msg) + * { + * if (option.arg != 0) + * return option::ARG_OK; + * + * if (msg) printError("Option '", option, "' requires an argument\n"); + * return option::ARG_ILLEGAL; + * } + * + * static option::ArgStatus NonEmpty(const option::Option& option, bool msg) + * { + * if (option.arg != 0 && option.arg[0] != 0) + * return option::ARG_OK; + * + * if (msg) printError("Option '", option, "' requires a non-empty argument\n"); + * return option::ARG_ILLEGAL; + * } + * + * static option::ArgStatus Numeric(const option::Option& option, bool msg) + * { + * char* endptr = 0; + * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){}; + * if (endptr != option.arg && *endptr == 0) + * return option::ARG_OK; + * + * if (msg) printError("Option '", option, "' requires a numeric argument\n"); + * return option::ARG_ILLEGAL; + * } + * }; + * @endcode + */ +struct Arg +{ + //! @brief For options that don't take an argument: Returns ARG_NONE. + static ArgStatus None(const Option&, bool) + { + return ARG_NONE; + } + static void printError(const char* msg1, const option::Option& opt, const char* msg2) + { + fprintf(stderr, "ERROR: %s", msg1); + fwrite(opt.name, opt.namelen, 1, stderr); + fprintf(stderr, "%s", msg2); + } + + //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise. + static ArgStatus Optional(const Option& option, bool) + { + if (option.arg && option.name[option.namelen] != 0) + return ARG_OK; + else + return ARG_IGNORE; + } + static option::ArgStatus Required(const option::Option& option, bool msg) + { + if (option.arg != 0) + return option::ARG_OK; + + if (msg) printError("Option '", option, "' requires an argument\n"); + return option::ARG_ILLEGAL; + } +}; + +/** + * @brief Determines the minimum lengths of the buffer and options arrays used for Parser. + * + * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated. + * If you don't want to use fixed size arrays (which may turn out too small, causing + * command line arguments to be dropped), you can use Stats to determine the correct sizes. + * Stats work cumulative. You can first pass in your default options and then the real + * options and afterwards the counts will reflect the union. + */ +struct Stats +{ + /** + * @brief Number of elements needed for a @c buffer[] array to be used for + * @ref Parser::parse() "parsing" the same argument vectors that were fed + * into this Stats object. + * + * @note + * This number is always 1 greater than the actual number needed, to give + * you a sentinel element. + */ + unsigned buffer_max; + + /** + * @brief Number of elements needed for an @c options[] array to be used for + * @ref Parser::parse() "parsing" the same argument vectors that were fed + * into this Stats object. + * + * @note + * @li This number is always 1 greater than the actual number needed, to give + * you a sentinel element. + * @li This number depends only on the @c usage, not the argument vectors, because + * the @c options array needs exactly one slot for each possible Descriptor::index. + */ + unsigned options_max; + + /** + * @brief Creates a Stats object with counts set to 1 (for the sentinel element). + */ + Stats() : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + } + + /** + * @brief Creates a new Stats object and immediately updates it for the + * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, + * if you just want to update @ref options_max. + * + * @note + * The calls to Stats methods must match the later calls to Parser methods. + * See Parser::parse() for the meaning of the arguments. + */ + Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt); + } + + //! @brief Stats(...) with non-const argv. + Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX Stats(...) (gnu==false). + Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX Stats(...) (gnu==false) with non-const argv. + Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) : + buffer_max(1), options_max(1) // 1 more than necessary as sentinel + { + add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); + } + + /** + * @brief Updates this Stats object for the + * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, + * if you just want to update @ref options_max. + * + * @note + * The calls to Stats methods must match the later calls to Parser methods. + * See Parser::parse() for the meaning of the arguments. + */ + void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false); + + //! @brief add() with non-const argv. + void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { + add(gnu, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX add() (gnu==false). + void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { + add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); + } + + //! @brief POSIX add() (gnu==false) with non-const argv. + void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // + bool single_minus_longopt = false) + { + add(false, usage, argc, (const char**) argv, min_abbr_len, single_minus_longopt); + } +private: + class CountOptionsAction; +}; + +/** + * @brief Checks argument vectors for validity and parses them into data + * structures that are easier to work with. + * + * @par Example: + * @code + * int main(int argc, char* argv[]) + * { + * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present + * option::Stats stats(usage, argc, argv); + * option::Option options[stats.options_max], buffer[stats.buffer_max]; + * option::Parser parse(usage, argc, argv, options, buffer); + * + * if (parse.error()) + * return 1; + * + * if (options[HELP]) + * ... + * @endcode + */ +class Parser +{ + int op_count; //!< @internal @brief see optionsCount() + int nonop_count; //!< @internal @brief see nonOptionsCount() + const char** nonop_args; //!< @internal @brief see nonOptions() + bool err; //!< @internal @brief see error() +public: + + /** + * @brief Creates a new Parser. + */ + Parser() : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + } + + /** + * @brief Creates a new Parser and immediately parses the given argument vector. + * @copydetails parse() + */ + Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief Parser(...) with non-const argv. + Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX Parser(...) (gnu==false). + Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, + bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX Parser(...) (gnu==false) with non-const argv. + Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, + bool single_minus_longopt = false, int bufmax = -1) : + op_count(0), nonop_count(0), nonop_args(0), err(false) + { + parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + /** + * @brief Parses the given argument vector. + * + * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will + * reorder arguments so that all non-options are at the end. This is the default behaviour + * of GNU getopt() but is not conforming to POSIX. @n + * Note, that once the argument vector has been reordered, the @c gnu flag will have + * no further effect on this argument vector. So it is enough to pass @c gnu==true when + * creating Stats. + * @param usage Array of Descriptor objects that describe the options to support. The last entry + * of this array must have 0 in all fields. + * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number + * will be determined automatically. In that case the @c argv list must end with a NULL + * pointer. + * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv + * list must be NULL to mark the end. + * @param options Each entry is the first element of a linked list of Options. Each new option + * that is parsed will be appended to the list specified by that Option's + * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid), + * it will be replaced rather than appended to. @n + * The minimum length of this array is the greatest Descriptor::index value that + * occurs in @c usage @e PLUS ONE. + * @param buffer Each argument that is successfully parsed (including unknown arguments, if they + * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this + * array. parse() scans the array for the first invalid entry and begins writing at that + * index. You can pass @c bufmax to limit the number of options stored. + * @param min_abbr_len Passing a value min_abbr_len > 0 enables abbreviated long + * options. The parser will match a prefix of a long option as if it was + * the full long option (e.g. @c --foob=10 will be interpreted as if it was + * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters + * (not counting the @c -- ) and is unambiguous. + * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true + * because the ambiguity check does not consider short options and abbreviated + * single minus long options will take precedence over short options. + * @param single_minus_longopt Passing @c true for this option allows long options to begin with + * a single minus. The double minus form will still be recognized. Note that + * single minus long options take precedence over short options and short option + * groups. E.g. @c -file would be interpreted as @c --file and not as + * -f -i -l -e (assuming a long option named @c "file" exists). + * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is + * @c bufmax-1. If there are more options, they will be processed (in particular + * their CheckArg will be called) but not stored. @n + * If you used Stats::buffer_max to dimension this array, you can pass + * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is + * "large enough". + * @attention + * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it + * is not possible for the same object to be in both arrays. For those options that are found in + * both @c buffer[] and @c options[] the respective objects are independent copies. And only the + * objects in @c options[] are properly linked via Option::next() and Option::prev(). + * You can iterate over @c buffer[] to + * process all options in the order they appear in the argument vector, but if you want access to + * the other Options with the same Descriptor::index, then you @e must access the linked list via + * @c options[]. You can get the linked list in options from a buffer object via something like + * @c options[buffer[i].index()]. + */ + void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1); + + //! @brief parse() with non-const argv. + void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) + { + parse(gnu, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX parse() (gnu==false). + void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], + int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) + { + parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + //! @brief POSIX parse() (gnu==false) with non-const argv. + void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, + bool single_minus_longopt = false, int bufmax = -1) + { + parse(false, usage, argc, (const char**) argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); + } + + /** + * @brief Returns the number of valid Option objects in @c buffer[]. + * + * @note + * @li The returned value always reflects the number of Options in the buffer[] array used for + * the most recent call to parse(). + * @li The count (and the buffer[]) includes unknown options if they are collected + * (see Descriptor::longopt). + */ + int optionsCount() + { + return op_count; + } + + /** + * @brief Returns the number of non-option arguments that remained at the end of the + * most recent parse() that actually encountered non-option arguments. + * + * @note + * A parse() that does not encounter non-option arguments will leave this value + * as well as nonOptions() undisturbed. This means you can feed the Parser a + * default argument vector that contains non-option arguments (e.g. a default filename). + * Then you feed it the actual arguments from the user. If the user has supplied at + * least one non-option argument, all of the non-option arguments from the default + * disappear and are replaced by the user's non-option arguments. However, if the + * user does not supply any non-option arguments the defaults will still be in + * effect. + */ + int nonOptionsCount() + { + return nonop_count; + } + + /** + * @brief Returns a pointer to an array of non-option arguments (only valid + * if nonOptionsCount() >0 ). + * + * @note + * @li parse() does not copy arguments, so this pointer points into the actual argument + * vector as passed to parse(). + * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls + * that actually encounter non-option arguments. A parse() call that encounters only + * options, will not change nonOptions(). + */ + const char** nonOptions() + { + return nonop_args; + } + + /** + * @brief Returns nonOptions()[i] (@e without checking if i is in range!). + */ + const char* nonOption(int i) + { + return nonOptions()[i]; + } + + /** + * @brief Returns @c true if an unrecoverable error occurred while parsing options. + * + * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an + * unrecoverable error that aborts the parse. Unknown options are only an error if + * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected. + * In that case if you want to exit the program if either an illegal argument + * or an unknown option has been passed, use code like this + * + * @code + * if (parser.error() || options[UNKNOWN]) + * exit(1); + * @endcode + * + */ + bool error() + { + return err; + } + +private: + friend struct Stats; + class StoreOptionAction; + struct Action; + + /** + * @internal + * @brief This is the core function that does all the parsing. + * @retval false iff an unrecoverable error occurred. + */ + static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, + bool single_minus_longopt, bool print_errors, int min_abbr_len); + + /** + * @internal + * @brief Returns true iff @c st1 is a prefix of @c st2 and + * in case @c st2 is longer than @c st1, then + * the first additional character is '='. + * + * @par Examples: + * @code + * streq("foo", "foo=bar") == true + * streq("foo", "foobar") == false + * streq("foo", "foo") == true + * streq("foo=bar", "foo") == false + * @endcode + */ + static bool streq(const char* st1, const char* st2) + { + while (*st1 != 0) + if (*st1++ != *st2++) + return false; + return (*st2 == 0 || *st2 == '='); + } + + /** + * @internal + * @brief Like streq() but handles abbreviations. + * + * Returns true iff @c st1 and @c st2 have a common + * prefix with the following properties: + * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller). + * @li (if min <= 0) its length is the same as that of @c st1 + * @li within @c st2 the character following the common prefix is either '=' or end-of-string. + * + * Examples: + * @code + * streqabbr("foo", "foo=bar",) == true + * streqabbr("foo", "fo=bar" , 2) == true + * streqabbr("foo", "fo" , 2) == true + * streqabbr("foo", "fo" , 0) == false + * streqabbr("foo", "f=bar" , 2) == false + * streqabbr("foo", "f" , 2) == false + * streqabbr("fo" , "foo=bar",) == false + * streqabbr("foo", "foobar" ,) == false + * streqabbr("foo", "fobar" ,) == false + * streqabbr("foo", "foo" ,) == true + * @endcode + */ + static bool streqabbr(const char* st1, const char* st2, long long min) + { + const char* st1start = st1; + while (*st1 != 0 && (*st1 == *st2)) + { + ++st1; + ++st2; + } + + return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '='); + } + + /** + * @internal + * @brief Returns true iff character @c ch is contained in the string @c st. + * + * Returns @c true for @c ch==0 . + */ + static bool instr(char ch, const char* st) + { + while (*st != 0 && *st != ch) + ++st; + return *st == ch; + } + + /** + * @internal + * @brief Rotates args[-count],...,args[-1],args[0] to become + * args[0],args[-count],...,args[-1]. + */ + static void shift(const char** args, int count) + { + for (int i = 0; i > -count; --i) + { + const char* temp = args[i]; + args[i] = args[i - 1]; + args[i - 1] = temp; + } + } +}; + +/** + * @internal + * @brief Interface for actions Parser::workhorse() should perform for each Option it + * parses. + */ +struct Parser::Action +{ + /** + * @brief Called by Parser::workhorse() for each Option that has been successfully + * parsed (including unknown + * options if they have a Descriptor whose Descriptor::check_arg does not return + * @ref ARG_ILLEGAL. + * + * Returns @c false iff a fatal error has occured and the parse should be aborted. + */ + virtual bool perform(Option&) + { + return true; + } + + /** + * @brief Called by Parser::workhorse() after finishing the parse. + * @param numargs the number of non-option arguments remaining + * @param args pointer to the first remaining non-option argument (if numargs > 0). + * + * @return + * @c false iff a fatal error has occurred. + */ + virtual bool finished(int numargs, const char** args) + { + (void) numargs; + (void) args; + return true; + } +}; + +/** + * @internal + * @brief An Action to pass to Parser::workhorse() that will increment a counter for + * each parsed Option. + */ +class Stats::CountOptionsAction: public Parser::Action +{ + unsigned* buffer_max; +public: + /** + * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each + * parsed Option. + */ + CountOptionsAction(unsigned* buffer_max_) : + buffer_max(buffer_max_) + { + } + + bool perform(Option&) + { + if (*buffer_max == 0x7fffffff) + return false; // overflow protection: don't accept number of options that doesn't fit signed int + ++*buffer_max; + return true; + } +}; + +/** + * @internal + * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in + * appropriate arrays (see Parser::parse()). + */ +class Parser::StoreOptionAction: public Parser::Action +{ + Parser& parser; + Option* options; + Option* buffer; + int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough". +public: + /** + * @brief Creates a new StoreOption action. + * @param parser_ the parser whose op_count should be updated. + * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index] + * @param buffer_ each Option is appended to this array as long as there's a free slot. + * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough". + */ + StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) : + parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_) + { + // find first empty slot in buffer (if any) + int bufidx = 0; + while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx]) + ++bufidx; + + // set parser's optionCount + parser.op_count = bufidx; + } + + bool perform(Option& option) + { + if (bufmax < 0 || parser.op_count < bufmax) + { + if (parser.op_count == 0x7fffffff) + return false; // overflow protection: don't accept number of options that doesn't fit signed int + + buffer[parser.op_count] = option; + int idx = buffer[parser.op_count].desc->index; + if (options[idx]) + options[idx].append(buffer[parser.op_count]); + else + options[idx] = buffer[parser.op_count]; + ++parser.op_count; + } + return true; // NOTE: an option that is discarded because of a full buffer is not fatal + } + + bool finished(int numargs, const char** args) + { + // only overwrite non-option argument list if there's at least 1 + // new non-option argument. Otherwise we keep the old list. This + // makes it easy to use default non-option arguments. + if (numargs > 0) + { + parser.nonop_count = numargs; + parser.nonop_args = args; + } + + return true; + } +}; + +inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], + Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax) +{ + StoreOptionAction action(*this, options, buffer, bufmax); + err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len); +} + +inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len, + bool single_minus_longopt) +{ + // determine size of options array. This is the greatest index used in the usage + 1 + int i = 0; + while (usage[i].shortopt != 0) + { + if (usage[i].index + 1 >= options_max) + options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel + + ++i; + } + + CountOptionsAction action(&buffer_max); + Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len); +} + +inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, + bool single_minus_longopt, bool print_errors, int min_abbr_len) +{ + // protect against NULL pointer + if (args == 0) + numargs = 0; + + int nonops = 0; + + while (numargs != 0 && *args != 0) + { + const char* param = *args; // param can be --long-option, -srto or non-option argument + + // in POSIX mode the first non-option argument terminates the option list + // a lone minus character is a non-option argument + if (param[0] != '-' || param[1] == 0) + { + if (gnu) + { + ++nonops; + ++args; + if (numargs > 0) + --numargs; + continue; + } + else + break; + } + + // -- terminates the option list. The -- itself is skipped. + if (param[1] == '-' && param[2] == 0) + { + shift(args, nonops); + ++args; + if (numargs > 0) + --numargs; + break; + } + + bool handle_short_options; + const char* longopt_name; + if (param[1] == '-') // if --long-option + { + handle_short_options = false; + longopt_name = param + 2; + } + else + { + handle_short_options = true; + longopt_name = param + 1; //for testing a potential -long-option + } + + bool try_single_minus_longopt = single_minus_longopt; + bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid? + + do // loop over short options in group, for long options the body is executed only once + { + int idx; + + const char* optarg; + + /******************** long option **********************/ + if (handle_short_options == false || try_single_minus_longopt) + { + idx = 0; + while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name)) + ++idx; + + if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options + { + int i1 = 0; + while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len)) + ++i1; + if (usage[i1].longopt != 0) + { // now test if the match is unambiguous by checking for another match + int i2 = i1 + 1; + while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len)) + ++i2; + + if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx + idx = i1; + } + } + + // if we found something, disable handle_short_options (only relevant if single_minus_longopt) + if (usage[idx].longopt != 0) + handle_short_options = false; + + try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group + + optarg = longopt_name; + while (*optarg != 0 && *optarg != '=') + ++optarg; + if (*optarg == '=') // attached argument + ++optarg; + else + // possibly detached argument + optarg = (have_more_args ? args[1] : 0); + } + + /************************ short option ***********************************/ + if (handle_short_options) + { + if (*++param == 0) // point at the 1st/next option character + break; // end of short option group + + idx = 0; + while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt)) + ++idx; + + if (param[1] == 0) // if the potential argument is separate + optarg = (have_more_args ? args[1] : 0); + else + // if the potential argument is attached + optarg = param + 1; + } + + const Descriptor* descriptor = &usage[idx]; + + if (descriptor->shortopt == 0) /************** unknown option ********************/ + { + // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options + idx = 0; + while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0)) + ++idx; + descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]); + } + + if (descriptor != 0) + { + Option option(descriptor, param, optarg); + switch (descriptor->check_arg(option, print_errors)) + { + case ARG_ILLEGAL: + return false; // fatal + case ARG_OK: + // skip one element of the argument vector, if it's a separated argument + if (optarg != 0 && have_more_args && optarg == args[1]) + { + shift(args, nonops); + if (numargs > 0) + --numargs; + ++args; + } + + // No further short options are possible after an argument + handle_short_options = false; + + break; + case ARG_IGNORE: + case ARG_NONE: + option.arg = 0; + break; + } + + if (!action.perform(option)) + return false; + } + + } while (handle_short_options); + + shift(args, nonops); + ++args; + if (numargs > 0) + --numargs; + + } // while + + if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number + numargs = 0; // of arguments, but as a service to the user we fix this if we spot it. + + if (numargs < 0) // if we don't know the number of remaining non-option arguments + { // we need to count them + numargs = 0; + while (args[numargs] != 0) + ++numargs; + } + + return action.finished(numargs + nonops, args - nonops); +} + +/** + * @internal + * @brief The implementation of option::printUsage(). + */ +struct PrintUsageImplementation +{ + /** + * @internal + * @brief Interface for Functors that write (part of) a string somewhere. + */ + struct IStringWriter + { + /** + * @brief Writes the given number of chars beginning at the given pointer somewhere. + */ + virtual void operator()(const char*, int) + { + } + }; + + /** + * @internal + * @brief Encapsulates a function with signature func(string, size) where + * string can be initialized with a const char* and size with an int. + */ + template + struct FunctionWriter: public IStringWriter + { + Function* write; + + virtual void operator()(const char* str, int size) + { + (*write)(str, size); + } + + FunctionWriter(Function* w) : + write(w) + { + } + }; + + /** + * @internal + * @brief Encapsulates a reference to an object with a write(string, size) + * method like that of @c std::ostream. + */ + template + struct OStreamWriter: public IStringWriter + { + OStream& ostream; + + virtual void operator()(const char* str, int size) + { + ostream.write(str, size); + } + + OStreamWriter(OStream& o) : + ostream(o) + { + } + }; + + /** + * @internal + * @brief Like OStreamWriter but encapsulates a @c const reference, which is + * typically a temporary object of a user class. + */ + template + struct TemporaryWriter: public IStringWriter + { + const Temporary& userstream; + + virtual void operator()(const char* str, int size) + { + userstream.write(str, size); + } + + TemporaryWriter(const Temporary& u) : + userstream(u) + { + } + }; + + /** + * @internal + * @brief Encapsulates a function with the signature func(fd, string, size) (the + * signature of the @c write() system call) + * where fd can be initialized from an int, string from a const char* and size from an int. + */ + template + struct SyscallWriter: public IStringWriter + { + Syscall* write; + int fd; + + virtual void operator()(const char* str, int size) + { + (*write)(fd, str, size); + } + + SyscallWriter(Syscall* w, int f) : + write(w), fd(f) + { + } + }; + + /** + * @internal + * @brief Encapsulates a function with the same signature as @c std::fwrite(). + */ + template + struct StreamWriter: public IStringWriter + { + Function* fwrite; + Stream* stream; + + virtual void operator()(const char* str, int size) + { + (*fwrite)(str, size, 1, stream); + } + + StreamWriter(Function* w, Stream* s) : + fwrite(w), stream(s) + { + } + }; + + /** + * @internal + * @brief Sets i1 = max(i1, i2) + */ + static void upmax(int& i1, int i2) + { + i1 = (i1 >= i2 ? i1 : i2); + } + + /** + * @internal + * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x + * and sets @c x=want_x . + * If x > want_x , a line break is output before indenting. + * + * @param write Spaces and possibly a line break are written via this functor to get + * the desired indentation @c want_x . + * @param[in,out] x the current indentation. Set to @c want_x by this method. + * @param want_x the desired indentation. + */ + static void indent(IStringWriter& write, int& x, int want_x) + { + int indent = want_x - x; + if (indent < 0) + { + write("\n", 1); + indent = want_x; + } + + if (indent > 0) + { + char space = ' '; + for (int i = 0; i < indent; ++i) + write(&space, 1); + x = want_x; + } + } + + /** + * @brief Returns true if ch is the unicode code point of a wide character. + * + * @note + * The following character ranges are treated as wide + * @code + * 1100..115F + * 2329..232A (just 2 characters!) + * 2E80..A4C6 except for 303F + * A960..A97C + * AC00..D7FB + * F900..FAFF + * FE10..FE6B + * FF01..FF60 + * FFE0..FFE6 + * 1B000...... + * @endcode + */ + static bool isWideChar(unsigned ch) + { + if (ch == 0x303F) + return false; + + return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6) + || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF) + || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6) + || (0x1B000 <= ch)); + } + + /** + * @internal + * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and + * iterates over these components. + * + * The top-level organizational unit is the @e table. + * A table begins at a Descriptor with @c help!=NULL and extends up to + * a Descriptor with @c help==NULL. + * + * A table consists of @e rows. Due to line-wrapping and explicit breaks + * a row may take multiple lines on screen. Rows within the table are separated + * by \\n. They never cross Descriptor boundaries. This means a row ends either + * at \\n or the 0 at the end of the help string. + * + * A row consists of columns/cells. Columns/cells within a row are separated by \\t. + * Line breaks within a cell are marked by \\v. + * + * Rows in the same table need not have the same number of columns/cells. The + * extreme case are interjections, which are rows that contain neither \\t nor \\v. + * These are NOT treated specially by LinePartIterator, but they are treated + * specially by printUsage(). + * + * LinePartIterator iterates through the usage at 3 levels: table, row and part. + * Tables and rows are as described above. A @e part is a line within a cell. + * LinePartIterator iterates through 1st parts of all cells, then through the 2nd + * parts of all cells (if any),... @n + * Example: The row "1 \v 3 \t 2 \v 4" has 2 cells/columns and 4 parts. + * The parts will be returned in the order 1, 2, 3, 4. + * + * It is possible that some cells have fewer parts than others. In this case + * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator + * always returns the same number of parts for each column. Note that this is different + * from the way rows and columns are handled. LinePartIterator does @e not guarantee that + * the same number of columns will be returned for each row. + * + */ + class LinePartIterator + { + const Descriptor* tablestart; //!< The 1st descriptor of the current table. + const Descriptor* rowdesc; //!< The Descriptor that contains the current row. + const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help. + const char* ptr; //!< Ptr to current part within the current row. + int col; //!< Index of current column. + int len; //!< Length of the current part (that ptr points at) in BYTES + int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account). + int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs. + int line_in_block; //!< Line index within the current cell of the current part. + int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration. + bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell. + + /** + * @brief Determines the byte and character lengths of the part at @ref ptr and + * stores them in @ref len and @ref screenlen respectively. + */ + void update_length() + { + screenlen = 0; + for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len) + { + ++screenlen; + unsigned ch = (unsigned char) ptr[len]; + if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte + { + // int __builtin_clz (unsigned int x) + // Returns the number of leading 0-bits in x, starting at the most significant bit + unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); + ch = ch & mask; // mask out length bits, we don't verify their correctness + while (((unsigned char) ptr[len + 1] ^ 0x80) <= 0x3F) // while next byte is continuation byte + { + ch = (ch << 6) ^ (unsigned char) ptr[len + 1] ^ 0x80; // add continuation to char code + ++len; + } + // ch is the decoded unicode code point + if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case + ++screenlen; + } + } + } + + public: + //! @brief Creates an iterator for @c usage. + LinePartIterator(const Descriptor usage[]) : + tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), max_line_in_block(0), line_in_block(0), + target_line_in_block(0), hit_target_line(true) + { + } + + /** + * @brief Moves iteration to the next table (if any). Has to be called once on a new + * LinePartIterator to move to the 1st table. + * @retval false if moving to next table failed because no further table exists. + */ + bool nextTable() + { + // If this is NOT the first time nextTable() is called after the constructor, + // then skip to the next table break (i.e. a Descriptor with help == 0) + if (rowdesc != 0) + { + while (tablestart->help != 0 && tablestart->shortopt != 0) + ++tablestart; + } + + // Find the next table after the break (if any) + while (tablestart->help == 0 && tablestart->shortopt != 0) + ++tablestart; + + restartTable(); + return rowstart != 0; + } + + /** + * @brief Reset iteration to the beginning of the current table. + */ + void restartTable() + { + rowdesc = tablestart; + rowstart = tablestart->help; + ptr = 0; + } + + /** + * @brief Moves iteration to the next row (if any). Has to be called once after each call to + * @ref nextTable() to move to the 1st row of the table. + * @retval false if moving to next row failed because no further row exists. + */ + bool nextRow() + { + if (ptr == 0) + { + restartRow(); + return rowstart != 0; + } + + while (*ptr != 0 && *ptr != '\n') + ++ptr; + + if (*ptr == 0) + { + if ((rowdesc + 1)->help == 0) // table break + return false; + + ++rowdesc; + rowstart = rowdesc->help; + } + else // if (*ptr == '\n') + { + rowstart = ptr + 1; + } + + restartRow(); + return true; + } + + /** + * @brief Reset iteration to the beginning of the current row. + */ + void restartRow() + { + ptr = rowstart; + col = -1; + len = 0; + screenlen = 0; + max_line_in_block = 0; + line_in_block = 0; + target_line_in_block = 0; + hit_target_line = true; + } + + /** + * @brief Moves iteration to the next part (if any). Has to be called once after each call to + * @ref nextRow() to move to the 1st part of the row. + * @retval false if moving to next part failed because no further part exists. + * + * See @ref LinePartIterator for details about the iteration. + */ + bool next() + { + if (ptr == 0) + return false; + + if (col == -1) + { + col = 0; + update_length(); + return true; + } + + ptr += len; + while (true) + { + switch (*ptr) + { + case '\v': + upmax(max_line_in_block, ++line_in_block); + ++ptr; + break; + case '\t': + if (!hit_target_line) // if previous column did not have the targetline + { // then "insert" a 0-length part + update_length(); + hit_target_line = true; + return true; + } + + hit_target_line = false; + line_in_block = 0; + ++col; + ++ptr; + break; + case 0: + case '\n': + if (!hit_target_line) // if previous column did not have the targetline + { // then "insert" a 0-length part + update_length(); + hit_target_line = true; + return true; + } + + if (++target_line_in_block > max_line_in_block) + { + update_length(); + return false; + } + + hit_target_line = false; + line_in_block = 0; + col = 0; + ptr = rowstart; + continue; + default: + ++ptr; + continue; + } // switch + + if (line_in_block == target_line_in_block) + { + update_length(); + hit_target_line = true; + return true; + } + } // while + } + + /** + * @brief Returns the index (counting from 0) of the column in which + * the part pointed to by @ref data() is located. + */ + int column() + { + return col; + } + + /** + * @brief Returns the index (counting from 0) of the line within the current column + * this part belongs to. + */ + int line() + { + return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line + } + + /** + * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters). + */ + int length() + { + return len; + } + + /** + * @brief Returns the width in screen columns of the part pointed to by @ref data(). + * Takes multi-byte UTF-8 sequences and wide characters into account. + */ + int screenLength() + { + return screenlen; + } + + /** + * @brief Returns the current part of the iteration. + */ + const char* data() + { + return ptr; + } + }; + + /** + * @internal + * @brief Takes input and line wraps it, writing out one line at a time so that + * it can be interleaved with output from other columns. + * + * The LineWrapper is used to handle the last column of each table as well as interjections. + * The LineWrapper is called once for each line of output. If the data given to it fits + * into the designated width of the last column it is simply written out. If there + * is too much data, an appropriate split point is located and only the data up to this + * split point is written out. The rest of the data is queued for the next line. + * That way the last column can be line wrapped and interleaved with data from + * other columns. The following example makes this clearer: + * @code + * Column 1,1 Column 2,1 This is a long text + * Column 1,2 Column 2,2 that does not fit into + * a single line. + * @endcode + * + * The difficulty in producing this output is that the whole string + * "This is a long text that does not fit into a single line" is the + * 1st and only part of column 3. In order to produce the above + * output the string must be output piecemeal, interleaved with + * the data from the other columns. + */ + class LineWrapper + { + static const int bufmask = 15; //!< Must be a power of 2 minus 1. + /** + * @brief Ring buffer for length component of pair (data, length). + */ + int lenbuf[bufmask + 1]; + /** + * @brief Ring buffer for data component of pair (data, length). + */ + const char* datbuf[bufmask + 1]; + /** + * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer + * assumes that the indentation has already been written when @ref process() + * is called, so this value is only used when a buffer flush requires writing + * additional lines of output. + */ + int x; + /** + * @brief The width of the column to line wrap. + */ + int width; + int head; //!< @brief index for next write + int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read) + + /** + * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to + * free up space. The contract of process() says that only 1 line is output. So + * this variable is used to track whether something has output a line. It is + * reset at the beginning of process() and checked at the end to decide if + * output has already occurred or is still needed. + */ + bool wrote_something; + + bool buf_empty() + { + return ((tail + 1) & bufmask) == head; + } + + bool buf_full() + { + return tail == head; + } + + void buf_store(const char* data, int len) + { + lenbuf[head] = len; + datbuf[head] = data; + head = (head + 1) & bufmask; + } + + //! @brief Call BEFORE reading ...buf[tail]. + void buf_next() + { + tail = (tail + 1) & bufmask; + } + + /** + * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line + * is flushed out of the buffer into @c write. + */ + void output(IStringWriter& write, const char* data, int len) + { + if (buf_full()) + write_one_line(write); + + buf_store(data, len); + } + + /** + * @brief Writes a single line of output from the buffer to @c write. + */ + void write_one_line(IStringWriter& write) + { + if (wrote_something) // if we already wrote something, we need to start a new line + { + write("\n", 1); + int _ = 0; + indent(write, _, x); + } + + if (!buf_empty()) + { + buf_next(); + write(datbuf[tail], lenbuf[tail]); + } + + wrote_something = true; + } + public: + + /** + * @brief Writes out all remaining data from the LineWrapper using @c write. + * Unlike @ref process() this method indents all lines including the first and + * will output a \\n at the end (but only if something has been written). + */ + void flush(IStringWriter& write) + { + if (buf_empty()) + return; + int _ = 0; + indent(write, _, x); + wrote_something = false; + while (!buf_empty()) + write_one_line(write); + write("\n", 1); + } + + /** + * @brief Process, wrap and output the next piece of data. + * + * process() will output at least one line of output. This is not necessarily + * the @c data passed in. It may be data queued from a prior call to process(). + * If the internal buffer is full, more than 1 line will be output. + * + * process() assumes that the a proper amount of indentation has already been + * output. It won't write any further indentation before the 1st line. If + * more than 1 line is written due to buffer constraints, the lines following + * the first will be indented by this method, though. + * + * No \\n is written by this method after the last line that is written. + * + * @param write where to write the data. + * @param data the new chunk of data to write. + * @param len the length of the chunk of data to write. + */ + void process(IStringWriter& write, const char* data, int len) + { + wrote_something = false; + + while (len > 0) + { + if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes) + { + output(write, data, len); + len = 0; + } + else // if (len > width) it's possible (but not guaranteed) that utf8len > width + { + int utf8width = 0; + int maxi = 0; + while (maxi < len && utf8width < width) + { + int charbytes = 1; + unsigned ch = (unsigned char) data[maxi]; + if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte + { + // int __builtin_clz (unsigned int x) + // Returns the number of leading 0-bits in x, starting at the most significant bit + unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); + ch = ch & mask; // mask out length bits, we don't verify their correctness + while ((maxi + charbytes < len) && // + (((unsigned char) data[maxi + charbytes] ^ 0x80) <= 0x3F)) // while next byte is continuation byte + { + ch = (ch << 6) ^ (unsigned char) data[maxi + charbytes] ^ 0x80; // add continuation to char code + ++charbytes; + } + // ch is the decoded unicode code point + if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case + { + if (utf8width + 2 > width) + break; + ++utf8width; + } + } + ++utf8width; + maxi += charbytes; + } + + // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits + // onto the 1st line. If maxi == len, all characters fit on the line. + + if (maxi == len) + { + output(write, data, len); + len = 0; + } + else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line + { + int i; + for (i = maxi; i >= 0; --i) + if (data[i] == ' ') + break; + + if (i >= 0) + { + output(write, data, i); + data += i + 1; + len -= i + 1; + } + else // did not find a space to split at => split before data[maxi] + { // data[maxi] is always the beginning of a character, never a continuation byte + output(write, data, maxi); + data += maxi; + len -= maxi; + } + } + } + } + if (!wrote_something) // if we didn't already write something to make space in the buffer + write_one_line(write); // write at most one line of actual output + } + + /** + * @brief Constructs a LineWrapper that wraps its output to fit into + * screen columns @c x1 (incl.) to @c x2 (excl.). + * + * @c x1 gives the indentation LineWrapper uses if it needs to indent. + */ + LineWrapper(int x1, int x2) : + x(x1), width(x2 - x1), head(0), tail(bufmask) + { + if (width < 2) // because of wide characters we need at least width 2 or the code breaks + width = 2; + } + }; + + /** + * @internal + * @brief This is the implementation that is shared between all printUsage() templates. + * Because all printUsage() templates share this implementation, there is no template bloat. + */ + static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, // + int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) + { + if (width < 1) // protect against nonsense values + width = 80; + + if (width > 10000) // protect against overflow in the following computation + width = 10000; + + int last_column_min_width = ((width * last_column_min_percent) + 50) / 100; + int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100; + if (last_column_own_line_max_width == 0) + last_column_own_line_max_width = 1; + + LinePartIterator part(usage); + while (part.nextTable()) + { + + /***************** Determine column widths *******************************/ + + const int maxcolumns = 8; // 8 columns are enough for everyone + int col_width[maxcolumns]; + int lastcolumn; + int leftwidth; + int overlong_column_threshold = 10000; + do + { + lastcolumn = 0; + for (int i = 0; i < maxcolumns; ++i) + col_width[i] = 0; + + part.restartTable(); + while (part.nextRow()) + { + while (part.next()) + { + if (part.column() < maxcolumns) + { + upmax(lastcolumn, part.column()); + if (part.screenLength() < overlong_column_threshold) + // We don't let rows that don't use table separators (\t or \v) influence + // the width of column 0. This allows the user to interject section headers + // or explanatory paragraphs that do not participate in the table layout. + if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' + || part.data()[part.length()] == '\v') + upmax(col_width[part.column()], part.screenLength()); + } + } + } + + /* + * If the last column doesn't fit on the same + * line as the other columns, we can fix that by starting it on its own line. + * However we can't do this for any of the columns 0..lastcolumn-1. + * If their sum exceeds the maximum width we try to fix this by iteratively + * ignoring the widest line parts in the width determination until + * we arrive at a series of column widths that fit into one line. + * The result is a layout where everything is nicely formatted + * except for a few overlong fragments. + * */ + + leftwidth = 0; + overlong_column_threshold = 0; + for (int i = 0; i < lastcolumn; ++i) + { + leftwidth += col_width[i]; + upmax(overlong_column_threshold, col_width[i]); + } + + } while (leftwidth > width); + + /**************** Determine tab stops and last column handling **********************/ + + int tabstop[maxcolumns]; + tabstop[0] = 0; + for (int i = 1; i < maxcolumns; ++i) + tabstop[i] = tabstop[i - 1] + col_width[i - 1]; + + int rightwidth = width - tabstop[lastcolumn]; + bool print_last_column_on_own_line = false; + if (rightwidth < last_column_min_width && rightwidth < col_width[lastcolumn]) + { + print_last_column_on_own_line = true; + rightwidth = last_column_own_line_max_width; + } + + // If lastcolumn == 0 we must disable print_last_column_on_own_line because + // otherwise 2 copies of the last (and only) column would be output. + // Actually this is just defensive programming. It is currently not + // possible that lastcolumn==0 and print_last_column_on_own_line==true + // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 => + // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes + // a bullshit value >100 for last_column_min_percent) => the above if condition + // is false => print_last_column_on_own_line==false + if (lastcolumn == 0) + print_last_column_on_own_line = false; + + LineWrapper lastColumnLineWrapper(width - rightwidth, width); + LineWrapper interjectionLineWrapper(0, width); + + part.restartTable(); + + /***************** Print out all rows of the table *************************************/ + + while (part.nextRow()) + { + int x = -1; + while (part.next()) + { + if (part.column() > lastcolumn) + continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1) + + if (part.column() == 0) + { + if (x >= 0) + write("\n", 1); + x = 0; + } + + indent(write, x, tabstop[part.column()]); + + if ((part.column() < lastcolumn) + && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' + || part.data()[part.length()] == '\v')) + { + write(part.data(), part.length()); + x += part.screenLength(); + } + else // either part.column() == lastcolumn or we are in the special case of + // an interjection that doesn't contain \v or \t + { + // NOTE: This code block is not necessarily executed for + // each line, because some rows may have fewer columns. + + LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper; + + if (!print_last_column_on_own_line) + lineWrapper.process(write, part.data(), part.length()); + } + } // while + + if (print_last_column_on_own_line) + { + part.restartRow(); + while (part.next()) + { + if (part.column() == lastcolumn) + { + write("\n", 1); + int _ = 0; + indent(write, _, width - rightwidth); + lastColumnLineWrapper.process(write, part.data(), part.length()); + } + } + } + + write("\n", 1); + lastColumnLineWrapper.flush(write); + interjectionLineWrapper.flush(write); + } + } + } + +} +; + +/** + * @brief Outputs a nicely formatted usage string with support for multi-column formatting + * and line-wrapping. + * + * printUsage() takes the @c help texts of a Descriptor[] array and formats them into + * a usage message, wrapping lines to achieve the desired output width. + * + * Table formatting: + * + * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables + * are used to align elements in the output. + * + * @code + * // Without a table. The explanatory texts are not aligned. + * -c, --create |Creates something. + * -k, --kill |Destroys something. + * + * // With table formatting. The explanatory texts are aligned. + * -c, --create |Creates something. + * -k, --kill |Destroys something. + * @endcode + * + * Table formatting removes the need to pad help texts manually with spaces to achieve + * alignment. To create a table, simply insert \\t (tab) characters to separate the cells + * within a row. + * + * @code + * const option::Descriptor usage[] = { + * {..., "-c, --create \tCreates something." }, + * {..., "-k, --kill \tDestroys something." }, ... + * @endcode + * + * Note that you must include the minimum amount of space desired between cells yourself. + * Table formatting will insert further spaces as needed to achieve alignment. + * + * You can insert line breaks within cells by using \\v (vertical tab). + * + * @code + * const option::Descriptor usage[] = { + * {..., "-c,\v--create \tCreates\vsomething." }, + * {..., "-k,\v--kill \tDestroys\vsomething." }, ... + * + * // results in + * + * -c, Creates + * --create something. + * -k, Destroys + * --kill something. + * @endcode + * + * You can mix lines that do not use \\t or \\v with those that do. The plain + * lines will not mess up the table layout. Alignment of the table columns will + * be maintained even across these interjections. + * + * @code + * const option::Descriptor usage[] = { + * {..., "-c, --create \tCreates something." }, + * {..., "----------------------------------" }, + * {..., "-k, --kill \tDestroys something." }, ... + * + * // results in + * + * -c, --create Creates something. + * ---------------------------------- + * -k, --kill Destroys something. + * @endcode + * + * You can have multiple tables within the same usage whose columns are + * aligned independently. Simply insert a dummy Descriptor with @c help==0. + * + * @code + * const option::Descriptor usage[] = { + * {..., "Long options:" }, + * {..., "--very-long-option \tDoes something long." }, + * {..., "--ultra-super-mega-long-option \tTakes forever to complete." }, + * {..., 0 }, // ---------- table break ----------- + * {..., "Short options:" }, + * {..., "-s \tShort." }, + * {..., "-q \tQuick." }, ... + * + * // results in + * + * Long options: + * --very-long-option Does something long. + * --ultra-super-mega-long-option Takes forever to complete. + * Short options: + * -s Short. + * -q Quick. + * + * // Without the table break it would be + * + * Long options: + * --very-long-option Does something long. + * --ultra-super-mega-long-option Takes forever to complete. + * Short options: + * -s Short. + * -q Quick. + * @endcode + * + * Output methods: + * + * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for + * output in the first argument(s) to printUsage(). Because printUsage() is implemented as + * a set of template functions, you have great flexibility in your choice of output + * method. The following example demonstrates typical uses. Anything that's similar enough + * will work. + * + * @code + * #include // write() + * #include // cout + * #include // ostringstream + * #include // fwrite() + * using namespace std; + * + * void my_write(const char* str, int size) { + * fwrite(str, size, 1, stdout); + * } + * + * struct MyWriter { + * void write(const char* buf, size_t size) const { + * fwrite(str, size, 1, stdout); + * } + * }; + * + * struct MyWriteFunctor { + * void operator()(const char* buf, size_t size) { + * fwrite(str, size, 1, stdout); + * } + * }; + * ... + * printUsage(my_write, usage); // custom write function + * printUsage(MyWriter(), usage); // temporary of a custom class + * MyWriter writer; + * printUsage(writer, usage); // custom class object + * MyWriteFunctor wfunctor; + * printUsage(&wfunctor, usage); // custom functor + * printUsage(write, 1, usage); // write() to file descriptor 1 + * printUsage(cout, usage); // an ostream& + * printUsage(fwrite, stdout, usage); // fwrite() to stdout + * ostringstream sstr; + * printUsage(sstr, usage); // an ostringstream& + * + * @endcode + * + * @par Notes: + * @li the @c write() method of a class that is to be passed as a temporary + * as @c MyWriter() is in the example, must be a @c const method, because + * temporary objects are passed as const reference. This only applies to + * temporary objects that are created and destroyed in the same statement. + * If you create an object like @c writer in the example, this restriction + * does not apply. + * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer. + * This differs from the way functors are passed to e.g. the STL algorithms. + * @li All printUsage() templates are tiny wrappers around a shared non-template implementation. + * So there's no penalty for using different versions in the same program. + * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded + * output. If your system uses a different charset, you must do your own conversion. You + * may also need to change the font of the console to see non-ASCII characters properly. + * This is particularly true for Windows. + * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments) + * into the usage. printUsage() has no protection against malicious UTF-8 sequences. + * + * @param prn The output method to use. See the examples above. + * @param usage the Descriptor[] array whose @c help texts will be formatted. + * @param width the maximum number of characters per output line. Note that this number is + * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will + * count multi-byte UTF-8 sequences properly. Asian wide characters are counted + * as 2 characters. + * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available + * for the last column (which typically contains the textual explanation of an option). + * If less space is available, the last column will be printed on its own line, indented + * according to @c last_column_own_line_max_percent. + * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to + * less than @c last_column_min_percent of the width being available, then only + * @c last_column_own_line_max_percent of the extra line(s) will be used for the + * last column's text. This ensures an indentation. See example below. + * + * @code + * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10) + * --3456789 1234567890 + * 1234567890 + * + * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) + * // last_column_own_line_max_percent=75 + * --3456789 + * 123456789012345 + * 67890 + * + * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) + * // last_column_own_line_max_percent=33 (i.e. max. 5) + * --3456789 + * 12345 + * 67890 + * 12345 + * 67890 + * @endcode + */ +template +void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::OStreamWriter write(prn); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::FunctionWriter write(prn); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::TemporaryWriter write(prn); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::SyscallWriter write(prn, fd); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +template +void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent = + 50, + int last_column_own_line_max_percent = 75) +{ + PrintUsageImplementation::StreamWriter write(prn, stream); + PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); +} + +} +// namespace option + +#endif /* OPTIONPARSER_H_ */ diff --git a/pasn1/parser.i b/pasn1/parser.i new file mode 100644 index 0000000..52fdbfa --- /dev/null +++ b/pasn1/parser.i @@ -0,0 +1,47 @@ + +%module pasn1 +%{ +#include "asn1_parser.h" +%} + +%include +%include + +namespace ans1 { + +/* +%rename(ASN1Parser) parser +%nodefaultctor +*/ +class module ; + + +class parser +{ + public: + typedef std::vector modules_type; + + typedef std::vector::iterator iterator; + + typedef std::list listener_list; + + typedef std::list string_list; + + modules_type &modules() { return m_modules;}; + + static parser *instance(); + + inline string_list &includes(); + + inline string_list &files(); + + inline bool file_mode(); + + inline void set_file_mode(bool fm); + + private: + parser(); +}; + + +} diff --git a/pkix/CMakeLists.txt b/pkix/CMakeLists.txt new file mode 100644 index 0000000..192e828 --- /dev/null +++ b/pkix/CMakeLists.txt @@ -0,0 +1,35 @@ +PROJECT(test-pkix) +# Libraries first + +INCLUDE(${rules_SOURCE_DIR}/flex.cmake) + + + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../../../utils) + +SET(PKIX PKIX1Explicit88) + +ADD_CUSTOM_COMMAND( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/PKIX1Explicit88.cpp + ${CMAKE_CURRENT_BINARY_DIR}/PKIX1Explicit88.h + COMMAND ${asn1p_EXE} + ARGS -I ${asn1-data-models_SOURCE_DIR}/ + -d parser=8 + -d msg=1 + -f rfc3280-PKIX1Explicit88.asn1 + -oPKIX1Explicit88 + DEPENDS ${asn1p_EXE} + COMMENT "Build PKIX1Explicit88.h and .cpp" + ) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${PKIX}.h GENERATED) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/${PKIX}.cpp GENERATED) + +ADD_EXECUTABLE(pkix_test + main_pkix.cpp + ${CMAKE_CURRENT_BINARY_DIR}/${PKIX}.cpp + ) +TARGET_LINK_LIBRARIES(pkix_test asn1) diff --git a/pkix/main_pkix.cpp b/pkix/main_pkix.cpp new file mode 100644 index 0000000..5dfb804 --- /dev/null +++ b/pkix/main_pkix.cpp @@ -0,0 +1,62 @@ +#include +#include +#include "rtasn1/asn1_config.h" +#include "rtasn1/asn1.h" +#include "PKIX1Explicit88.h" +//#include "PKIX1Explicit88.cpp" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" + +using namespace PKIX1Explicit88; + +int main(int argc,char **argv) +{ + asn1::streams::ber ctx; + asn1::prim::types::Integer i(1); + PKIX1Explicit88::Certificate cert,read_cert; + PKIX1Explicit88::Name name(PKIX1Explicit88::Name::typeof_rdnSequence,MAKE_TAG(0,0,16)); + AttributeTypeAndValue issuer_t; + PKIX1Explicit88::TBSCertificate tb; + + issuer_t.type = id_domainComponent(); + PKIX1Explicit88::AttributeTypeAndValue issuer = issuer_t; + RelativeDistinguishedName rdn= issuer; + asn1::PrintableString str(asn1::prim::types::String("Andre EBERSOLD ")); + PDSParameter pd; + pd.printable_string = str; + + OBJECT_IDENTIFIER pk = pkcs_9(); + //name.get_rdnSequence() = rdn; + name.get_rdnSequence().push_back(rdn); + std::cout<<"Hello world"< 1) + { + std::cout<<"Try to read file given as parameter : "< + + 2 + 44:BE:0C:8B:50:00:24:B4:11:D3:36:30:4B:C0:33:77 + + 1.2.840.113549.1.1.5 + 05 00 + + + + + + 2.5.4.6 + 13 02 55 53 + + + + + 2.5.4.8 + 13 02 55 54 + + + + + 2.5.4.7 + 13 0E 53 61 6C 74 20 4C 61 6B 65 20 43 69 74 79 + + + + + 2.5.4.10 + + 13 15 54 68 65 20 55 53 45 52 54 52 55 53 54 20 + 4E 65 74 77 6F 72 6B + + + + + + 2.5.4.11 + + 13 18 68 74 74 70 3A 2F 2F 77 77 77 2E 75 73 65 + 72 74 72 75 73 74 2E 63 6F 6D + + + + + + 2.5.4.3 + + 13 22 55 54 4E 2D 55 53 45 52 46 69 72 73 74 2D + 4E 65 74 77 6F 72 6B 20 41 70 70 6C 69 63 61 74 + 69 6F 6E 73 + + + + + + + + 990709184839Z + + + 190709185749Z + + + + + + + 2.5.4.6 + 13 02 55 53 + + + + + 2.5.4.8 + 13 02 55 54 + + + + + 2.5.4.7 + 13 0E 53 61 6C 74 20 4C 61 6B 65 20 43 69 74 79 + + + + + 2.5.4.10 + + 13 15 54 68 65 20 55 53 45 52 54 52 55 53 54 20 + 4E 65 74 77 6F 72 6B + + + + + + 2.5.4.11 + + 13 18 68 74 74 70 3A 2F 2F 77 77 77 2E 75 73 65 + 72 74 72 75 73 74 2E 63 6F 6D + + + + + + 2.5.4.3 + + 13 22 55 54 4E 2D 55 53 45 52 46 69 72 73 74 2D + 4E 65 74 77 6F 72 6B 20 41 70 70 6C 69 63 61 74 + 69 6F 6E 73 + + + + + + + + 1.2.840.113549.1.1.1 + 05 00 + + + 0011000010000010000000010000101000000010100000100000000100000001 + 0000000010110011111110111001000110100001111001000011011001010101 + 1000010110101100000001100011010001011011101000001001101001011000 + 1011001011111000101101010000111100000101011101111000001110101110 + 0011001010110001011101101001001001101000111011000010001101001010 + 1100100101110110001111111110001110011100101101100011011101111001 + 0000001110111001101010110110100110001101000001110010010110110110 + 0001100101100111111001001011000000011011000110000111001101100001 + 0100101011101000011111101100110111010011001011110110010011100011 + 1010011001111100000011001111101000010111100000001010001100001101 + 0100011110001001010011110101000101110001001011111110111011111100 + 0011111111111001101110000001011010000000100001111000100110010011 + 0010010100100000100110100100001110000010011010010010010001110110 + 0010100001011001001101011010000100011101110000000111111110000011 + 0000011001100100000101100010000000101100110100110100100110100100 + 1000010110110100110000000110000101111111010100010000100011111000 + 0110100000010101100100011000000011001011101001011101010111101110 + 0011101100111010111101001000010000000100010111100110000001011001 + 1010011110001100001101000111001011101110101110000111100011000101 + 1101000100111011000100100100101001101111011111100110010100100111 + 1011100110100100010101011100010110111001011011110100001110100100 + 1100010100011101001011001001100111000000010100101010010001111000 + 0100110000010101101100110100000010011000000010000110101101000011 + 1100011000000001101100000111101001111011111101010110101100011100 + 0010001000111111110010111110111111111111101010001101000000111010 + 0100101101110110000101011001111011010010110100011100011000101110 + 1110001111011011010101110001101100110010101000101011100001101111 + 1110100010000110101001100011111101110000101010111110010101110000 + 1001001010101011010001000001111001000000010100001111101110011100 + 1010001101100010111001000110110001101110101000001100100011011110 + 1110001010000000010000101111101011101001001011111110100011001110 + 0011001000000100100011110111110010001101101101110001110010100011 + 0011010100111100000101011101110110011110110000111010111010010111 + 101001010000001000000011000000010000000000000001 + + + + + 2.5.29.15 + 03 02 01 C6 + + + 2.5.29.19 + + 30 03 01 01 FF + + + 2.5.29.14 + + 04 14 FA 86 C9 DB E0 BA E9 78 F5 4B A8 D6 15 DF + F0 D3 E1 6A 14 3C + + + + 2.5.29.31 + + 30 46 30 44 A0 42 A0 40 86 3E 68 74 74 70 3A 2F + 2F 63 72 6C 2E 75 73 65 72 74 72 75 73 74 2E 63 + 6F 6D 2F 55 54 4E 2D 55 53 45 52 46 69 72 73 74 + 2D 4E 65 74 77 6F 72 6B 41 70 70 6C 69 63 61 74 + 69 6F 6E 73 2E 63 72 6C + + + + + + 1.2.840.113549.1.1.5 + 05 00 + + + 1010010011110011001001011100110011010001110101001001000110000011 + 0010001011010000110011000011001010101011100110111001011001001110 + 0011010010010001010101000010000000100101001101000110000101011111 + 0010101000000010000101011110000110001011101010101111111101111101 + 0110010001010001110011110000101011111111101111000111110111011000 + 0010000101101010011110001100101100101111010100010110111111111000 + 0100001000011101001100111011110111101011101101010111101110010100 + 1100001111000011101010011010000000101101110111111101000100101001 + 0001111100011101111111101000111100111111101110111010100001000101 + 0010101001111111110100010110111001010101001001001110001010111011 + 0000001011111011001100010011111110111110111010001011110011101100 + 0100000000101011111110000000000111010100010101100011100011100100 + 1100101001000100100000101011010101100001001000000010000101100111 + 0110010111110110111100000000101111100111001101001111100010100101 + 1100001010011100101000110101110001000000000111111000010110010011 + 1001010100000110110111100100111111010100001001111010100110110110 + 1010010111111100000101101100110101110011001100010011111110111000 + 0110010100100111110011111101010001010011000110101111000010101100 + 0110111010011111010011110000010100001100000000111000000110100111 + 1000010000101001110001000101101010111101011001000101011101110010 + 1010110100111011110011110011011100011000101001101001100011000110 + 1010110100000110101101001101110000001000101000110000010011010101 + 0010100110100100100101101001101000010010011001110100101010001100 + 0110000001000101100111011111000100100011100110101011000000000000 + 1001110001101000101101011001100001010000110100111110111110001110 + 0010111010010010011001011011000101001000001111100010000110111110 + 0001010100110000001010100000110110110101000011001010001101101011 + 0011111110101110011111110101011111110101000111111001011001111100 + 1101111101101111110111011000001000110000001011000110010100011011 + 0100000001001010110011010110100010111001011100101110110001110001 + 0111011011101100010101001000111000011111100001010000110000000001 + 0110101011111010101001100011100010101100000111111100010010000100 + + diff --git a/pkix/sample-Certificate-1.der b/pkix/sample-Certificate-1.der new file mode 100644 index 0000000000000000000000000000000000000000..e82877d1b464fe79a0c3b3aca04ba7058e8b487c GIT binary patch literal 1128 zcmXqLVo5P*V)j|U%*4pVB;c}-r#pZ_WsBftGXw7f#^naQY@Awc9&O)w85vnw84Ma1 z8*&?PvN4CUun9AT2E#ZUKu(CExPd50hFzF1I5DS0!6z|0Rlzy4q|#8%Kn5hiB`g|} zk*W|H>>3mj6dD|&;Fnrbo?n!0sAwP$lIIqd$S5f(u+rBrFE7_CElw>eDJm^4(M!(H zHPklH1Sw$_RtgRA(*+sfmRVF>q6;-b!LgtqCo?&*Br`v+*g#I4*V59!+`!V%!o!&Sj4ykRk~d#8V3q5iu+_CI%sHMDn5R#lkg+?1(OrV(knQ1(E5Gh2$7g3e{nC9PWy zB-RIV{KycU*l>F3)pyobUs_n=5+axPm=wL+QE~L5wUAeSU8?%dC80-m<~uJrDyuW| zK+uv3AJNSYGdQxHk1=kjs{WcSqhx>j{r?pgth~!a=UuvZOz-jSaA~7OJMv$&Ewe9J z{j^}xY8N?&fZuZ#Cq2o@TX5puqXws6FZExXGh*ql>D?}~*wjY!?!3e6rY~h;W@KPo z+&IyovCn`Tm^ftlSy+In_?Q7dh$GC%_@9N`$btm;Sj1RFezl#v{b1M2im%=) zu8H3NaQR`Dh>d|iNLrr7!@$kJWr5QIhc-KCGE6SYK~0AGSQ8&|+S3E-L5?+GrUAwp zBg2xj&ol zaFR9N`+95jl*5NtF3`PyQBz*_U%&nC6|P$K7xO|@9_?oOZD_ym#hy0~+CLbtgjqZ} z<I5a{#VpjZd>|C>};{2{f<=i^H+kUKCH=` z@6XD^+_=0&^GMX*l<=ap*5}P7md!Y}mTk)&j>RljHJ41AC6w;fli)h{qw=f`40AHJ z&Iq{tzE5vb>P8Pc#eJd%TD)6%7H8Y9s}KJwKdt6|{@o@6om6QDud^9Di{2ELy$R`) QZ{=ak`nAkrjr@@o04N=tZU6uP literal 0 HcmV?d00001 diff --git a/rtasn1/CMakeLists.txt b/rtasn1/CMakeLists.txt new file mode 100644 index 0000000..340d926 --- /dev/null +++ b/rtasn1/CMakeLists.txt @@ -0,0 +1,71 @@ +PROJECT(libasn1) +SUBDIRS(cpp) + +CONFIGURE_FILE(asn1_config.h.in asn1_config.h) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/asn1_config.h GENERATED) + +ADD_LIBRARY(asn1 + asn1_context.cpp + asn1_codec_ber.cpp + asn1_codec_jer.cpp + asn1_codec_oer.cpp + asn1_codec_per.cpp + prim_types.cpp + asn1_types.cpp + cpp/prim_oid.cpp + cjson/cJSON.c + ) +# +# Install stuff +# +IF(APPLE) + INSTALL(TARGETS asn1 + COMPONENT RuntimeLibraries + LIBRARY DESTINATION Smartasn1.app/Contents/lib/ + ARCHIVE DESTINATION Smartasn1.app/Contents/lib/ + ) + INSTALL(FILES + asn1.h + ${CMAKE_CURRENT_BINARY_DIR}/asn1_config.h + asn1_types.h + asn1_context.h + asn1_errors.h + asn1_codec.h + asn1_tag.h + prim_types.h + asn1_types.inc + asn1_rose.h + asn1_types.hpp + asn1_codec_ber.h + asn1_codec_jer.h + asn1_codec_oer.h + asn1_codec_per.h + asn1_debug.h + COMPONENT Asn1Headers + DESTINATION Smartasn1.app/Contents/include/asn1/) +ELSE(APPLE) + INSTALL(TARGETS asn1 + COMPONENT RuntimeLibraries + LIBRARY DESTINATION lib/ + ARCHIVE DESTINATION lib/ + ) + INSTALL(FILES + asn1.h + asn1_types.h + asn1_types.inc + asn1_context.h + asn1_errors.h + asn1_codec.h + asn1_tag.h + prim_types.h + asn1_rose.h + asn1_types.hpp + asn1_codec_ber.h + asn1_codec_jer.h + asn1_codec_oer.h + asn1_codec_per.h + asn1_debug.h + COMPONENT Asn1Headers + DESTINATION include/asn1/) + +ENDIF(APPLE) diff --git a/rtasn1/asn1.h b/rtasn1/asn1.h new file mode 100644 index 0000000..a582a3c --- /dev/null +++ b/rtasn1/asn1.h @@ -0,0 +1,86 @@ +#ifndef ASN1_H__ +#define ASN1_H__ + +#include "rtasn1/asn1_config.h" +#include "rtasn1/asn1_debug.h" +#include "rtasn1/asn1_errors.h" +#include "rtasn1/asn1_tag.h" +#include "rtasn1/prim_types.h" +namespace asn1 { class context; }; +namespace asn1 { namespace streams { class ber;} }; +#include "rtasn1/asn1_types.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_context.h" +#include "rtasn1/asn1_rose.h" +#include "rtasn1/asn1_types.hpp" +#include +#if defined(__GNUC__) ||defined(_WIN32) +#include +#endif + +#if defined (ASN1_ATTRIBUTE_OPTIONAL_AS_SHARED_POINTER) +// ASN1_OPTIONAL_AS_SHARED_POINTER +# define ASN1_ATTRIBUTE_OPTIONAL(x) asn1::intrusive_ptr + +# define ASN1_ATTRIBUTE_OPTIONAL_ENCODE(x) do { \ + if( !(x.is_nul() ) ) { \ + (x)->encode(ctx); \ + } \ + } while (0) + +# define ASN1_ATTRIBUTE_OPTIONAL_DECODE(x) do { \ + if( ! x.is_nul() ) { \ + x->decode(ctx); \ + } else { \ + x.create(); \ + if (x->decode(ctx) != asn1::ok) { \ + x.release(); \ + }\ + } \ + } while(0) + +# define ASN1_ATTRIBUTE_OPTIONAL_DECODE_IMPLICIT(x,tg) do { \ + if( ! c.x.is_nul() ) { \ + c.x->set_tag(tg); \ + if (c.x->decode(ctx) != asn1::ok) { \ + c.x.release(); \ + }\ + } else { \ + c.x.create(tg); \ + if (c.x->decode(ctx) != asn1::ok) { \ + c.x.release(); \ + }\ + } \ + } while(0) + + +#elif defined (ASN1_ATTRIBUTE_OPTIONA_AS_POINTER) +// ASN1_OPTIONAL_AS_POINTER +# define ASN1_ATTRIBUTE_OPTIONAL(x) x * +# define ASN1_ATTRIBUTE_OPTIONAL_ENCODE(x) x +# define ASN1_ATTRIBUTE_OPTIONAL_DECODE(x) x +#else +// ASN1_OPTIONAL_AS_NOT_SUPPORTED +# define ASN1_ATTRIBUTE_OPTIONAL(x) x +# define ASN1_ATTRIBUTE_OPTIONAL_ENCODE(x) { \ + x.encode(ctx); \ + } +# define ASN1_ATTRIBUTE_OPTIONAL_DECODE(x) do { \ + x.decode(ctx); \ + } while(0) + +# define ASN1_ATTRIBUTE_OPTIONAL_DECODE_IMPLICIT(x,tg) do { \ + x.set_tag(tg);\ + x.decode(ctx); \ + } while(0) +#endif + +namespace asn1 { +namespace types { +} +} + +/* +vim:et:sw=2:ts=2: + */ +#endif diff --git a/rtasn1/asn1_codec.h b/rtasn1/asn1_codec.h new file mode 100644 index 0000000..70e867c --- /dev/null +++ b/rtasn1/asn1_codec.h @@ -0,0 +1,40 @@ +#ifndef ASN1_CODEC_H__ +#define ASN1_CODEC_H__ +#include +#include "rtasn1/asn1.h" +namespace asn1 { + namespace types { + extern int debug_level; + } + namespace codecs { + class ber; + } +}; + +// +namespace asn1 +{ + + +class context_base; + +/** + * + * @brief Base class to Implement encode and docode + * functions related to ASN1 types. + * + * put in this class methods that are common to all + * type of encoders / decoders BER,JER,OER,PER,XER + * Eventual parameters, allocator + */ + class codec + { + public: + codec( ) {}; + }; + +}; +#endif +/* + * vim: et sw=2 ts=2 list: + */ diff --git a/rtasn1/asn1_codec_ber.cpp b/rtasn1/asn1_codec_ber.cpp new file mode 100644 index 0000000..63c10f3 --- /dev/null +++ b/rtasn1/asn1_codec_ber.cpp @@ -0,0 +1,1126 @@ +#include +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_context.h" +#include "rtasn1/asn1_codec_ber.h" + +/* +vim:et:sw=2:ts=2 + */ +namespace asn1 { + + +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + template <> \ + void codecBER::encode(streams::ber &ctx, const asn1::Asn1Type &t) \ + { \ + encode_ber(ctx,t); \ + } \ + template <> \ + int \ + codecBER::decode(streams::ber &ctx, asn1::Asn1Type &t) \ + { \ + return decode_ber(ctx,t); \ + } + +ASN1_TYPE_CLS(asn1::prim::types::ObjectIdentifier,asn1::types::UNIVERSAL,6,ObjectIdentifier) + +#include "rtasn1/asn1_types.inc" + +# if 0 + std::cerr<<"codecBER::"<<__FUNCTION__<<" good "; \ + std::cerr<<#Asn1Type< 31 ) + { + //required = (types::count_bits(tgv) + 6 ) / 7 ; + // Compute required size for id > 31 + for ( required = 1, i = 7 ; i < sizeof(long) * 8 ; i+=7) + { + if (t.get_id() >> i ) + { + required++; + } else + break; + } + // Encode id ... + unsigned char * end = b + required ; + for ( i-= 7, ++pos; &b[pos] < end; i-=7 , pos++) + { + b[pos] = 0x80 | (( tgv >> i) & 0x7F); + } + b[pos] = (( tgv >> i) & 0x7F); + required++; + } + + // Get Length of underlying data objects length, and encode length. + size_t data_len = obj.get_data_length(); + ASN1_BER_LOG_DEBUG("codecBER::encode_header data_length = %ld len=%ld",data_len,len); + if (data_len < 128) + { // Don't know how to do this for now + b[++pos] = data_len; + ctx.nb_bits(8 + ((required)<<3)); + } else + { + int count = (types::count_bits(data_len +1)+7)/8; + b[++pos] = count | 0x80; + while (count-- > 0) + { + b[++pos] = (len >> (count+8)); + } + } +} +// +void +codecBER::encode_tag(streams::ber &ctx,const asn1::tag &t,const size_t data_len) +{ + unsigned long pos = ctx.bytes(); + unsigned char *b = ctx.buffer(); + size_t i = 0; + long required = 1; + + ASN1_BER_LOG_DEBUG("ber::encode_tag code tag: cls=%d id=%d ",t.get_class(),t.get_id()); + // Encode Tag, check the tag value .... + b[pos] = ((t.get_class() & 0x03)<<6 )| ( (t.get_id() < 31) ? t.get_id() : 0x1F); + if ( t.get_constructed() ) + b[pos] |= 0x20; + long tgv = t.get_id(); + + if ( t.get_id() > 31 ) + { + //required = (types::count_bits(tgv) + 6 ) / 7 ; + // Compute required size for id > 31 + for ( required = 1, i = 7 ; i < sizeof(long) * 8 ; i+=7) + { + if (t.get_id() >> i ) + { + required++; + } else + break; + } + // Encode id ... + unsigned char * end = b + required ; + for ( i-= 7, ++pos; &b[pos] < end; i-=7 , pos++) + { + b[pos] = 0x80 | (( tgv >> i) & 0x7F); + } + b[pos] = (( tgv >> i) & 0x7F); + required++; + } + + // Get Length of underlying data objects length, and encode length. + ASN1_BER_LOG_DEBUG("ber::encode_header data_length = %ld ",data_len); + if (data_len < 128) + { // Don't know how to do this for now + b[++pos] = data_len; + ctx.nb_bits(8 + ((required)<<3)); + } else + { + int count = (types::count_bits(data_len +1)+7)/8; + b[++pos] = count | 0x80; + while (count-- > 0) + { + b[++pos] = (data_len >> (count+8)); + } + } +} + + + + +namespace streams { + + + +ber::ber(int sz) : asn1::context(sz) +{ + ASN1_BER_LOG_DEBUG("ber::ber %d ",sz); +} + +ber::ber(const ber &_codec) : asn1::context() +{ + ASN1_BER_LOG_DEBUG("ber::ber(const ber &_codec ) "); +} + +long ber::decode_length(unsigned char *buf, long *readed) +{ + long result = 0; + long nb_octet = *buf & 0x7f; + + *readed = 1; + if ((*buf & 0x80) && (*buf & 0x7F)) { + // Long form number ... + *readed = (*buf & 0x7F) + 1; + buf++; + while (nb_octet-- ) { + result = (result<<8) | (*buf); + buf++; + } + ASN1_BER_LOG_DEBUG("asn1::codec::ber::length long form value=%ld readed=%ld",result,*readed); + return result; + } else if (!(*buf & 0x80) && (*buf & 0x7F)){ + result = *buf & 0x7F; + // Short one byte + *readed = 1; + ASN1_BER_LOG_DEBUG("ans1::codec::ber::length short form result=%ld ",result); + return result; + } else if (*buf == 0) { + *readed = 1; + ASN1_BER_LOG_DEBUG("ber::length: 0 "); + return 0; + }else { + // Indefinit form + std::cout<<"ber::length indefinit form not yet supported TO BE CODED"<(&b)) + { + integer = i->get_sys_value(); + } else if (const UInt64 *i = dynamic_cast< const UInt64 *>(&b)) + { + integer = i->get_sys_value(); + } else if (const ENUMERATED *i = dynamic_cast< const ENUMERATED *>(&b)) + { + integer = i->get_sys_value(); + } + int intsize = 4; + long mask = 0x1FF <<23; // Shift 8 *3 - 1 ? 0xFF800000 + + while ( ( ((integer & mask) == 0) || ((integer & mask) == mask)) + && intsize > 1) { + intsize--; + integer <<=8; + } + ASN1_BER_LOG_DEBUG("ber::encode integer tag.byte()=%d value=%lld intsize=%d decale =%d" + ,b.tag().byte() + ,(long long)integer + ,(int)intsize + ,(intsize<<3)); + + encode_header(b,intsize); + + unsigned long pos = bytes(); + unsigned char *bu = buffer(); + + nb_bits(intsize<<3); + + + if ((integer & 0x7F000000)) { + + } + while ( (intsize--) > 0) + { + bu[pos++] = ( (integer & 0xFF000000)>>24 ); + integer<<=8; + } +} + +/** + * Decode Integer + */ +int ber::decode_integer(asn1::INTEGER &t) +{ + int len = 0; + int result = 0; + + ASN1_BER_LOG_DEBUG("ber::decode integer tag=%d",t.tag().byte()); + + if ( ! decode_header(t.tag(),len) || ( len == 0 )) + { + ASN1_BER_LOG_DEBUG("ber::decode_integer WRONG TAG expected=%d",t.tag().byte()); + return asn1::wrong_tag; + } + unsigned long pos = bytes(); + unsigned char *bu = buffer(); + nb_bits(len<<3); + // I don't know yet how to handle this case + if (len> 16 ) + { + ASN1_BER_LOG_ERROR("ber::decode_integer too long len = %d",len); + return asn1::wrong_length; + } + + ASN1_BER_LOG_DEBUG("ber::decode_integer start result=%d check_tag=%d len =%d",(int)result,check_tag(),len); + result = (char) bu[pos]; /* Keep sign */ + while (--len) + { + result = (result<<8) | ((unsigned char)bu[++pos] & 0xFF); + } + ASN1_BER_LOG_DEBUG("ber::decode_integer end result=%d",(int)result); + t.get_value() = result; + return asn1::ok; +} + +int ber::decode_integer(asn1::UInt64 &t) +{ + int len = 0; + if (! decode_header(t.tag(),len) || (len == 0) ) + return asn1::wrong_tag; + unsigned long acc = decode_byte(); /* No signess */ + while (--len > 0) + { + acc = (acc<< 8) | decode_byte(); + } + t = acc; + return asn1::ok; +} + + +// Bit String +// +void ber::encode_bitstring(const asn1::BIT_STRING &t) +{ + int len = t.size() + 1; + ASN1_BER_LOG_DEBUG("ber::encode bit string len=%d blen=%lu" + ,len + ,t.get_nb_bits() + ); + encode_header(t,len); + unsigned long pos = bytes(); + unsigned char *bu = buffer(); + + if (t.size() > 0) + { + unsigned char last = t[t.size()-1]; + unsigned char padding = 0; + unsigned char mask = 1; + + padding = t.get_nb_bits() % 8; + + if (padding ) + { + padding = 8 - padding; + } else + { // Cannot be 0 there is a problem here + while (last) + { + padding++; last>>=1; + mask<<=1; mask |=1; + } + padding = 8 - padding; + } + bu[pos++] = padding; + len = t.size() - 1; + + nb_bits(((1+ t.size()) <<3)); + while (len > 0) + { + bu[pos++] = t[len]<>(8-padding); + len--; + } + bu[pos] = t[0]<(b); + const asn1::prim::types::String &s = b.get_prim(); + len = s.get_value().size(); // Length + + encode_header(b,len); + + unsigned long pos = bytes(); + unsigned char *buf = buffer(); + + for ( int i = 0; i< len ; i++) + buf[pos++] = s.get_value().c_str()[i]; + nb_bits(len*8); +} + + +int ber::decode_string(asn1::types::strtype &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("ber::decode string tag_id=%d",b.tag().get_id()); + //asn1::prim::types::String &s = dynamic_cast(b); + asn1::prim::types::String &s = b.get_prim(); + + if (decode_header(b.type::tag(),len)) + { + unsigned long pos = bytes(); + unsigned char *bu = buffer(); + std::string result; + result.assign((const char *)&bu[pos],len); + s = asn1::prim::types::String(result); + nb_bits((len<<3)); + } else { + return asn1::wrong_tag; + } + return asn1::ok; +} + +// Any +// +void ber::encode_any(const asn1::types::any_type &b) +{ + ASN1_BER_LOG_DEBUG("ber::encode_any "); +} + +int ber::decode_any(asn1::types::any_type &b) +{ + asn1::tag t(0,0); + int len = 0; + ASN1_BER_LOG_DEBUG("ber::decode_any "); + if (decode_tag(t,len)) + { + nb_bits((len<<3)); + } + std::cerr<<"ber::decode_any len="<(b).encode_preamble_ber(*this); + encode_header(b,len); +} +void ber::encode_sequence_epilogue(const asn1::types::sequence_type &b) +{ + ASN1_BER_LOG_DEBUG("ber::encode_sequence_epilogue tag=%d const ",b.tag().byte()); + //b.encode_epilogue_ber(*this); +} + + + +int ber::decode_sequence_preamble(asn1::types::sequence_type &b) +{ + int len; + std::string n = typeid(b).name(); + ASN1_BER_LOG_DEBUG("ber::decode sequence preamble %s",n.c_str()); + if (decode_header(b.tag(),len)) + { + return b.decode_preamble_ber(*this); + } else + { + return asn1::unknown; + } +} + +int ber::decode_sequence_epilogue(asn1::types::sequence_type &b) +{ + return b.decode_epilogue_ber(*this); +} + + +// +void ber::encode_header(const asn1::types::type &obj, int &len) +{ + asn1::tag t = obj.tag(); + unsigned long pos = bytes(); + unsigned char *b = buffer(); + size_t i = 0; + long required = 1; + + ASN1_BER_LOG_DEBUG("ber::encode_header code tag: cls=%d id=%d ",t.get_class(),t.get_id()); + // Encode Tag, check the tag value .... + b[pos] = ((t.get_class() & 0x03)<<6 )| ( (t.get_id() < 31) ? t.get_id() : 0x1F); + if ( ! obj.primitive() ) + b[pos] |= 0x20; + long tgv = t.get_id(); + + if ( t.get_id() > 31 ) + { + //required = (types::count_bits(tgv) + 6 ) / 7 ; + // Compute required size for id > 31 + for ( required = 1, i = 7 ; i < sizeof(long) * 8 ; i+=7) + { + if (t.get_id() >> i ) + { + required++; + } else + break; + } + // Encode id ... + unsigned char * end = b + required ; + for ( i-= 7, ++pos; &b[pos] < end; i-=7 , pos++) + { + b[pos] = 0x80 | (( tgv >> i) & 0x7F); + } + b[pos] = (( tgv >> i) & 0x7F); + required++; + } + + // Get Length of underlying data objects length, and encode length. + size_t data_len = obj.get_data_length(); + ASN1_BER_LOG_DEBUG("ber::encode_header data_length = %ld len=%d",data_len,len); + if (data_len < 128) + { // Don't know how to do this for now + b[++pos] = data_len; + nb_bits(8 + ((required)<<3)); + } else + { + int count = (types::count_bits(data_len +1)+7)/8; + b[++pos] = count | 0x80; + while (count-- > 0) + { + b[++pos] = (len >> (count+8)); + } + } +} +// +void ber::encode_tag(const asn1::tag &t,const int &len) +{ + unsigned long pos = bytes(); + unsigned char *b = buffer(); + size_t i = 0; + long required = 1; + + ASN1_BER_LOG_DEBUG("ber::encode_tag code tag: cls=%d id=%d ",t.get_class(),t.get_id()); + // Encode Tag, check the tag value .... + b[pos] = ((t.get_class() & 0x03)<<6 )| ( (t.get_id() < 31) ? t.get_id() : 0x1F); + if ( t.get_constructed() ) + b[pos] |= 0x20; + long tgv = t.get_id(); + + if ( t.get_id() > 31 ) + { + //required = (types::count_bits(tgv) + 6 ) / 7 ; + // Compute required size for id > 31 + for ( required = 1, i = 7 ; i < sizeof(long) * 8 ; i+=7) + { + if (t.get_id() >> i ) + { + required++; + } else + break; + } + // Encode id ... + unsigned char * end = b + required ; + for ( i-= 7, ++pos; &b[pos] < end; i-=7 , pos++) + { + b[pos] = 0x80 | (( tgv >> i) & 0x7F); + } + b[pos] = (( tgv >> i) & 0x7F); + required++; + } + + // Get Length of underlying data objects length, and encode length. + size_t data_len = len; + ASN1_BER_LOG_DEBUG("ber::encode_header data_length = %ld len=%d",data_len,len); + if (data_len < 128) + { // Don't know how to do this for now + b[++pos] = data_len; + nb_bits(8 + ((required)<<3)); + } else + { + int count = (types::count_bits(data_len +1)+7)/8; + b[++pos] = count | 0x80; + while (count-- > 0) + { + b[++pos] = (len >> (count+8)); + } + } +} + + +/** + * + */ +int ber::decode_tag(asn1::tag &t) +{ + int len; + return decode_header(t,len); +} +/** + * @brief Decodes tag and length without any check + */ +bool ber::decode_tag(asn1::tag &tag,int &len) +{ + long nb = 0; + long nbt = 1; + long tval = 0; + + unsigned long pos = bytes(); + unsigned char *b = buffer(); + ASN1_BER_LOG_DEBUG("ber::decode_tag tag : cls=%d id=%d pos=%ld have tag in stream=%d" + , tag.get_class() + , tag.get_id() + , pos + , b[pos]); + int tcls = (b[pos] >> 6); + tval = b[pos]; + tag.byte(tval); + if ((tval &= 0x1F) != 0x1F) + { + len = decode_length(&b[pos+1],&nb); + nb_bits( (nb + 1)<<3); + ASN1_BER_LOG_DEBUG("ber::decode_tag sf tag : cls=%d id=%d tval=%ld nbt=%ld pos=%lu" + , tag.get_class() + , tag.get_id() + , tval,nbt,pos); + return true; + } + // Long Form... be sure not to read too far.... + for (pos++, tval = 0; /* Stop Before end of buffer*/ nbt < 3 + ;pos++ , nbt++) + { + if ( b[pos] & 0x80 ) + { + tval = tval<<7 | (b[pos] & 0x7F); + } else + { // Last 7 bits + tval = tval<<7 | b[pos] ; + break; + } + } + ASN1_BER_LOG_DEBUG("ber::decode_tag lf tag : cls=%d id=%d tval=%ld nbt=%ld pos=%lu" + , tag.get_class() + , tag.get_id() + , tval,nbt,pos); + len = decode_length(&b[pos+1],&nb); + tag.byte(tval); + nb_bits( (nb + nbt + 1)<<3); + return true; +} + +/** + * @brief Decode header + * @param tag + * @len TODO should be of type size_t len cannot be negatif + * @return return true if tag matches decoded tag false otherwise + * Buffer position changed to data position if function returns true. + */ +bool ber::decode_header(const asn1::tag &tag,int &len,bool check) +{ + long nb = 0; + long nbt = 1; + long tval = 0; + unsigned long pos = bytes(); + unsigned char *b = buffer(); + ASN1_BER_LOG_DEBUG("ber::decode_header tag : cls=%d id=%d pos=%ld expected=%d stream has=%d " + , tag.get_class() + , tag.get_id() + , pos + , tag.byte(),b[pos]); + int tcls = (b[pos] >> 6); + tval = b[pos]; + if ((tval &= 0x1F) != 0x1F) + { + // Short From + if ( b[pos] != tag.byte() ) + return false; + + len = decode_length(&b[pos+1],&nb); + + nb_bits( (nb + 1)<<3); + return true; + } + // Long Form... be sure not to read too far.... + for (pos++, tval = 0; /* Stop Before end of buffer*/ nbt < 3 + ;pos++ , nbt++) + { + if ( b[pos] & 0x80 ) + { + tval = tval<<7 | (b[pos] & 0x7F); + } else + { // Last 7 bits + tval = tval<<7 | b[pos] ; + break; + } + } + ASN1_BER_LOG_DEBUG("ber::decode_header lf tag : cls=%d id=%d tval=%ld nbt=%ld pos=%lu" + , tag.get_class() + , tag.get_id() + , tval,nbt,pos); + if (tag.get_id() != tval) + return false; + len = decode_length(&b[pos+1],&nb); + nb_bits( (nb + nbt + 1)<<3); + return true; +} + + + + + +/** + :vim et sw=2 ts=2: + */ +} +} diff --git a/rtasn1/asn1_codec_ber.h b/rtasn1/asn1_codec_ber.h new file mode 100644 index 0000000..7891adc --- /dev/null +++ b/rtasn1/asn1_codec_ber.h @@ -0,0 +1,239 @@ +#ifndef CODEC_BER_H +#define CODEC_BER_H +#include +#if 0 +#if defined(__GNUC__) && defined(DEBUG) & not(defined(ASN1_BER_LOG_DEBUG)) +#define ASN1_BER_LOG_DEBUG(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (asn1.y : %d)\n",__LINE__);\ +} while (0) +#elseif not(defined(ASN1_BER_LOG_DEBUG)) + static inline void ASN1_BER_LOG_DEBUG(const char *fmt,...) {(void)fmt;}; +#endif + +#else +#include "rtasn1/asn1_debug.h" +#endif +namespace asn1 { +class context; +class codecBER; +namespace streams { +//#define DEBUG +/** + * + */ + +class ber : public asn1::context +{ + public: + ber( int sz = 512) ; + ber(unsigned char *b,size_t size) + : asn1::context(b,size) {}; + ber(const ber &c) ; + ~ber() {} + + virtual int decode_tag(asn1::tag &t) ; + + // Null + // 5 + virtual void encode_null(const asn1::Null &b) ; + virtual int decode_null(asn1::Null &b) ; + + // Bool + // + virtual void encode_boolean(const asn1::BOOLEAN &b) ; + virtual int decode_boolean(asn1::BOOLEAN &b) ; + + // Integer + // + virtual void encode_integer(const asn1::types::type &b) ; + virtual int decode_integer(asn1::INTEGER &b) ; + int decode_integer(asn1::UInt64 &b) ; + + // Bit String + // + virtual void encode_bitstring(const asn1::BIT_STRING &b) ; + virtual int decode_bitstring(asn1::BIT_STRING &b) ; + + // Octet string + // + virtual void encode_octetstring(const asn1::OCTET_STRING &b) ; + virtual int decode_octetstring(asn1::OCTET_STRING &b) ; + + virtual void encode_string(const asn1::types::strtype &b) ; + virtual int decode_string(asn1::types::strtype &b) ; + // Choice + // + virtual void encode_choice(asn1::types::choice_type &b) ; + virtual int decode_choice(asn1::types::choice_type &b) ; + + // Sequence + virtual void encode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual void encode_sequence_epilogue(asn1::types::sequence_type &b) ; + void encode_sequence_preamble(const asn1::types::sequence_type &b) ; + void encode_sequence_epilogue(const asn1::types::sequence_type &b) ; + virtual int decode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual int decode_sequence_epilogue(asn1::types::sequence_type &b) ; + + // Any + // + virtual void encode_any(const asn1::types::any_type &b); + virtual int decode_any(asn1::types::any_type &b); + /** + * When reading ber, we need to be able to decode the length + */ + long decode_length(unsigned char *buf, long *readed); + /** + * decode tag without cheking value + */ + bool decode_tag( asn1::tag &t, int &len); + + bool decode_header(const asn1::tag &tag,int &len,bool check_tag=true); + + friend class asn1::codecBER; + protected: + /* deprecated */ + void encode_header(const asn1::types::type &obj, int &len); + /* deprecated */ + void encode_tag(const asn1::tag &obj,const int &len); + /* encode simple byte */ + void encode_byte(unsigned char c); + + unsigned char decode_byte(); + +}; + +// End namesape codecs +} + +/** + * @brief This class is responsible for all BER encoding + * and decoding. + * + */ + class codecBER : public codec + { + protected: + codecBER(const codecBER &c) {}; + public: + codecBER() {} + + template + void encode(streams::ber &ctx,const T &t) ; + + /* New encoding .... deprecates the one in streams::ber*/ + void encode_header(streams::ber &ctx, const asn1::types::type &obj, const size_t len); + /* New encoding that deprecates the one in ber class */ + void encode_tag(streams::ber &ctx,const asn1::tag &obj,const size_t len); +#if 0 + /* Will this work ? I don't think it will. Need to think about it + * a bit more + */ + size_t get_length(const asn1::types::type &obj) const; + + template + size_t get_data_length(const T &t) const + { return 0; }; +#endif + template + int decode(streams::ber &ctx, T &t) ; + /* Special case for Sequence OF */ + template + void encode(streams::ber &ctx,const asn1::Seq &t) + { + typename asn1::Seq::const_iterator mit = t.begin(); + int dlen = t.get_data_length(); + ctx.encode_header(t.tag(),dlen); + for (; mit != t.end() ; ++mit) + { + if (mit != t.begin()) + encode(ctx,(*mit)); + } + } + template + int decode(streams::ber &ctx,asn1::Seq &t) + { + T element; + int ret; + int len = 0; + std::cout<<"TODO decode Seq"< size ="< + void encode(streams::ber &ctx,const asn1::intrusive_ptr &t) + { + int len; + /* If it's a choice, several options are available ! do I create + * the object to check if it works or not ? + */ + std::cout<<"codecBER::encode optional ! how do I do this ?"< + int decode(streams::ber &ctx,asn1::intrusive_ptr &t) + { + int len; + /* If it's a choice, several options are available ! do I create + * the object to check if it works or not ? + */ + std::cout<<"codecBER::decode optional ! how do I do this ?"< \ + void codecBER::encode(streams::ber &ctx, const asn1::Asn1Type &t) \ + ; \ + template <> \ + int \ + codecBER::decode(streams::ber &ctx, asn1::Asn1Type &t) \ + ; +#include "rtasn1/asn1_types.inc" + + +// End namespace ans1 +} + +#endif diff --git a/rtasn1/asn1_codec_jer.cpp b/rtasn1/asn1_codec_jer.cpp new file mode 100644 index 0000000..28b35ef --- /dev/null +++ b/rtasn1/asn1_codec_jer.cpp @@ -0,0 +1,1259 @@ +#include +#include +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_context.h" +#include "rtasn1/cjson/cJSON.h" + +#include "rtasn1/asn1_codec_jer.h" + + +/* a lookup table which lets us quickly determine three things: + * VEC - valid escaped control char + * note. the solidus '/' may be escaped or not. + * IJC - invalid json char + * VHC - valid hex char + * NFP - needs further processing (from a string scanning perspective) + * NUC - needs utf8 checking when enabled (from a string scanning perspective) + */ +#define VEC 0x01 +#define IJC 0x02 +#define VHC 0x04 +#define NFP 0x08 +#define NUC 0x10 + +static const char charLookupTable[256] = +{ + /*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , + /*08*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , + /*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , + /*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , + + /*20*/ 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , 0 , 0 , + /*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC , + /*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC , + /*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 , + + /*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 , + /*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + /*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + /*58*/ 0 , 0 , 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , + + /*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 , + /*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 , + /*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 , + /*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC +}; + + + +/* +vim:et:sw=2:ts=2 + */ +namespace asn1 { + +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + template <> \ + void codecJER::encode(streams::jer &ctx, const asn1::Asn1Type &t) \ + { \ + encode_jer(ctx,t); \ + } \ + template <> \ + int \ + codecJER::decode(streams::jer &ctx, asn1::Asn1Type &t) \ + { \ + return decode_jer(ctx,t); \ + } +#if 0 +/* comments for debuging purpose. */ + std::cerr<<"codecJER::"<<__FUNCTION__<<" good "; \ + std::cerr<<#Asn1Type< +void codecJER::encode(streams::jer &ctx, const asn1::ObjectIdentifier &t) +{ + std::cerr<<"codecJER::"<<__FUNCTION__<<" good "; + std::cerr<<"asn1::ObjectIdentifier "< +int +codecJER::decode(streams::jer &ctx, asn1::ObjectIdentifier &t) +{ + std::cerr<<"codecJER::"<<__FUNCTION__<<" good "; + std::cerr<<"asn1::ObjectIdentifier"< (m_size - m_bufOff)) + { + std::cerr<<"jer::put_string Failed\n"<(&b)) + { + integer = i->get_value(); + } else if (const asn1::prim::types::UInt64 *i = dynamic_cast< const asn1::prim::types::UInt64 *>(&b)) + { + integer = i->get_value(); + } + + char *ptr = (char *)buffer(); ptr+=m_bufOff; + tmp = integer; + + if (tmp == 0) + count++; + + while ((unsigned long)tmp > 0 ) + { + tmp = tmp/base; count++; + } + + if (m_bufOff + count > get_size()) + { + std::cout<<"Issue with jer::encode_integer buffer overflow"<= 10 && (res < 16 )) + { + * --ptr = 'A' - 10 + (char)res; + } + } while ((integer = t ) != 0); + m_bufOff += count; + ASN1_BER_LOG_DEBUG("jer::encode integer tag=%d value=%ld " + , b.tag().byte() + ,(long)integer + ); +} + +/** + * Decode Integer + */ +int jer::decode_integer(asn1::INTEGER &t) +{ + size_t len = 0; + unsigned char *buf = NULL; + int result = 0; + ASN1_BER_LOG_DEBUG("jer::decode integer tag=%d",t.tag().byte()); + switch( json_lex(m_bufOff,&buf,len)) + { + case jer_tok_integer: + { + std::string b((char *)buf,len); + t = atol(b.c_str()); + } + break; + default: + std::cout<<"jer::decode_integer error"<>4 ) & 0x0F]; + *buf++ = gAlpha[( *ptr++ ) & 0x0F]; + } while (--len); + put_char("\"",1); +} + +int jer::decode_octetstring(asn1::OCTET_STRING &b_) +{ + int len = 0; + std::string field; + ASN1_BER_LOG_DEBUG("jer::decode octet string TODO "); + if (! get_token(field)) + { + ASN1_BER_LOG_ERROR("jer::decode octerstring tag_id=%d no field",b_.tag().get_id()); + return asn1::wrong_type; + } + std::string &result = b_.get_value().get_value(); + result.resize(0,'\0'); + for (std::string::iterator it = field.begin() ; it!= field.end() + ; ++it) + { + char c1 = *it; ++it; + char c2 = *it; + char r = ((c1 - '0')<<4 & 0xF0 ) | ((c2 - '0') & 0x0F ); + result.push_back(r); + + } + return asn1::ok; +} + +void jer::encode_string(const asn1::types::type &b) +{ + int len = 0; + const asn1::prim::types::String &s = dynamic_cast< const asn1::prim::types::String &>(b); + len = s.get_value().size(); // Length + ASN1_BER_LOG_DEBUG( "jer::encode string tag=%d len=%d" + , b.tag().get_id() + , len + ); + put_field(s.get_value().c_str(),len); +} + + +int jer::decode_string(asn1::types::type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("jer::decode string tag_id=%d",b.tag().get_id()); + asn1::prim::types::String &s = dynamic_cast(b); + + return asn1::ok; +} + + +// Choice +// +void jer::encode_choice(asn1::types::choice_type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("jer::encode choice "); +} + +int jer::decode_choice(asn1::types::choice_type &b) +{ + ASN1_BER_LOG_DEBUG("jer::decode choice "); + return asn1::ok; +} + + +// Sequence +void jer::encode_sequence_preamble(asn1::types::sequence_type &b) +{ + int len = 0; + unsigned long pos = bytes(); + unsigned char *bu = buffer(); + ASN1_BER_LOG_DEBUG("jer::encode sequence preamble tag=%d",b.tag().byte()); +} +void jer::encode_sequence_epilogue(asn1::types::sequence_type &b) +{ + ASN1_BER_LOG_DEBUG("jer::encode sequence epilogue tag=%d",b.tag().byte()); +} + + +int jer::decode_sequence_preamble(asn1::types::sequence_type &b) +{ + if ( get_token(jer_tok_left_bracket)) + { + return asn1::ok; + } else + return asn1::wrong_type; +} + +int jer::decode_sequence_epilogue(asn1::types::sequence_type &b) +{ + if ( get_token(jer_tok_right_bracket)) + { + return asn1::ok; + } else + return asn1::wrong_type; +} + + +// +void jer::encode_header(const asn1::types::type &obj, int &len) +{ + asn1::tag t = obj.tag(); + unsigned long pos = bytes(); + unsigned char *b = buffer(); + + ASN1_BER_LOG_DEBUG("jer::encode_header code tag: cls=%d id=%d ",t.get_class(),t.get_id()); + // Encode Tag, check the tag value .... +} + +int jer::decode_tag(asn1::tag &t) +{ + int len; + return decode_header(t,len); +} +/** + * + */ +bool jer::decode_tag(asn1::tag &tag,int &len) +{ + return true; +} + +bool jer::decode_header(const asn1::tag &tag,int &len) +{ + return true; +} + +/* */ +#define STR_CHECK_EOF \ +if (offset >= jsonTextLen) { \ + tok = jer_tok_eof; \ + goto finish_string_lex; \ +} + +jer::jer_token +jer::lex_string( const unsigned char * jsonText, + size_t jsonTextLen, size_t & offset) +{ + jer_token tok = jer_tok_error; + int hasEscapes = 0; + + for (;;) { + unsigned char curChar; +#if 0 + /* now jump into a faster scanning routine to skip as much + * of the buffers as possible */ + { + const unsigned char * p; + size_t len; + + if ((lexer->bufInUse && yajl_buf_len(lexer->buf) && + lexer->bufOff < yajl_buf_len(lexer->buf))) + { + p = ((const unsigned char *) yajl_buf_data(lexer->buf) + + (lexer->bufOff)); + len = yajl_buf_len(lexer->buf) - lexer->bufOff; + lexer->bufOff += yajl_string_scan(p, len, lexer->validateUTF8); + } + else if (*offset < jsonTextLen) + { + p = jsonText + *offset; + len = jsonTextLen - *offset; + *offset += yajl_string_scan(p, len, lexer->validateUTF8); + } + } +#endif + STR_CHECK_EOF; + + curChar = readChar( jsonText, offset); + + /* quote terminates */ + if (curChar == '"') { + tok = jer_tok_string; + break; + } + /* backslash escapes a set of control chars, */ + else if (curChar == '\\') { + hasEscapes = 1; + STR_CHECK_EOF; + + /* special case \u */ + curChar = readChar( jsonText, offset); + if (curChar == 'u') { + unsigned int i = 0; + + for (i=0;i<4;i++) { + STR_CHECK_EOF; + curChar = readChar( jsonText, offset); + if (!(charLookupTable[curChar] & VHC)) { + /* back up to offending char */ + unreadChar( offset); + m_error = jer_err_string_invalid_hex_char; + goto finish_string_lex; + } + } + } else if (!(charLookupTable[curChar] & VEC)) { + /* back up to offending char */ + unreadChar(offset); + m_error = jer_err_string_invalid_escaped_char; + goto finish_string_lex; + } + } + /* when not validating UTF8 it's a simple table lookup to determine + * if the present character is invalid */ + else if(charLookupTable[curChar] & IJC) { + /* back up to offending char */ + unreadChar(offset); + m_error = jer_err_string_invalid_json_char; + goto finish_string_lex; + } +#if 0 + /* when in validate UTF8 mode we need to do some extra work */ + else if (lexer->validateUTF8) { + yajl_tok t = yajl_lex_utf8_char(lexer, jsonText, jsonTextLen, + offset, curChar); + + if (t == yajl_tok_eof) { + tok = yajl_tok_eof; + goto finish_string_lex; + } else if (t == yajl_tok_error) { + lexer->error = yajl_lex_string_invalid_utf8; + goto finish_string_lex; + } + } +#endif + /* accept it, and move on */ + } + finish_string_lex: + /* tell our buddy, the parser, wether he needs to process this string + * again */ + if (hasEscapes && tok == jer_tok_string) { + tok = jer_tok_string_with_escapes; + } + + return tok; + return jer_tok_error; +} + +#define RETURN_IF_EOF if (offset >= jsonTextLen) return jer_tok_eof; +jer::jer_token +jer::lex_number( const unsigned char * jsonText, + size_t jsonTextLen, size_t & offset) +{ + unsigned char c; + + jer_token tok = jer_tok_integer; + + RETURN_IF_EOF; + c = readChar( jsonText, offset); + + /* optional leading minus */ + if (c == '-') { + RETURN_IF_EOF; + c = readChar( jsonText, offset); + } + + /* a single zero, or a series of integers */ + if (c == '0') { + RETURN_IF_EOF; + c = readChar( jsonText, offset); + } else if (c >= '1' && c <= '9') { + do { + RETURN_IF_EOF; + c = readChar( jsonText, offset); + } while (c >= '0' && c <= '9'); + } else { + unreadChar( offset); + m_error = jer_err_missing_integer_after_minus; + return jer_tok_error; + } + + /* optional fraction (indicates this is floating point) */ + if (c == '.') { + int numRd = 0; + + RETURN_IF_EOF; + c = readChar( jsonText, offset); + + while (c >= '0' && c <= '9') { + numRd++; + RETURN_IF_EOF; + c = readChar( jsonText, offset); + } + + if (!numRd) { + unreadChar( offset); + m_error = jer_err_missing_integer_after_decimal; + return jer_tok_error; + } + tok = jer_tok_double; + } + + /* optional exponent (indicates this is floating point) */ + if (c == 'e' || c == 'E') { + RETURN_IF_EOF; + c = readChar( jsonText, offset); + + /* optional sign */ + if (c == '+' || c == '-') { + RETURN_IF_EOF; + c = readChar( jsonText, offset); + } + + if (c >= '0' && c <= '9') { + do { + RETURN_IF_EOF; + c = readChar( jsonText, offset); + } while (c >= '0' && c <= '9'); + } else { + unreadChar( offset); + m_error = jer_err_missing_integer_after_exponent; + return jer_tok_error; + } + tok = jer_tok_double; + } + + /* we always go "one too far" */ + unreadChar( offset); + + return tok; +} + +jer::jer_token +jer::lex_comment(const unsigned char * jsonText, + size_t jsonTextLen, size_t & offset) +{ + return jer_tok_error; +} + +int +jer::json_lex(size_t &offset,unsigned char **outBuf, size_t &outLen) +{ + unsigned char * jsonText = m_buffer; + size_t jsonTextLen = m_size; + size_t startOffset = offset; + int tok = jer_tok_error; + unsigned char c; + + *outBuf = NULL; + outLen = 0; +#if 1 + for (;;) { + assert(offset <= jsonTextLen); + + if (offset >= jsonTextLen) { + tok = jer_tok_eof; + goto lexed; + } + + //c = readChar(lexer, jsonText, offset); + c = readChar(); + + switch (c) { + case '{': + tok = jer_tok_left_bracket; + goto lexed; + case '}': + tok = jer_tok_right_bracket; + goto lexed; + case '[': + tok = jer_tok_left_brace; + goto lexed; + case ']': + tok = jer_tok_right_brace; + goto lexed; + case ',': + tok = jer_tok_comma; + goto lexed; + case ':': + tok = jer_tok_colon; + goto lexed; + case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': + startOffset++; + break; + case 't': { + const char * want = "rue"; + do { + if (offset >= jsonTextLen) { + tok = jer_tok_eof; + goto lexed; + } + //c = readChar(lexer, jsonText, offset); + c = readChar(); + if (c != *want) { + //unreadChar(lexer, offset); + unreadChar(offset); + m_error = jer_err_invalid_string; + tok = jer_tok_error; + goto lexed; + } + } while (*(++want)); + tok = jer_tok_bool; + goto lexed; + } + case 'f': { + const char * want = "alse"; + do { + if (offset >= jsonTextLen) { + tok = jer_tok_eof; + goto lexed; + } + //c = readChar(lexer, jsonText, offset); + c = readChar(); + if (c != *want) { + //unreadChar(lexer, offset); + unreadChar(offset); + m_error = jer_err_invalid_string; + tok = jer_tok_error; + goto lexed; + } + } while (*(++want)); + tok = jer_tok_bool; + goto lexed; + } + case 'n': { + const char * want = "ull"; + do { + if (offset >= jsonTextLen) { + tok = jer_tok_eof; + goto lexed; + } + //c = readChar(lexer, jsonText, offset); + c = readChar(); + if (c != *want) { + //unreadChar(lexer, offset); + unreadChar(offset); + m_error = jer_err_invalid_string; + tok = jer_tok_error; + goto lexed; + } + } while (*(++want)); + tok = jer_tok_null; + goto lexed; + } + case '"': { + tok = lex_string( (const unsigned char *) jsonText, + jsonTextLen, offset); + goto lexed; + } + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + /* integer parsing wants to start from the beginning */ + //unreadChar(lexer, offset); + unreadChar(offset); + tok = lex_number((const unsigned char *) jsonText, + jsonTextLen, offset); + goto lexed; + } + case '/': + /* hey, look, a probable comment! If comments are disabled + * it's an error. */ + if (!m_allowComments) { + //unreadChar(lexer, offset); + unreadChar( offset); + m_error = jer_err_unallowed_comment; + tok = jer_tok_error; + goto lexed; + } + /* if comments are enabled, then we should try to lex + * the thing. possible outcomes are + * - successful lex (tok_comment, which means continue), + * - malformed comment opening (slash not followed by + * '*' or '/') (tok_error) + * - eof hit. (tok_eof) */ + tok = lex_comment((const unsigned char *) jsonText, + jsonTextLen, offset); + if (tok == jer_tok_comment) { + /* "error" is silly, but that's the initial + * state of tok. guilty until proven innocent. */ + tok = jer_tok_error; +#if 0 + yajl_buf_clear(lexer->buf); + bufInUse = 0; +#endif + startOffset = offset; + break; + } + /* hit error or eof, bail */ + goto lexed; + default: + m_error = jer_err_invalid_char; + tok = jer_tok_error; + goto lexed; + } + } + + + lexed: + /* need to append to buffer if the buffer is in use or + * if it's an EOF token */ +#if 0 + if (tok == jer_tok_eof || lexer->bufInUse) { + if (!lexer->bufInUse) yajl_buf_clear(lexer->buf); + lexer->bufInUse = 1; + yajl_buf_append(lexer->buf, jsonText + startOffset, offset - startOffset); + lexer->bufOff = 0; + + if (tok != jer_tok_eof) { + *outBuf = yajl_buf_data(lexer->buf); + *outLen = yajl_buf_len(lexer->buf); + lexer->bufInUse = 0; + } + } else +#endif + if (tok != jer_tok_error) { + *outBuf = jsonText + startOffset; + outLen = offset - startOffset; + } + + /* special case for strings. skip the quotes. */ + if (tok == jer_tok_string || tok == jer_tok_string_with_escapes) + { + assert(outLen >= 2); + (*outBuf)++; + outLen -= 2; + } + + +#ifdef YAJL_LEXER_DEBUG + if (tok == jer_tok_error) { + printf("lexical error: %s\n", + yajl_lex_error_to_string(yajl_lex_get_error(lexer))); + } else if (tok == jer_tok_eof) { + printf("EOF hit\n"); + } else { + printf("lexed %s: '", tokToStr(tok)); + fwrite(*outBuf, 1, *outLen, stdout); + printf("'\n"); + } +#endif +#endif + return tok; +} +/** + * question the next token but don't move lexer forward + */ +int +jer::json_lex_peek(size_t &offset,const unsigned char **outbuf, size_t &outlen) +{ + return 1; +} + + +/* + * vim:et:sw=2:ts=2 + */ +/* end of namespace */ +} +} diff --git a/rtasn1/asn1_codec_jer.h b/rtasn1/asn1_codec_jer.h new file mode 100644 index 0000000..8f20263 --- /dev/null +++ b/rtasn1/asn1_codec_jer.h @@ -0,0 +1,275 @@ +#ifndef CODEC_JER_H +#define CODEC_JER_H +#include + +#if defined(__GNUC__) && defined(DEBUG) & not(defined(ASN1_BER_LOG_DEBUG)) +#define ASN1_BER_LOG_DEBUG(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (asn1.y : %d)\n",__LINE__);\ +} while (0) +#elseif not(defined(ASN1_BER_LOG_DEBUG)) + static inline void ASN1_BER_LOG_DEBUG(const char *fmt,...) {(void)fmt;}; +#endif + +namespace asn1 { +class context; + + + + +namespace streams { + +/** + * Should not be in codecs namespace. + * It's a jer context used by the jer codec. + */ +class jer : public asn1::context +{ + public: + enum jer_token { + jer_tok_bool + , jer_tok_colon + , jer_tok_comma + , jer_tok_eof + , jer_tok_error + , jer_tok_left_brace + , jer_tok_left_bracket + , jer_tok_null + , jer_tok_right_brace + , jer_tok_right_bracket + /* */ + , jer_tok_integer + , jer_tok_double + , jer_tok_string + , jer_tok_string_with_escapes + , jer_tok_comment + }; + + enum jer_lex_error { + jer_err_ok = 0 + ,jer_err_string_invalid_utf8 + ,jer_err_string_invalid_escaped_char + ,jer_err_string_invalid_json_char + ,jer_err_string_invalid_hex_char + ,jer_err_invalid_string + ,jer_err_invalid_char + /* Missing error codes for numbers*/ + ,jer_err_unallowed_comment + ,jer_err_missing_integer_after_minus + ,jer_err_missing_integer_after_decimal + ,jer_err_missing_integer_after_exponent + }; + + jer( int sz = 512) ; + jer(unsigned char *buf, int sz = 512) ; + jer(const jer &c) ; + ~jer() {} + + virtual int decode_tag(asn1::tag &t) ; + + // Null + // 5 + virtual void encode_null(const asn1::Null &b) ; + virtual int decode_null(asn1::Null &b) ; + + // Bool + // + virtual void encode_boolean(const asn1::BOOLEAN &b) ; + virtual int decode_boolean(asn1::BOOLEAN &b) ; + + // Integer + // + virtual void encode_integer(const asn1::types::type &b) ; + virtual int decode_integer(asn1::INTEGER &b) ; + int decode_integer(asn1::UInt64 &b) ; + + // Bit String + // + virtual void encode_bitstring(const asn1::BIT_STRING &b) ; + virtual int decode_bitstring(asn1::BIT_STRING &b) ; + + // Octet string + // + virtual void encode_octetstring(const asn1::OCTET_STRING &b) ; + virtual int decode_octetstring(asn1::OCTET_STRING &b) ; + + virtual void encode_string(const asn1::types::type &b) ; + virtual int decode_string(asn1::types::type &b) ; + // Choice + // + virtual void encode_choice(asn1::types::choice_type &b) ; + virtual int decode_choice(asn1::types::choice_type &b) ; + + // Sequence + virtual void encode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual void encode_sequence_epilogue(asn1::types::sequence_type &b) ; + virtual int decode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual int decode_sequence_epilogue(asn1::types::sequence_type &b) ; + + /** + * When reading jer, we need to be able to decode the length + */ + bool decode_tag( asn1::tag &t, int &len); + + bool decode_header(const asn1::tag &tag,int &len); + /**/ + void put_string(const std::string &s); + /**/ + void put_char(const unsigned char *s,size_t len); + + void put_char(const char *s,size_t len); + + /** + * retrieve token. If the lexer parses token + * return true or else return false and leave + * m_bufOff unchanged. + */ + bool get_token(const char *); + bool get_token(jer_token tok); + bool get_token(std::string &s); + + inline void put_field(const char *s,size_t len) + { put_char("\"",1); put_char(s,len); put_char("\"",1); }; + /* json specifique functions code */ + const char *error_to_string(int i) const; + /* get current offset into the most recently lexed json string */ + inline size_t current_offset() const { return m_bufOff; }; + /* number of char lexed */ + inline size_t current_char() const { return m_charOff; }; + /* number of lines lexed */ + inline size_t current_line() const { return m_lineOff; }; + + friend std::ostream &operator<<(std::ostream &os,const jer &_jer) + { + os<<(char *)const_cast< jer &>(_jer).buffer(); return os; + } + protected: + /* To be reviewed */ + inline unsigned char readChar() + {return (m_bufOff < get_size() ? *(m_buffer + m_bufOff++) : *m_buffer); }; + /* To be reviewed */ + inline unsigned char readChar(const unsigned char *c,size_t &offset) + {return c[offset++]; }; + + inline size_t unreadChar(size_t &off) { return (off>0)?off--:m_bufOff--; }; + /** + * do i need encode_header for jer ? + */ + void encode_header(const asn1::types::type &obj, int &len); + + const char * tok2str(int tok) const; + /** + * analyse,lex buffer and return appropriate token + * this function can be invoked several times until eof. + */ + int json_lex(size_t &offset,unsigned char **outbuf, size_t &outlen); + /** + * question the next token but don't move lexer forward + */ + int json_lex_peek(size_t &offset,const unsigned char **outbuf, size_t &outlen); + + jer_token lex_string(const unsigned char *,size_t,size_t &offset); + + jer_token lex_number(const unsigned char *,size_t,size_t &offset); + + jer_token lex_comment(const unsigned char *,size_t,size_t &offset); + /* Offset local variables */ + size_t m_lineOff; + size_t m_charOff; + /** Current offset into lex buffer */ + size_t m_bufOff; + bool m_allowComments; + // There is no way to get parent so may use a stack to push/pop parent element + jer_lex_error m_error; +}; /* end jer class */ + +} /* end streams namespace */ + +/** + * + * How will codecJER look like ? + */ + + class codecJER : public codec + { + protected: + + public: + codecJER() {} + + template + void encode(streams::jer &ctx,const T &t) ; + + template + int decode(streams::jer &ctx, T &t) ; + + /* Special case for Sequence OF */ + template + void encode(streams::jer &ctx,const asn1::Seq &t) + { + typename asn1::Seq::const_iterator mit = t.begin(); + for (; mit != t.end() ; ++mit) + { + if (mit != t.begin()) + ctx.put_char(", ",2); + encode(ctx,(*mit)); + } + } + + template + int decode(streams::jer &ctx,asn1::Seq &t) + { + T element; + int ret; + if ( ! ctx.get_token(streams::jer::jer_tok_left_brace)) + { + + std::cerr<<"decode sequenceof non left brace aiee"< size ="< \ + void codecJER::encode(streams::jer &ctx, const asn1::Asn1Type &t) \ + ; \ + template <> \ + int \ + codecJER::decode(streams::jer &ctx, asn1::Asn1Type &t) \ + ; +#include "rtasn1/asn1_types.inc" + + +} + +#endif +/* + * vim: et sw=2 ts=2 : + */ diff --git a/rtasn1/asn1_codec_oer.cpp b/rtasn1/asn1_codec_oer.cpp new file mode 100644 index 0000000..2122429 --- /dev/null +++ b/rtasn1/asn1_codec_oer.cpp @@ -0,0 +1,456 @@ +#include +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_context.h" + +#include "rtasn1/asn1_codec_oer.h" + +/* +vim:et:sw=2:ts=2 + */ +namespace asn1 { + +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + template <> \ + void codecOER::encode(streams::oer &ctx, const asn1::Asn1Type &t) \ + { std::cerr<<"codecOER::"<<__FUNCTION__<<" good "; \ + std::cerr<<#Asn1Type< \ + int \ + codecOER::decode(streams::oer &ctx, asn1::Asn1Type &t) \ + { std::cerr<<"codecOER::"<<__FUNCTION__<<" good "; \ + std::cerr<<#Asn1Type<(b); + long integer = i.get_value(); + int intsize = 4; + long mask = 0x1FF <<23; // Shift 8 *3 - 1 ? 0xFF800000 + + ASN1_BER_LOG_DEBUG("oer::encode integer tag=%d value=%ld intsize=%d decale =%d",b.tag().byte(),(long)i.get_value(),(int)intsize,(intsize<<3)); + +} + +/** + * Decode Integer + */ +int oer::decode_integer(asn1::INTEGER &t) +{ + int len = 0; + int result = 0; + + ASN1_BER_LOG_DEBUG("oer::decode integer tag=%d",t.tag().byte()); + return asn1::ok; +} + + +// Bit String +// +void oer::encode_bitstring(const asn1::BIT_STRING &t) +{ + int len = t.size() + 1; + ASN1_BER_LOG_DEBUG("oer::encode bit string len=%d ",len); +} + +int oer::decode_bitstring(asn1::BIT_STRING &t) +{ + ASN1_BER_LOG_DEBUG("oer::decode bit string tag=%d ",t.tag().byte()); + return asn1::ok; +} + + +// Octet string +// +void oer::encode_octetstring(const asn1::OCTET_STRING &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("oer::encode octet string tag=%d",b.tag().byte()); +} + +int oer::decode_octetstring(asn1::OCTET_STRING &b_) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("oer::decode octet string TODO "); + return asn1::ok; +} + +void oer::encode_string(const asn1::types::type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("oer::encode string tag=%d",b.tag().get_id()); + const asn1::prim::types::String &s = dynamic_cast< const asn1::prim::types::String &>(b); + len = ((std::string)s.get_value()).size(); // Length + //encode_header(b.type::tag(),len); + + unsigned long pos = bytes(); + unsigned char *buf = buffer(); + +} + + +int oer::decode_string(asn1::types::type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("oer::decode string tag_id=%d",b.tag().get_id()); + asn1::prim::types::String &s = dynamic_cast(b); + + return asn1::ok; +} + + +// Choice +// +void oer::encode_choice(asn1::types::choice_type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("oer::encode choice "); +} + +int oer::decode_choice(asn1::types::choice_type &b) +{ + ASN1_BER_LOG_DEBUG("oer::decode choice "); + return asn1::ok; +} + + +// Sequence +void oer::encode_sequence_preamble(asn1::types::sequence_type &b) +{ + int len = 0; + unsigned long pos = bytes(); + unsigned char *bu = buffer(); + ASN1_BER_LOG_DEBUG("oer::encode sequence preamble tag=%d",b.tag().byte()); +} +void oer::encode_sequence_epilogue(asn1::types::sequence_type &b) +{ + ASN1_BER_LOG_DEBUG("oer::encode sequence epilogue tag=%d",b.tag().byte()); +} + + +int oer::decode_sequence_preamble(asn1::types::sequence_type &b) +{ + int len; + std::string n = typeid(b).name(); + ASN1_BER_LOG_DEBUG("oer::decode sequence preable %s",n.c_str()); + + //return b.decode_preamble_ber(*this); + return asn1::ok; +} + +int oer::decode_sequence_epilogue(asn1::types::sequence_type &b) +{ + //return b.decode_epilogue_ber(*this); + return asn1::ok; +} + + +// +void oer::encode_header(const asn1::types::type &obj, int &len) +{ + asn1::tag t = obj.tag(); + unsigned long pos = bytes(); + unsigned char *b = buffer(); + + ASN1_BER_LOG_DEBUG("oer::encode_header code tag: cls=%d id=%d ",t.get_class(),t.get_id()); + // Encode Tag, check the tag value .... +} + + +bool oer::decode_header(const asn1::tag &tag,int &len) +{ + return true; +} + + + +/* + * vim:et:sw=2:ts=2 + */ +/* end of namespace */ +} +} diff --git a/rtasn1/asn1_codec_oer.h b/rtasn1/asn1_codec_oer.h new file mode 100644 index 0000000..dffe72e --- /dev/null +++ b/rtasn1/asn1_codec_oer.h @@ -0,0 +1,127 @@ +#ifndef CODEC_OER_H +#define CODEC_OER_H +#include + +#if defined(__GNUC__) && defined(DEBUG) & not(defined(ASN1_BER_LOG_DEBUG)) +#define ASN1_BER_LOG_DEBUG(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (asn1.y : %d)\n",__LINE__);\ +} while (0) +#elseif not(defined(ASN1_BER_LOG_DEBUG)) + static inline void ASN1_BER_LOG_DEBUG(const char *fmt,...) {(void)fmt;}; +#endif + +namespace asn1 { +class context; + + + + +namespace streams { +//#define DEBUG +/** + * + */ + +class oer : public asn1::context +{ + public: + oer( int sz = 512) ; + oer(const oer &c) ; + ~oer() {} + + // Null + // 5 + virtual void encode_null(const asn1::Null &b) ; + virtual int decode_null(asn1::Null &b) ; + + // Bool + // + virtual void encode_boolean(const asn1::BOOLEAN &b) ; + virtual int decode_boolean(asn1::BOOLEAN &b) ; + + // Integer + // + virtual void encode_integer(const asn1::types::type &b) ; + virtual int decode_integer(asn1::INTEGER &b) ; + + // Bit String + // + virtual void encode_bitstring(const asn1::BIT_STRING &b) ; + virtual int decode_bitstring(asn1::BIT_STRING &b) ; + + // Octet string + // + virtual void encode_octetstring(const asn1::OCTET_STRING &b) ; + virtual int decode_octetstring(asn1::OCTET_STRING &b) ; + + virtual void encode_string(const asn1::types::type &b) ; + virtual int decode_string(asn1::types::type &b) ; + // Choice + // + virtual void encode_choice(asn1::types::choice_type &b) ; + virtual int decode_choice(asn1::types::choice_type &b) ; + + // Sequence + virtual void encode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual void encode_sequence_epilogue(asn1::types::sequence_type &b) ; + virtual int decode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual int decode_sequence_epilogue(asn1::types::sequence_type &b) ; + + /** + * When reading ber, we need to be able to decode the length + */ + bool decode_tag( asn1::tag &t, int &len); + + bool decode_header(const asn1::tag &tag,int &len); + protected: + void encode_header(const asn1::types::type &obj, int &len); + // There is no way to get parent so may use a stack to push/pop parent element +}; + +} + +/** + * + * How will codecBER look like ? + */ + + class codecOER : public codec + { + protected: + + public: + codecOER() {} + + template + void encode(streams::oer &ctx,const T &t) ; + + template + int decode(streams::oer &ctx, T &t) ; + // Need to provide implementation + // For base Types, INTEGER, BOOLEAN... +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + void encode_oer(streams::oer &ctx, const asn1::Asn1Type &t); \ + int \ + decode_oer(streams::oer &ctx, asn1::Asn1Type &t); +#include "rtasn1/asn1_types.inc" + }; + +/* encode / decode specialization declaration */ +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + template <> \ + void codecOER::encode(streams::oer &ctx, const asn1::Asn1Type &t) \ + ; \ + template <> \ + int \ + codecOER::decode(streams::oer &ctx, asn1::Asn1Type &t) \ + ; +#include "rtasn1/asn1_types.inc" + + +} + +#endif +/* + * vim: et sw=2 ts=2 : + */ diff --git a/rtasn1/asn1_codec_per.cpp b/rtasn1/asn1_codec_per.cpp new file mode 100644 index 0000000..3cbb2b0 --- /dev/null +++ b/rtasn1/asn1_codec_per.cpp @@ -0,0 +1,469 @@ +#include +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_context.h" + +#include "rtasn1/asn1_codec_per.h" + +/* +vim:et:sw=2:ts=2 + */ +namespace asn1 { + +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + template <> \ + void codecPER::encode(codecs::per &ctx, const asn1::Asn1Type &t) \ + { std::cerr<<"codecPER::"<<__FUNCTION__<<" good "; \ + std::cerr<<#Asn1Type< \ + asn1::Asn1Type & \ + codecPER::decode(codecs::per &ctx, asn1::Asn1Type &t) \ + { std::cerr<<"codecPER::"<<__FUNCTION__<<" good "; \ + std::cerr<<#Asn1Type<(b); + long integer = i.get_value(); + int intsize = 4; + long mask = 0x1FF <<23; // Shift 8 *3 - 1 ? 0xFF800000 + + ASN1_BER_LOG_DEBUG("per::encode integer tag=%d value=%ld intsize=%d decale =%d",b.tag().byte(),(long)i.get_value(),(int)intsize,(intsize<<3)); + +} + +/** + * Decode Integer + */ +int per::decode_integer(asn1::INTEGER &t) +{ + int len = 0; + int result = 0; + + ASN1_BER_LOG_DEBUG("per::decode integer tag=%d",t.tag().byte()); + return asn1::ok; +} + + +// Bit String +// +void per::encode_bitstring(const asn1::BIT_STRING &t) +{ + int len = t.size() + 1; + ASN1_BER_LOG_DEBUG("per::encode bit string len=%d ",len); +} + +int per::decode_bitstring(asn1::BIT_STRING &t) +{ + ASN1_BER_LOG_DEBUG("per::decode bit string tag=%d ",t.tag().byte()); + return asn1::ok; +} + + +// Octet string +// +void per::encode_octetstring(const asn1::OCTET_STRING &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("per::encode octet string tag=%d",b.tag().byte()); +} + +int per::decode_octetstring(asn1::OCTET_STRING &b_) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("per::decode octet string TODO "); + return asn1::ok; +} + +void per::encode_string(const asn1::types::type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("per::encode string tag=%d",b.tag().get_id()); + const asn1::prim::types::String &s = dynamic_cast< const asn1::prim::types::String &>(b); + len = ((std::string)s.get_value()).size(); // Length + //encode_header(b.type::tag(),len); + + unsigned long pos = bytes(); + unsigned char *buf = buffer(); + +} + + +int per::decode_string(asn1::types::type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("per::decode string tag_id=%d",b.tag().get_id()); + asn1::prim::types::String &s = dynamic_cast(b); + + return asn1::ok; +} + + +// Choice +// +void per::encode_choice(asn1::types::choice_type &b) +{ + int len = 0; + ASN1_BER_LOG_DEBUG("per::encode choice "); +} + +int per::decode_choice(asn1::types::choice_type &b) +{ + ASN1_BER_LOG_DEBUG("per::decode choice "); + return asn1::ok; +} + + +// Sequence +void per::encode_sequence_preamble(asn1::types::sequence_type &b) +{ + int len = 0; + unsigned long pos = bytes(); + unsigned char *bu = buffer(); + ASN1_BER_LOG_DEBUG("per::encode sequence preamble tag=%d",b.tag().byte()); +} +void per::encode_sequence_epilogue(asn1::types::sequence_type &b) +{ + ASN1_BER_LOG_DEBUG("per::encode sequence epilogue tag=%d",b.tag().byte()); +} + + +int per::decode_sequence_preamble(asn1::types::sequence_type &b) +{ + int len; + std::string n = typeid(b).name(); + ASN1_BER_LOG_DEBUG("per::decode sequence preable %s",n.c_str()); + + //return b.decode_preamble_ber(*this); + return asn1::ok; +} + +int per::decode_sequence_epilogue(asn1::types::sequence_type &b) +{ + //return b.decode_epilogue_ber(*this); + return asn1::ok; +} + + +// +void per::encode_header(const asn1::types::type &obj, int &len) +{ + asn1::tag t = obj.tag(); + unsigned long pos = bytes(); + unsigned char *b = buffer(); + + ASN1_BER_LOG_DEBUG("per::encode_header code tag: cls=%d id=%d ",t.get_class(),t.get_id()); + // Encode Tag, check the tag value .... +} + +bool per::decode_header(const asn1::tag &tag,int &len) +{ + return true; +} + + + +/* + * vim:et:sw=2:ts=2 + */ +/* end of namespace */ +} +} diff --git a/rtasn1/asn1_codec_per.h b/rtasn1/asn1_codec_per.h new file mode 100644 index 0000000..292c408 --- /dev/null +++ b/rtasn1/asn1_codec_per.h @@ -0,0 +1,126 @@ +#ifndef CODEC_PER_H +#define CODEC_PER_H +#include + +#if defined(__GNUC__) && defined(DEBUG) & not(defined(ASN1_BER_LOG_DEBUG)) +#define ASN1_BER_LOG_DEBUG(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (asn1.y : %d)\n",__LINE__);\ +} while (0) +#elseif not(defined(ASN1_BER_LOG_DEBUG)) + static inline void ASN1_BER_LOG_DEBUG(const char *fmt,...) {(void)fmt;}; +#endif + +namespace asn1 { +class context; + + + + +namespace codecs { +//#define DEBUG +/** + * + */ + +class per : public asn1::context +{ + public: + per( int sz = 512) ; + per(const per &c) ; + ~per() {} + + // Null + // 5 + virtual void encode_null(const asn1::Null &b) ; + virtual int decode_null(asn1::Null &b) ; + + // Bool + // + virtual void encode_boolean(const asn1::BOOLEAN &b) ; + virtual int decode_boolean(asn1::BOOLEAN &b) ; + + // Integer + // + virtual void encode_integer(const asn1::types::type &b) ; + virtual int decode_integer(asn1::INTEGER &b) ; + + // Bit String + // + virtual void encode_bitstring(const asn1::BIT_STRING &b) ; + virtual int decode_bitstring(asn1::BIT_STRING &b) ; + + // Octet string + // + virtual void encode_octetstring(const asn1::OCTET_STRING &b) ; + virtual int decode_octetstring(asn1::OCTET_STRING &b) ; + + virtual void encode_string(const asn1::types::type &b) ; + virtual int decode_string(asn1::types::type &b) ; + // Choice + // + virtual void encode_choice(asn1::types::choice_type &b) ; + virtual int decode_choice(asn1::types::choice_type &b) ; + + // Sequence + virtual void encode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual void encode_sequence_epilogue(asn1::types::sequence_type &b) ; + virtual int decode_sequence_preamble(asn1::types::sequence_type &b) ; + virtual int decode_sequence_epilogue(asn1::types::sequence_type &b) ; + + /** + * When reading ber, we need to be able to decode the length + */ + + bool decode_header(const asn1::tag &tag,int &len); + protected: + void encode_header(const asn1::types::type &obj, int &len); + // There is no way to get parent so may use a stack to push/pop parent element +}; + +} + +/** + * + * How will codecPER look like ? + */ + + class codecPER : public codec + { + protected: + + public: + codecPER() {} + + template + void encode(codecs::per &ctx,const T &t) ; + + template + T& decode(codecs::per &ctx, T &t) ; + // Need to provide implementation + // For base Types, INTEGER, BOOLEAN... +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + void encode_per(codecs::per &ctx, const asn1::Asn1Type &t); \ + asn1::Asn1Type & \ + decode_per(codecs::per &ctx, asn1::Asn1Type &t); +#include "rtasn1/asn1_types.inc" + }; + +/* encode / decode specialization declaration */ +#define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) \ + template <> \ + void codecPER::encode(codecs::per &ctx, const asn1::Asn1Type &t) \ + ; \ + template <> \ + asn1::Asn1Type & \ + codecPER::decode(codecs::per &ctx, asn1::Asn1Type &t) \ + ; +#include "rtasn1/asn1_types.inc" + + +} + +#endif +/* + * vim: et sw=2 ts=2 : + */ diff --git a/rtasn1/asn1_config.h.in b/rtasn1/asn1_config.h.in new file mode 100644 index 0000000..880afc4 --- /dev/null +++ b/rtasn1/asn1_config.h.in @@ -0,0 +1,20 @@ +#cmakedefine HAVE_UNISTD_H +#cmakedefine HAVE_STDLIB_H +#cmakedefine HAVE_PTHREAD_H +#cmakedefine HAVE_DIRECT_H +#cmakedefine HAVE_STDINT_H +/* system function check*/ +#cmakedefine HAVE_GETCWD +#cmakedefine HAVE_MKDIR + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_DIRECT_H +#include +#endif diff --git a/rtasn1/asn1_context.cpp b/rtasn1/asn1_context.cpp new file mode 100644 index 0000000..f706106 --- /dev/null +++ b/rtasn1/asn1_context.cpp @@ -0,0 +1,125 @@ +#include +#include + +#include "rtasn1/asn1_errors.h" +#include "asn1.h" +#include "asn1_codec.h" +#include "asn1_context.h" +/* + * ** Translation Table as described in RFC1113 + * */ +static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* + * ** Translation Table to decode (created by author) + * */ +static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + + +namespace asn1 { + +/** + * Default constructor + */ +context::context(size_t size) : m_bits(0),m_check_tag(true),m_managed(true) + , m_size(size) +#ifdef WITH_CODEC + , asn1::context_base() +#endif + +{ + m_buffer = (unsigned char *)malloc(size); + memset(m_buffer,0x00,size); +}; + +context::context(unsigned char *b,size_t size) : m_bits(0),m_buffer(b),m_check_tag(true),m_managed(false) + , m_size(size) +#ifdef WITH_CODEC + , asn1::context_base() +#endif +{ +}; + +context::context(const context &c) +#ifdef WITH_CODEC + : asn1::context_base() +#endif +{ + ; +} + +context::~context() +{ + if (types::debug_level> 6) + { + if (m_bits != 0) + { + std::cout<<" context::"<<__FUNCTION__<<" coded: "<(str.c_str())); + while (p < end) + { + if (p+3 < end) { + encode_base64_block(p,out,0); + p+=3; out+=4; + } else + { + encode_base64_block(p,out,end-p); + p+= (end-p); + } + } + + +} + +void +context::encode_base64_block(unsigned char *in,unsigned char *out,int len) +{ + out[0] = (unsigned char) cb64[ (int)(in[0] >> 2) ]; + out[1] = (unsigned char) cb64[ (int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) ]; + out[2] = (unsigned char) (len > 1 ? cb64[ (int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) ] : '='); + out[3] = (unsigned char) (len > 2 ? cb64[ (int)(in[2] & 0x3f) ] : '='); + ; +} + + +void +context::decode_base64_block(unsigned char *in,unsigned char *out,int len) +{ + out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4); + out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2); + out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]); +} + +} diff --git a/rtasn1/asn1_context.h b/rtasn1/asn1_context.h new file mode 100644 index 0000000..10528fb --- /dev/null +++ b/rtasn1/asn1_context.h @@ -0,0 +1,199 @@ +#ifndef ASN1_CONTEXT_H__ +#define ASN1_CONTEXT_H__ +#include +#include +# include +#if defined (__APPLE_CC__) +# include +#else +# include "malloc.h" +#endif +#include "rtasn1/asn1.h" + +namespace asn1 { + namespace types { +extern int debug_level; + } +}; + +namespace asn1 { + +/** + * + * Futur Abstract Class to decode/encode primitive types + * + */ +class context_base { + + public: + context_base() {}; + + virtual int decode_tag(asn1::tag &t) = 0; + // Null + // 5 + virtual void encode_null(const asn1::Null &b) = 0; + virtual int decode_null(asn1::Null &b) = 0; + + // Bool + // + virtual void encode_boolean(const asn1::BOOLEAN &b) = 0; + virtual int decode_boolean(asn1::BOOLEAN &b) = 0; + + // Integer + // + virtual void encode_integer(const asn1::types::type &b) = 0; + virtual int decode_integer(asn1::INTEGER &b) = 0; + + // Bit String + // + virtual void encode_bitstring(const asn1::BIT_STRING &b) = 0; + virtual int decode_bitstring(asn1::BIT_STRING &b) = 0; + + // Octet string + // + virtual void encode_octetstring(const asn1::OCTET_STRING &b) = 0; + virtual int decode_octetstring(asn1::OCTET_STRING &b) = 0; + + virtual void encode_string(const asn1::types::strtype &b) = 0; + virtual int decode_string(asn1::types::strtype &b) = 0; + + // Choice + // + virtual void encode_choice(asn1::types::choice_type &b) = 0; + virtual int decode_choice(asn1::types::choice_type &b) = 0; + + // Sequence + // + virtual void encode_sequence_preamble(asn1::types::sequence_type &b) = 0; + virtual void encode_sequence_epilogue(asn1::types::sequence_type &b) = 0; + virtual int decode_sequence_preamble(asn1::types::sequence_type &b) = 0; + virtual int decode_sequence_epilogue(asn1::types::sequence_type &b) = 0; + + // Any + // + virtual void encode_any(const asn1::types::any_type &b) = 0; + virtual int decode_any(asn1::types::any_type &b) = 0; + + private: + context_base(const context_base &c) {}; + + protected: +}; + + +#define WITH_CODEC +/** + * context object provides an enviromnent to codec function for reading + * and writing data. + * It must be able to provide the position in the buffer, the number for + * bits written. + * + * + */ +class context +#ifdef WITH_CODEC + : public ::asn1::context_base +#endif +{ + private: + context(const context &c) ; + bool m_managed; // Flag that helps to decide wether the buffer shall be deleted or not. + public: + + // Constructors + context(size_t size=512) ; + + context(unsigned char *b,size_t size); + + + ~context() ; + + // base 64 set and get for fast ws usage + void set_base64(const std::string &str); + + void get_base64(std::string &str); + // + inline bool check_tag() const {return m_check_tag;}; + + inline void check_tag(bool _t) {m_check_tag = _t;}; + + + inline void nb_bits( long b) {m_bits+=b;} ; + + inline size_t get_size() const { return m_size; }; + + inline unsigned long nb_read_bits() {return m_bits;} ; + // This is something like get_position, set_position. + inline unsigned long bytes() {return m_bits / 8;}; + + void bytes(unsigned long l) { m_bits = l * 8;}; + + inline unsigned char * buffer() {return m_buffer;}; + + inline void reset() { m_bits = 0 ;} ; +#ifdef WITH_CODEC + virtual int decode_tag(asn1::tag &t) {return true;}; + // Null + // 5 + virtual void encode_null(const asn1::Null &b) { ; }; + virtual int decode_null(asn1::Null &b) { return false; }; + + // Bool + // + virtual void encode_boolean(const asn1::BOOLEAN &b) { ; }; + virtual int decode_boolean(asn1::BOOLEAN &b) { return asn1::unknown; }; + + // Integer + // + virtual void encode_integer(const asn1::types::type &b) { ; }; + virtual int decode_integer(asn1::INTEGER &b) { return asn1::unknown; }; + virtual int decode_integer(asn1::UInt64 &b) { return asn1::unknown; }; + + // Bit String + // + virtual void encode_bitstring(const asn1::BIT_STRING &b) { ; }; + virtual int decode_bitstring(asn1::BIT_STRING &b) { return asn1::unknown; }; + + // Octet string + // + virtual void encode_octetstring(const asn1::OCTET_STRING &b) { ; }; + virtual int decode_octetstring(asn1::OCTET_STRING &b) { return asn1::unknown; }; + + virtual void encode_string(const asn1::types::strtype &b) {}; + virtual int decode_string(asn1::types::strtype &b) {return asn1::unknown;}; + // Choice + // + virtual void encode_choice(asn1::types::choice_type &b) { ; }; + virtual int decode_choice(asn1::types::choice_type &b) { return asn1::unknown; }; + // Sequence + // + virtual void encode_sequence_preamble(asn1::types::sequence_type &b) { ; }; + virtual void encode_sequence_epilogue(asn1::types::sequence_type &b) { ; }; + virtual int decode_sequence_preamble(asn1::types::sequence_type &b) { return asn1::unknown; }; + virtual int decode_sequence_epilogue(asn1::types::sequence_type &b) { return asn1::unknown; }; + + + // Any + // + virtual void encode_any(const asn1::types::any_type &b) {}; + virtual int decode_any(asn1::types::any_type &b) {return asn1::unknown;}; +#endif + protected: + void encode_base64_block(unsigned char *in,unsigned char *out,int len); + + void decode_base64_block(unsigned char *in,unsigned char *out,int len); + + protected: + bool m_check_tag; + long m_bits; + unsigned char * m_buffer; + size_t m_size; +}; + + +} + +/* +vim:et:sw=2:ts=2: + */ +#endif diff --git a/rtasn1/asn1_debug.h b/rtasn1/asn1_debug.h new file mode 100644 index 0000000..0b7efde --- /dev/null +++ b/rtasn1/asn1_debug.h @@ -0,0 +1,89 @@ +#ifndef ASN1_DEBUG_H__ +#define ASN1_DEBUG_H__ + +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ *10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__ ) +#endif + +#if defined(__APPLE__) || (GCC_VERSION > 40800) +#include +#include +#include +#endif +#if defined(_WIN32) +# include +#endif + + +namespace asn1 { + namespace types { + extern int debug_level; + } +}; + +#if defined(__GNUC__) && defined(DEBUG) && !defined(ASN1_BER_LOG_DEBUG) + +#define __MYFILE__ (strrchr(__FILE__,'/')?strrchr(__FILE__,'/')+1 : __FILE__) + +# define ASN1_BER_LOG_DEBUG(fmt,args...) do {\ + if (::asn1::types::debug_level >= 7) \ + { fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__MYFILE__,__LINE__); \ + } \ +} while (0); + +# define ASN1_BER_LOG_INFO(fmt,args...) do {\ + if (::asn1::types::debug_level >= 3) \ + { fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ + } \ +} while (0); + +# define ASN1_BER_LOG_ERROR(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ +} while (0); + +#elif defined(_WIN32) || defined(_WINDOWS) + +#define __MYFILE__ (strrchr(__FILE__,'/')?strrchr(__FILE__,'/')+1 : __FILE__) + +# define ASN1_BER_LOG_DEBUG(fmt,...) do {\ + if (::asn1::types::debug_level >= 7) \ + { fprintf(stderr,fmt,__VA_ARGS__);\ + fprintf(stderr," (%s : %d)\n",__MYFILE__,__LINE__); \ + } \ + } while (0); +# define ASN1_BER_LOG_INFO(fmt,...) do {\ + } while (0); +# define ASN1_BER_LOG_ERROR(fmt,...) do {\ + fprintf(stderr,fmt,__VA_ARGS__);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ + } while (0); +#else +// Not debug +# if not(defined(ASN1_BER_LOG_DEBUG)) +# define ASN1_BER_LOG_DEBUG(fmt,...) \ + do { } while (0); +# else + static inline void ASN1_BER_LOG_DEBUG(const char *fmt,...) + { + (void)fmt; + }; +# endif + +#define ASN1_BER_LOG_INFO(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ +} while (0); + +# define ASN1_BER_LOG_ERROR(fmt,args...) do {\ + fprintf(stderr,fmt,##args);\ + fprintf(stderr," (%s : %d)\n",__FILE__,__LINE__);\ +} while (0); + +#endif + +#endif diff --git a/rtasn1/asn1_errors.h b/rtasn1/asn1_errors.h new file mode 100644 index 0000000..cf74d81 --- /dev/null +++ b/rtasn1/asn1_errors.h @@ -0,0 +1,23 @@ +#ifndef ASN1_ERRORS_H__ +#define ASN1_ERRORS_H__ + +/** + * Liste the errors that can occur during parsing + */ + +namespace asn1 { + +enum errors { + ok = 0, + wrong_tag = 1, + wrong_type = 2, + wrong_length = 3, + constraint_size = 4, + incomplet = 5, + unknown = 6 + +}; + +}; + +#endif diff --git a/rtasn1/asn1_rose.h b/rtasn1/asn1_rose.h new file mode 100644 index 0000000..22c1ff3 --- /dev/null +++ b/rtasn1/asn1_rose.h @@ -0,0 +1,239 @@ +#ifndef ASN1_ROSE_H__ +#define ASN1_ROSE_H__ + +#include +#include +namespace asn1 { + + +// classes using intrusive pointers +// must provide the folowing methodes +// +// add_ref +// release +// +template +class intrusive_ptr +{ + public: + typedef T * pointer; + typedef T & reference; + intrusive_ptr(const asn1::tag &t = asn1::tag(0,0)) + : m_ptr(NULL) , m_tag(t) + { +// ASN1_BER_LOG_DEBUG("intrusive_ptr<>::construct tag= %d",m_tag.byte()); + }; + + intrusive_ptr( T* h) + : m_ptr(h) ,m_tag(h->tag()) + {if (m_ptr != NULL) m_ptr->add_ref();}; + + intrusive_ptr(const intrusive_ptr & ht) + : m_tag(ht.m_tag) ,m_ptr(NULL) + { + ASN1_BER_LOG_DEBUG("intrusive_ptr<> copy tag= %d <- %d ht.m_ptr=%0lx" + , m_tag.byte() + , ht.m_tag.byte() + , (long)ht.m_ptr); + if (ht.m_ptr) + { + std::string name = typeid(*ht.m_ptr).name(); + ASN1_BER_LOG_DEBUG("intrusive_ptr<> copied %s",name.c_str()); + m_ptr = ht.m_ptr; + m_ptr->add_ref(); + m_tag = ht.m_tag; + } + }; + + pointer clone() + { + T *tp = new T(m_tag); + return tp; + } + void set_tag(const asn1::tag &t) { m_tag =t;}; + inline void create(asn1::tag t = asn1::tag(0,0)) + { + if ( ! is_nul() ) + m_ptr->release(); + m_ptr = new T(); + if (t.byte() > 0 ) + { + m_ptr->set_tag(t); + } else { + // This does not work at all with csta_insigth !! + // m_ptr->set_tag(m_tag); + } + m_ptr->add_ref(); + } ; + + inline void release() + { + if (!is_nul() ) + { + m_ptr->release(); + m_ptr = NULL; + } + } + inline bool is_nul() const {return m_ptr == NULL;}; + + intrusive_ptr & operator =(const intrusive_ptr &ht) + { + if (m_ptr) m_ptr->release(); + if (ht.m_ptr) + { + m_ptr = ht.m_ptr; + m_ptr->add_ref(); + } + return *this; + }; + + virtual ~intrusive_ptr() + { + if (m_ptr) + m_ptr->release(); + m_ptr = NULL; + }; + + const asn1::tag &tag() const + { + static asn1::tag t(0,0); + if (m_ptr) + m_ptr->tag(); + return t; + } + + bool primitive() const + { + if (m_ptr) + return m_ptr->primitive(); + return false; + } + + size_t get_length() const + { + if (m_ptr) + return m_ptr->get_length(); + return 0; + } + void encode(asn1::context &ctx) + { + if (m_ptr) + m_ptr->encode(ctx); + } + + int decode(asn1::context &ctx) + { + ASN1_BER_LOG_DEBUG("intrusive_ptr<>::decode DECODE m_ptr=%ld",(long)m_ptr); + if (m_ptr) + { + int ret = m_ptr->decode(ctx); + if ( ret != asn1::ok) + release(); + return ret; + } else + { + std::string name; + if (m_tag.byte() > 0) + { + m_ptr = new T(m_tag); + } else + m_ptr = new T(); + m_ptr->add_ref(); + name = typeid(*m_ptr).name(); + + int ret = this->m_ptr->decode(ctx); + if ( ret != asn1::ok) + release(); + return ret; + } + return asn1::unknown; + } + // + pointer operator *( ) { return m_ptr;}; + const pointer operator *( ) const{ return m_ptr;}; + // cast operator + operator T *( ) { return m_ptr;}; + + reference get() + { if (m_ptr == NULL ) create(m_tag); return *m_ptr; } + + reference get() const + { if (m_ptr == NULL ) assert(0); return *m_ptr; } + // + T* operator ->() {return m_ptr;}; + const T* operator ->() const {return m_ptr;}; + + friend std::ostream & operator<<(std::ostream &os,const intrusive_ptr &t) + { + if (! t.is_nul()) + { + os<<"OPT"<<(*t.m_ptr); + } else + os<<" null "; + return os; + } + protected: + pointer m_ptr; + asn1::tag m_tag; +}; + + + + // Generic class for object handling. +// Not yet clear about how this will work. +struct Object { + public: + typedef asn1::intrusive_ptr ptr; + + Object() : m_ref(0) {/*std::cout<<"Build Object"< + void to_type(T &_t) + {_t = dynamic_cast(*this); }; + + template + void to_type(T *_t) + {_t = dynamic_cast(this); }; + private: + int m_ref; // Ref counting +}; + +struct ObjectSetEntry +{ + ObjectSetEntry *m_next; + Object *m_object; +}; + + +} +/* +vim:et:sw=2:ts=2: + */ +#endif diff --git a/rtasn1/asn1_tag.h b/rtasn1/asn1_tag.h new file mode 100644 index 0000000..7494778 --- /dev/null +++ b/rtasn1/asn1_tag.h @@ -0,0 +1,58 @@ +#ifndef ASN1_TAG_H__ +#define ASN1_TAG_H__ +#include +namespace asn1 +{ + +#define MAKE_TAG(CLS,C,ID ) ( (((CLS) & 0x03)<<6) |((C & 0x01)<<5) |((ID)&0x1F) ) +/* Don't use constructed info for tag comparisen */ +#define MAKE_LONG_TAG(CLS,C,ID ) ( (((CLS) & 0x03)) |((ID)<<2) ) + /** + * + * The form below is the BER encoding. + * 8 7 6 5 4 3 2 1 + * class | P/C | Tag Identifier + */ +struct tag +{ + public: + inline void set_constructed() { m_constructed = true;}; + + tag(int cls,int id,bool _c = false) : m_class(cls), m_id(id) ,m_constructed(_c) {}; + tag(unsigned char c) : m_class(0),m_id(0),m_constructed(false) { byte(c);}; + tag(const tag &_t) : m_class(_t.m_class), m_id(_t.m_id) ,m_constructed(_t.m_constructed) {}; + + inline int get_class() const {return m_class; }; + + inline int get_id() const {return m_id; }; + + inline long get_tag() const {return ((m_id<<2) | m_class); }; + + inline bool get_constructed() const {return m_constructed; }; + + bool operator ==(const tag & t) const + { return m_id == t.m_id && m_class == t.m_class;} + + bool operator ==(long l) const + { + return (m_id == (l>>2)) && (m_class == (l & 0x03)); + } + + inline void byte(const unsigned char c) { + m_class = (0xC0 & c)>>6; + m_id = (0x1F & c); + m_constructed = ((0x20&c)>>5) > 0; + }; + + // Don't use this function to be able to process tag numbers > 30 + inline unsigned char byte() const + { return MAKE_TAG(m_class,m_constructed,m_id); }; + protected: + int m_class; + int m_id; + bool m_constructed; +}; + +} + +#endif diff --git a/rtasn1/asn1_types.cpp b/rtasn1/asn1_types.cpp new file mode 100644 index 0000000..3a05922 --- /dev/null +++ b/rtasn1/asn1_types.cpp @@ -0,0 +1,1164 @@ +#include +#include +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_errors.h" +#include "asn1_types.h" +#include "rtasn1/asn1_context.h" +#include "rtasn1/asn1_codec_ber.h" +#include +namespace asn1 { + + +// Object Identifier +std::ostream & operator << (std::ostream &os,const ObjectIdentifier &o) +{ + os<<"{"<(o)<<"}"; + return os; +} + +} /* end namespace */ +/** + * REAL BEGIN + */ +namespace asn1 { +namespace types { + + +int debug_level = 1; + +// Local static functions +// computes the number of bits required for the given number (positive) +size_t count_bits(unsigned range) +{ + switch (range) + { + case 0 : + return sizeof(unsigned)*8; + case 1: + return 1; + } + size_t _bits = 0; + while (_bits < (sizeof(unsigned)*8) && range > (unsigned)(1 << _bits)) + _bits++; + return _bits; +} +/* test */ +const tag gTags[] = { + tag(1,1) + , tag(2,0) +}; + +/////////////////////////////////////////////////////////////////////////////// +// CLASS type implementation +/////////////////////////////////////////////////////////////////////////////// + + +type::type(int c ,int tid) + : m_ref(0) , m_tag(c,tid) +{ +} + +type::type(const asn1::tag &t) + : m_ref(0) , m_tag(t) +{ +} + +type::type(const type &t) + : m_ref(0), m_tag(t.m_tag) +{ + ; +} + +type::~type() +{ +} +#if 0 + inline void add_ref() {m_ref++;} + + inline void release() {if (--m_ref == 0) delete this;} +#endif +bool type::primitive() const +{ + return true; +} +#if 0 +int +type::get_data_length() const +{ + return 0; +} +#endif +void type::set_tag(const asn1::tag &t) +{ + if (!this->primitive()) + { + m_tag = asn1::tag(t.get_class(),t.get_id(),true); + } else + m_tag = t; +} + +type * +type::clone() +{ + std::cerr<<"asn1::types::type::clone ERROR type here not good "< 0) + { + return m_tag; + } + else + return t; +} + +void +type::printf(std::ostream &os) const +{ + os<<"type::printf TODO"; +} + +size_t +type::get_length() const +{ + size_t len = 1; + if (m_tag.get_id() > 31) + len += (count_bits(m_tag.get_id())+6)/7; + // add data_len field + size_t data_len = get_data_length(); + if (data_len < 128) + len+= 1; + else + len+= (count_bits(data_len)+7)/8 + 1; + // return tag + len + data_len + return len + data_len; +} + + +/** + * used by decode functions + * + */ +long length(unsigned char *buf, long *readed) +{ + long result = 0; + long nb_octet = *buf & 0x7f; + *readed = 1; + if ((*buf & 0x80) && (*buf & 0x7F)) { + // Long form number ... + *readed = (*buf & 0x7F) + 1; + buf++; + // ASN1_BER_LOG_DEBUG("ber::length nb_octet %d form :result = %ld readed=%ld buf-1=%02x buf=%02x",nb_octet,result,*readed,*(buf-1),*buf); + while (nb_octet-- ) { + result = (result<<8) | (*buf) ; + buf++; + } + ASN1_BER_LOG_DEBUG("asn1::types::length long form : value=%ld readed=%ld ",result,*readed); + return result; + } else if (!(*buf & 0x80) && (*buf & 0x7F)){ + result = *buf & 0x7F; + // Short one byte + *readed = 1; + ASN1_BER_LOG_DEBUG("asn1::types::length short form :result=%ld readed=%ld",result,*readed); + return result; + } else if (*buf == 0) { + *readed = 1; + ASN1_BER_LOG_DEBUG("asn1::types::length: 0 "); + return 0; + }else { + // Indefinit form + std::cerr<<"asn1::types::length indefinit form not yet supported TO BE CODED"<encode(ctx); + ctx.encode_any(*this); +} + +// +// +int +any_type::decode(asn1::context &ctx) +{ + if (m_any ) + return m_any->decode(ctx); + std::cerr<<"any_type::decode TOBE CODED"<tag(); + } else + return m_tag; +} + +} // end of namespace types + +/////////////////////////////////////////////////////////////////////////////// +// prim encode/decode specialized implementations +/////////////////////////////////////////////////////////////////////////////// + +// Boolean +// +static tag BOOLEAN_tag_list[] = { + tag(asn1::types::UNIVERSAL,1) +}; +const asn1::types::descriptor asn1::BOOLEAN::_meta = { + BOOLEAN_tag_list + , 1 + , NULL + , 0 + , NULL + , 0 +}; + +void BOOLEAN::encode(asn1::context &ctx) +{ + ctx.encode_boolean(*this); +} + + +int BOOLEAN::decode(asn1::context &ctx) +{ + return ctx.decode_boolean(*this); +} + + +// Integer +static tag INTEGER_tag_list[] = { + tag(asn1::types::UNIVERSAL,2) +}; +const asn1::types::descriptor asn1::INTEGER::_meta = { + INTEGER_tag_list + , 1 + , NULL + , 0 + , NULL + , 0 +}; +size_t INTEGER::get_data_length() const +{ + long value = m_Prim.get_value(); + int shift = (sizeof(value)-1)*8-1; + + // remove all sequences of nine 0's or 1's at the start of the value + while (shift > 0 && ((value >> shift)&0x1ff) == (value < 0 ? 0x1ff : 0)) + shift -= 8; + + return (shift+9)/8; +} + +void INTEGER::encode(asn1::context &ctx) +{ + ctx.encode_integer(*this); +} +int INTEGER::decode(asn1::context &ctx) +{ + return ctx.decode_integer(*this); +} + +// UInt64 +static tag UInt64_tag_list[] = { + tag(asn1::types::UNIVERSAL,2) +}; +const asn1::types::descriptor asn1::UInt64::_meta = { + UInt64_tag_list + , 1 + , NULL + , 0 + , NULL + , 0 +}; +/** + * I have an issue when running tests on 64Bits architecture. + * For limits DWORD eg 0xFFFFFFFF the number of bytes is 5! + * I need to figure out what's wrong + * anyway, there is an issue. Both methods return the same value. + */ +size_t UInt64::get_data_length() const +{ +#if 1 + long long value = m_Prim.get_value(); + int intsize = sizeof(value); + //int intsize = 4; + long long mask = ((long long)0x1FF << ((intsize -1 )*8 - 1)); // Shift 8 *3 - 1 ? 0xFF800000 + std::cerr<<"value="<tag().get_id() ) + { + m_len = types::length(&b[pos],&nb); + ASN1_BER_LOG_DEBUG("OID decode len=%ld nb=%ld",m_len,nb); + ctx.nb_bits((m_len<<3)+ (nb<<3)+8); + if (m_len > MAX_OID_LEN) + { + ASN1_BER_LOG_ERROR(" ObjectIdentifier::decode len_exceed max %ld",m_len); + } + memcpy(m_oid,&b[pos+nb],(m_len>MAX_OID_LEN)?MAX_OID_LEN:m_len); + } else + { + ASN1_BER_LOG_DEBUG("ObjectIdentifier::decode FAILED bad tag %d expected 6 check_tag=%d" ,tg.get_id(),ctx.check_tag()); + return asn1::wrong_tag; + } + return asn1::ok; +} + + +// OBJECT IDENTIFIER_NG +void OBJECT_IDENTIFIER_NG::encode(asn1::context &ctx) +{ + unsigned long pos = ctx.bytes(); + unsigned char *b = ctx.buffer(); + asn1::tag &tg= const_cast(tag()); + b[pos] = tg.byte(); + ctx.nb_bits(8); + + ASN1_BER_LOG_DEBUG("OID encode size=%zu",m_Prim.get_oid_length()); + unsigned long ipos = pos; + b[++pos] = m_Prim.get_oid_length(); + for (int it = 0 ; it < m_Prim.get_oid_length() ;it++) + { + b[++pos] = m_Prim.get_value()[it]; + } + ctx.nb_bits((pos-ipos+1)<<3); // * 8 +} + +int OBJECT_IDENTIFIER_NG::decode(asn1::context &ctx) +{ + unsigned long pos = ctx.bytes(); + unsigned char *b = ctx.buffer(); + asn1::tag tg(0,0); + tg.byte(b[pos]); + pos++; + long nb = 0; + if (tg.get_id() == this->tag().get_id() ) + { + int m_len = types::length(&b[pos],&nb); + ASN1_BER_LOG_DEBUG("OID decode len=%ld nb=%ld" + , m_Prim.get_oid_length(),nb); + ctx.nb_bits((m_Prim.get_oid_length()<<3) + (nb<<3) + 8); + m_Prim.from_string(m_len,(char *)&b[pos+nb]); + } else + { + ASN1_BER_LOG_DEBUG("DECODE OID FAILED bad tag %d expected 6 check_tag=%d" ,tg.get_id(),ctx.check_tag()); + return asn1::wrong_tag; + } + return asn1::ok; +} + + + +// Enumeration +static tag ENUMERATED_tag_list[] = { + tag(asn1::types::UNIVERSAL,10) +}; +const asn1::types::descriptor asn1::ENUMERATED::_meta = { + ENUMERATED_tag_list + , 1 + , NULL + , 0 + , NULL + , 0 +}; +size_t ENUMERATED::get_data_length() const +{ + return 1; +} + +void ENUMERATED::encode(asn1::context &ctx) +{ + ASN1_BER_LOG_DEBUG("prim<0,10,Integer>(ENUMERARED)::encode tag=%d",tag().byte()); + ctx.encode_integer(*this); +} + +int ENUMERATED::decode(asn1::context &ctx) +{ + INTEGER i(this->tag()); + ASN1_BER_LOG_DEBUG("prim<0,10,Integer>(ENUMERARED)::decode"); + int ret = ctx.decode_integer(i); + if (ret == asn1::ok) { + ASN1_BER_LOG_DEBUG("prim<0,10,Integer>(ENUMERARED)::decode assign %ld to m_" + ,i.get_value().get_value()); + m_Prim = i.get_value(); + } + return ret; +} +#ifdef ASN1_TYPE_CLS +#undef ASN1_TYPE_CLS +#endif +#define ASN1_TYPE_CLS(p,cls,tg,typ) \ +tag typ##_tag_list[] = { \ + tag(cls,tg) \ +}; \ +const asn1::types::descriptor asn1::typ::_meta = { \ + typ##_tag_list \ + , 1 \ + , NULL \ + , 0 \ + , NULL \ + , 0 \ +}; \ +typ &typ::operator =(const char *s) \ +{ \ + m_Prim = std::string(s); \ + return *this; \ +} \ +size_t typ::get_data_length() const \ + { return get_value().size() ; } \ +void typ::encode(asn1::context &ctx) \ +{ \ + ctx.encode_string(*this); \ +} \ +int typ::decode(asn1::context &ctx) \ +{ \ + return ctx.decode_string(*this); \ +} + +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,12,UTF8String) +// tag 13 is RELATIVE_OID +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,18,NumericString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,19,PrintableString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,20,TeletexString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,21,VideotexString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,22,IA5String) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,25,GraphicString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,26,VisibleString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,27,GeneralString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,29,UniversalString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,30,BMPString) + +// GeneralizedTime +static tag GeneralizedTime_tag_list[] = { + tag(asn1::types::UNIVERSAL,24) +}; +const asn1::types::descriptor asn1::GeneralizedTime::_meta = { + GeneralizedTime_tag_list + , 1 + , NULL + , 0 + , NULL + , 0 +}; +void GeneralizedTime::encode(asn1::context &ctx) +{ + //ctx.encode_octetstring(*this); +} +int GeneralizedTime::decode(asn1::context &ctx) +{ + return asn1::wrong_tag; + //return ctx.decode_string(*this); +} + +// UTCTime +static tag UTCTime_tag_list[] = { + tag(asn1::types::UNIVERSAL,23) +}; +const asn1::types::descriptor asn1::UTCTime::_meta = { + UTCTime_tag_list + , 1 + , NULL + , 0 + , NULL + , 0 +}; +void UTCTime::encode(asn1::context &ctx) +{ + //ctx.encode_octetstring(*this); +} +int UTCTime::decode(asn1::context &ctx) +{ + return asn1::wrong_tag; + //return ctx.decode_string(*this); +} + + +// Null +void EXTERNAL::encode(asn1::context &ctx) +{ + ASN1_BER_LOG_DEBUG("EXTERNAL::encode TODO"); +} + +int EXTERNAL::decode(asn1::context &ctx) +{ + ASN1_BER_LOG_DEBUG("EXTERNAL::decode TODO"); + return asn1::wrong_tag; +} +/////////////////////////////////////////////////////////////////////////////// +// prim codec specialized implementations +/////////////////////////////////////////////////////////////////////////////// + + +// REAL; +static tag REAL_tag_list[] = { + tag(asn1::types::UNIVERSAL,9) +}; +const asn1::types::descriptor asn1::REAL::_meta = { + REAL_tag_list + , 1 + , NULL + , 0 + , NULL + , 0 +}; +void REAL::encode(asn1::context &ctx) +{ + ASN1_BER_LOG_DEBUG("REAL::encode TODO"); + +} + +int REAL::decode(asn1::context &ctx) +{ + ASN1_BER_LOG_DEBUG("REAL::decode TODO"); + return asn1::ok; +} + +// +//ENUMERATED; +namespace types { + +////////////////////////////////////////////////////////////////// + +/** + * + */ +choice_type::choice_type( unsigned int k + , const asn1::tag &t + , const descriptor *_d + ) + : m_kind(k), m_choice(NULL) + , asn1::types::type(t) + , m_desc(_d) +{ +// ASN1_BER_LOG_DEBUG("choice_type(%p)::choice_type(%d) ",this,m_kind ); +} + +choice_type::choice_type(const asn1::tag &t,const descriptor *_d) + : m_kind(t.get_tag()), m_choice(NULL),asn1::types::type(t) + , m_desc(_d) +{ +// ASN1_BER_LOG_DEBUG("choice_type::choice_type(%d) ",m_kind ); +} + +choice_type::choice_type(const choice_type &t) : m_kind(t.m_kind) + , asn1::types::type(t) + , m_choice(NULL) + , m_desc(t.m_desc) +{ + ASN1_BER_LOG_DEBUG("choice_type::choice_type(const choice_type &) t.m_choice=%p m_kind=%d tag=%ld" + ,t.m_choice,t.m_kind,t.m_tag.get_tag() ); + if (this == &t) + { + return; + } + if (t.m_choice) + { + m_tag = t.m_tag; + m_choice = t.m_choice->clone(); + } else + { + m_tag = t.m_tag; + m_choice = NULL; + } + +} + +/** + * + */ +bool choice_type::get_object() +{ + return this->create_object(); + +} + + +size_t choice_type::get_data_length() const +{ + if (m_choice) + return m_choice->get_data_length(); + assert(0 && " choice_type::get_data_length nothing selected") ; + return 0; +} + +// Get the current member. NULL if not found +member_desc * +choice_type::get_member() const +{ + int _count = 0; + assert((m_desc != NULL) && "mdesc should always be initialized not NULL."); + for ( ; _count < m_desc->m_t2elcount ; _count++) + { + if (m_tag.get_tag() == m_desc->m_t2el[_count].m_tag ) + { + return &m_desc->m_members[m_desc->m_t2el[_count].m_elidx]; + } + } + return NULL; +} + +bool choice_type::check_create() +{ + ASN1_BER_LOG_DEBUG("choice_type(%p)::check_create kind=%d tag=%ld",this,m_kind,m_tag.get_tag() ); + if (m_choice != NULL) + return true; + if ( create_object() ) + { + member_desc *m = get_member() ; + if (m && ( m->m_tmode == 1) ) + { + ASN1_BER_LOG_DEBUG("choice_type(%p)::check_create kind=%d tag=%ld EXPLICIT No tag propagation" + ,this,m_kind,m_tag.get_tag() ); + return true; + } + if (m_tag.byte() != 0) + { + m_choice->set_tag(m_tag); + } + return true; + } + std::cerr<<"choice_type::check_create "<clone(); + std::string x = typeid(*m_choice).name(); + std::string xo = typeid(*c.m_choice).name(); + ASN1_BER_LOG_DEBUG("choice_type::operator = kind=%d tg=%d m_choice %s = %s" + ,m_kind + ,m_tag.byte() + ,x.c_str() + ,xo.c_str()); + } else + { +#ifdef DEBUG + ASN1_BER_LOG_DEBUG("choice_type::operator = c.m_choice is nul for %s",name.c_str() ); +#endif + } + } else + { +#ifdef DEBUG + ASN1_BER_LOG_DEBUG("choice_type::operator = copy to myself go awayof %s",name.c_str() ); +#endif + } + return *this; +} + +/** + * + */ +bool choice_type::operator == (const choice_type &_c) const +{ +#ifdef DEBUG + std::string name = typeid(*this).name(); + ASN1_BER_LOG_DEBUG("choice_type::operator == %s",name.c_str() ); +#endif + return false; +} + +/** + * + */ +choice_type::~choice_type() { +// ASN1_BER_LOG_DEBUG("choice_type::~choice_type delete %d",m_kind); + if (m_choice) + delete m_choice; +} + +/** + * + */ +bool choice_type::primitive() const +{ + if (m_choice) + return m_choice->primitive(); + return true; +} +const asn1::tag &choice_type::tag() const +{ + if (m_choice) + return m_choice->tag(); + return type::tag(); +} + +void +choice_type::set_tag(const asn1::tag &t) +{ + ASN1_BER_LOG_DEBUG("choice_type(%p)::set_tag kind=%d class=%d id=%d" + , this + , m_kind + , t.get_class() + , t.get_id() ); + if (m_choice) + delete m_choice; + m_choice = NULL; + // Is this always correct ? Most of the time. Don't remove + // Until you come out with a better idea + m_kind = t.get_tag( ) ; + asn1::types::type::set_tag(t); + if (this->create_object() ) + { + member_desc *m = get_member() ; + if (m && ( m->m_tmode == 1) ) + { + ASN1_BER_LOG_DEBUG( "choice_type(%p)::set_tag EXPLICIT dont' propagate" + , this + ); + return ; + } + m_choice->set_tag(t); + } +} +// New way +void choice_type::encode(asn1::context &ctx) +{ + ASN1_BER_LOG_DEBUG("choice_type::encode delegate to ctx " ); + ctx.encode_choice(*this); +} + +int choice_type::decode(asn1::context &ctx) +{ + std::string name = typeid(*this).name(); + std::string name1; + if ( m_choice != NULL) + { + name1 = typeid(*m_choice).name(); + delete m_choice ; + m_choice = NULL; + } else + name1 = "NULL"; + ASN1_BER_LOG_DEBUG("choice_type::decode %s m_choice is %s (deleted) delegate to ctx",name.c_str(),name1.c_str() ); + if ( m_choice && (dynamic_cast(m_choice) == NULL)) + { + ASN1_BER_LOG_DEBUG("choice_type::decode %s delegate to ctx NOT A CHOICE ",name.c_str() ); + return m_choice->decode(ctx); + } + return ctx.decode_choice(*this); +} + + // New way specific for ber +void choice_type::encode_ber(asn1::streams::ber &ctx) +{ + unsigned long m_pos = ctx.bytes(); + unsigned char *m_buffer = ctx.buffer(); + if (m_choice) + m_choice->encode(ctx); + m_buffer[m_pos++] = this->tag().byte(); +} + +int choice_type::decode_ber(asn1::streams::ber &ctx) +{ + asn1::tag t(0,0); + std::string name = typeid(*this).name(); + unsigned long m_pos = ctx.bytes(); + unsigned char *m_buffer = ctx.buffer(); + int len = 0; + ASN1_BER_LOG_DEBUG("choice_type::decode_ber %s stream tag = %d" + , name.c_str() + , m_buffer[m_pos] + ); + + if (ctx.decode_tag(t,len) ) + { + set_tag(t); + if (check_create()) + { + std::string name = typeid(*this).name(); + std::string name1 = typeid(*m_choice).name(); + // Very ugly .... If m_choice is of type Choice + // It must be an explicit tag, Should be handled by parser + member_desc *m = get_member() ; + if (m && ( m->m_tmode == 1) ) + { + std::cerr<<"choice_type::"<<__FUNCTION__<<" "<decode(ctx); + if (res != asn1::ok) + { + ASN1_BER_LOG_ERROR("choice_type(%s)::decode_ber m_choice(%s)->decode failed tag = %d pos=%lu but tag was correct %d" + ,name.c_str() + ,name1.c_str() + ,t.byte() + , m_pos + , m_choice->tag().byte() + ); + ctx.bytes(m_pos); + } + return res; + } else + { + ASN1_BER_LOG_ERROR("choice_type::decode_ber Failed %s tag=%d check create did not work",name.c_str(),t.byte() ); + } + } + ctx.bytes(m_pos); + ASN1_BER_LOG_ERROR("choice_type::decode_ber Failed " ); + return asn1::unknown; +} + +void choice_type::printf(std::ostream &os) const +{ + if (m_choice) + { + member_desc *m = get_member() ; + os<m_name<<" :"; + m_choice->printf(os); + } +} + +/** + * implement sequence + */ +sequence_type::sequence_type(const asn1::tag &t) : asn1::types::type(t) +{ +} + + + +sequence_type::~sequence_type() +{ +} + + +sequence_type & sequence_type::operator = (const sequence_type &c) +{ + return *this; +} + + +bool +sequence_type:: primitive() const +{ + return false; +} + + +const asn1::tag &sequence_type::tag() const +{ + ASN1_BER_LOG_DEBUG("sequence_type::tag return %d ",type::tag().byte() ); + return type::tag(); +} + +size_t sequence_type::get_data_length() const +{ + assert (0) ; +} + // New way +void sequence_type::encode_preamble(asn1::context &ctx) +{ + m_pos = ctx.bytes(); + m_buffer = ctx.buffer(); + ctx.encode_sequence_preamble(*this); +} + +void sequence_type::encode_preamble_ber(asn1::context &ctx) +{ + m_pos = ctx.bytes(); + m_buffer = ctx.buffer(); + m_buffer[m_pos++] = this->tag().byte(); + ctx.nb_bits(16); // tag done +} + +void sequence_type::encode_epilogue_ber(asn1::context &ctx) +{ + unsigned long len = ctx.bytes() - m_pos - 1; + m_buffer[m_pos] = len; +} + +int sequence_type::decode_preamble_ber(asn1::streams::ber &ctx) +{ + return asn1::ok; +} + +int sequence_type::decode_epilogue_ber(asn1::streams::ber &ctx) +{ + return asn1::ok; +} + +/** + * Generic encoding decoding + */ +void sequence_type::encode_epilogue(asn1::context &ctx) +{ + ctx.encode_sequence_epilogue(*this); +} + + +int sequence_type::decode_preamble(asn1::context &ctx) +{ + int len; + m_pos = ctx.bytes(); + m_buffer = ctx.buffer(); + asn1::tag &tg= const_cast(tag()); + return ctx.decode_sequence_preamble(*this); +} + +int sequence_type::decode_epilogue(asn1::context &ctx) +{ + unsigned long len = ctx.bytes() - m_pos - 1; + return ctx.decode_sequence_epilogue(*this); +} + + +void sequence_type::encode(asn1::context &ctx) +{ + encode_preamble(ctx); +} + +int sequence_type::decode(asn1::context &ctx) +{ + return decode_preamble(ctx); +} + + + +// End of namespace types +} + + +}; diff --git a/rtasn1/asn1_types.h b/rtasn1/asn1_types.h new file mode 100644 index 0000000..16ac1f7 --- /dev/null +++ b/rtasn1/asn1_types.h @@ -0,0 +1,1098 @@ +#ifndef ASN1_TYPES_H__ +#define ASN1_TYPES_H__ +#include +#include + +#include "rtasn1/asn1_errors.h" + +#define MEMBER_OFFSET(cls,mbr) ((ptrdiff_t)&(((cls *)0)->mbr) - (ptrdiff_t)((cls *)0)) + +namespace asn1 +{ + class context; + class codecJER; + class codecBER; + class codecOER; +} + +namespace asn1 { + +/* basic types that will be used by codecs, and so on */ +typedef unsigned char byte; /* 8 bits data */ +typedef unsigned short word; /* 16 bits data */ + + +namespace types { + +//int debug_level; + +typedef enum { + UNIVERSAL, + APPLICATION, + CONTEXT_SPECIFIC, + PRIVATE +} tag_class; + + +/** + * The descriptors below are provided for choice because I was unable to + * come up with code that would work properly due to implicit / explicit + * tagging. + * I might considerer using this structures for set and sequence as well. + */ +struct member_desc; +struct tag2member_desc; +enum type_flags { + TF_NONE , + TF_POINTER = 0x01, + TF_SHARED_POINTER = 0x02, + TF_OPEN_TYPE = 0x04 +}; +struct descriptor { + tag *m_tags; + unsigned int m_tagcount; + /** + * For Sequence, Set and Choice + */ + struct member_desc *m_members; /* array of member descriptors */ + int m_elcount; /* number of elements in struct */ + struct tag2member_desc *m_t2el; /* */ + long m_t2elcount; /* number of elements in t2el arr */ +}; + + +struct member_desc { + enum type_flags m_flags; + long m_tmode; /* tag mode EXPLICIT(1) or IMPLICIT(-1) */ + long m_tag; /* tag value id<<2 |class */ + int m_member_offser; /* Member offset */ + long m_midx; /* member index is structure */ + struct descriptor *m_type; /* member type descriptor */ + const char *m_name; /* member str name for display */ +}; + +/** + * Most of the time m_kind == m_tag + */ +struct tag2member_desc { + long m_tag; /* tag of the element */ + long m_kind; /* This is a bit confusing.. */ + int m_elidx; /* element index for the tag */ +}; + +/** + * + */ +enum constraint_type { + un_constrained = 0 + , partial_constrained + , fixed_constrained + , extendable_constrained +}; + +struct constraint_desc { + constraint_type m_t; + long m_l; + long m_u; +}; + +/** Functions + * - length will go + * - count_bits will be used to compute the length of an integer + * + */ +long length(unsigned char *buf, long *_read); + +size_t count_bits(unsigned int val); + +/** + * @brief top class for asn1 types. + */ +class type +{ + protected: + type(const type &t) ; + + public: + type(int c = 0,int tid=0) ; + + type(const asn1::tag &t) ; + + virtual ~type() ; + // For the intrusive pointer managment + inline void add_ref() + {m_ref++;} + + inline void release() + {if (--m_ref == 0) delete this;} + + virtual bool primitive() const ; + // Return length of encoded type tag + len + data + size_t get_length() const; + // return only data length. Can'e declare + // as pure virtual because og object and objectclass templates + virtual size_t get_data_length() const + { return 0;} + virtual void set_tag(const asn1::tag &t) ; + + + // Needed for copy constructor choice + virtual type *clone() ; + + // encoding / decoding mechanism. + + virtual void encode(asn1::context &ctx) ; + + virtual int decode(asn1::context &ctx) ; + + virtual bool equal(const type &c) + { + std::cerr<<"type::equal should not be called"<(this)->get_prim(); }; +}; + +/** + * container The fact that is a template and contains a + * vector is not really how it should be. + * Constructed types are sequences, choice, and any. This type + * should only be used for user interfaces. + */ +template +class container : public asn1::types::type +{ + public: + typedef T prim_type; + typedef T type; + typedef typename std::vector items; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + + inline container(const asn1::tag &t) + : asn1::types::type(t) + { +#if 0 + std::cerr<<"container::container(t="<<(int)t.byte()<<")\n"; + std::cerr<<"Liste size="< &c) + { + std::cout<<"cp :"< &c) + { +#if 0 + std::cout<<"container::cp copy " <m_tag.byte() != 0) + { + return m_tag; + } + else + return t; + }; + + size_t size() const + { + return m_.size(); + } + void resize(size_t t) + { + m_.resize(t); + } + void printf(std::ostream &os) const + { + int count = 0; + const_iterator mit = begin(); + os << " container "< The constructor should use a tag and build the + * appropriate object according to the tag. + */ +class any_type : public asn1::types::type +{ + protected: + asn1::types::type *m_any; + public: + any_type(asn1::types::type *v = NULL); + + any_type(const asn1::types::type &v); + + ~any_type(); + // Cast operator + // operator T() {return *m_any;} + // const T* operator *() {return m_any;} + virtual size_t get_data_length() const + { return 0 ; } + + virtual void encode(asn1::context &ctx) ; + + virtual int decode(asn1::context &ctx) ; + + bool operator == (const any_type &_c) const ; + + virtual const asn1::tag &tag() const ; + + friend std::ostream &operator <<(std::ostream &os, const any_type &s) + { + //os<<" tag("< { +/* In namespace asn1 */ +#define ASN1_TYPE_CLS_GEN(parent,typ,cls,tg,asn1t) \ + class asn1t : \ + public asn1::types::parent { \ + protected: \ + typ m_Prim; \ + public: \ + typedef typ prim_type; \ + typedef typ* prim_type_pointer; \ + typedef typ& prim_type_reference; \ + typedef const typ& prim_type_const_reference;\ + ~asn1t() {} \ + asn1t(const asn1::tag &t = asn1::tag(cls,tg)) \ + : asn1::types::parent(t) \ + {}; \ + asn1t(const asn1t &v) \ + : m_Prim(v.m_Prim) , asn1::types::parent(v.m_tag) \ + { } ; \ + inline asn1t(const typ &c) \ + : asn1::types::parent(asn1::tag(cls,tg)) \ + , m_Prim(c) \ + { }; \ + inline asn1t(const typ::prim_type &c) \ + : asn1::types::parent(asn1::tag(cls,tg)) \ + , m_Prim(c) \ + { }; \ + \ + prim_type get_value() const \ + { \ + return m_Prim; \ + } \ + prim_type_reference get_value() \ + { \ + return m_Prim; \ + } \ + prim_type::prim_type get_sys_value() const \ + { \ + return m_Prim.get_value(); \ + } \ + virtual asn1t *clone() \ + { \ + return new asn1t(*this); \ + }; /* Needed for copy constructor choice */ \ + /** */ \ + bool equal(const asn1::types::type &t) \ + { \ + const asn1t *c = dynamic_cast(&t); \ + std::cerr<<"prim::equal "<get_value(); \ + } else \ + return false ; \ + } \ + /** */ \ + inline asn1t &operator =(const asn1t &t) \ + { \ + m_Prim = t.m_Prim; return *this; \ + }; \ + \ + virtual const asn1::tag &tag() const \ + { \ + static asn1::tag t = asn1::tag(cls,tg); \ + if (m_tag.byte() > 0) \ + { \ + return m_tag; \ + } else return t; \ + }; \ + \ + /** Will be new way */ \ + virtual void encode(asn1::context &ctx); \ + \ + virtual int decode(asn1::context &ctx); \ + \ + virtual void printf(std::ostream &os) const \ + {os<<*this;}; \ + \ + friend std::ostream &operator <<(std::ostream &os, const asn1t &s)\ + { \ + os<<" tag("< + class Seq : public asn1::types::container + { + public: + typedef typename asn1::types::container::iterator iterator; + typedef typename asn1::types::container::const_iterator const_iterator ; + + Seq(const asn1::tag &t = asn1::tag(asn1::types::UNIVERSAL,16,true)) + : asn1::types::container(t) + { +// std::cerr<<"Seq::Seq(t="<<(int)t.byte()<<")\n"; + }; + Seq(const Seq &c) : + asn1::types::container(asn1::tag(c.tag())) + { +// std::cerr<<"Seq::Seq m_="<m_.size()<<" c:"<m_ = c.m_; +// std::cerr<<" After:"<m_.size()<(asn1::tag(asn1::types::UNIVERSAL,16,true)) + { +// std::cerr<<"Seq:: copy base :"<m_.size()<m_.push_back(c); + }; + + inline Seq &operator=(const Seq &c) + { + if (this != &c) + { + this->m_ = c.m_; + } + return *this; + } + + Seq &get_value() + { + return *this; + } + + const Seq &get_value() const + { + return *this; + } + + virtual Seq *clone() + { + return new Seq(*this); + } + + bool operator ==(const Seq &o) const + { + std::cerr<<"TODO implement Seq =="<::asn1::types::container::push_back(t); + }; + + inline iterator begin() + { return this->::asn1::types::container::begin(); }; + + inline const_iterator begin() const + { return this->::asn1::types::container::begin(); }; + + inline iterator end() + { return this->::asn1::types::container::end(); }; + + inline const_iterator end() const + { return this->::asn1::types::container::end(); }; + + inline T operator [](int i) + { return this->m_[i]; }; + + virtual ~Seq() ; + + virtual void encode(asn1::context &ctx); + virtual int decode(asn1::context &ctx); + + friend std::ostream &operator <<(std::ostream &os,const Seq &t) + { + int count = 0; + typename ::asn1::types::container::const_iterator mit= + const_cast &>(t).begin(); + os << "SEQUENCE OF"< &>(t).end(); + ++mit) + { + std::streamsize indent = os.precision() + 2; + os< + class Set : public asn1::types::container + { + public: + typedef typename asn1::types::container::iterator iterator; + typedef typename asn1::types::container::const_iterator const_iterator ; + Set(const asn1::tag &t = asn1::tag(asn1::types::UNIVERSAL,17,true)) + : asn1::types::container(t) + {}; + + virtual ~Set() {}; + + Set(const Set &c) : + asn1::types::container(asn1::tag(c.tag())) + { + this->m_ = c.m_; + } + inline Set &operator=(const Set &c) + { + this->m_ = c.m_; + return *this; + } + virtual Set *clone() + { + return new Set(*this); + } + + virtual size_t get_data_length() const + { return 0 ; } + + Set &get_value() { return *this; } + + const Set &get_value() const { return *this; } + + Set(const T &c) : + asn1::types::container(asn1::tag(asn1::types::UNIVERSAL,17)) + { + this->m_.push_back(c); + } + + bool operator ==(const Set &o) const + { + std::cerr<<"TODO implement Seq =="<::asn1::types::container::begin(); }; + + inline const_iterator begin() const + { return this->::asn1::types::container::begin(); } + + inline iterator end() + { return this->::asn1::types::container::end(); }; + + inline const_iterator end() const + { return this->::asn1::types::container::end(); }; + + virtual const asn1::tag &tag() const + { + return this->::asn1::types::container::tag(); + }; + + virtual void encode(asn1::context &ctx); + + virtual int decode(asn1::context &ctx); + + inline T operator [](int i) {return this->m_[i];}; + + friend std::ostream &operator <<(std::ostream &os,const Set &t) + { + int count = 0; + typename ::asn1::types::container::const_iterator mit= + const_cast &>(t).begin(); + for (; + mit != const_cast &>(t).end(); + ++mit) + os<<"SET OF ["< +Seq::~Seq() { + this->m_.erase(this->m_.begin(),this->m_.end()); +// ASN1_BER_LOG_DEBUG("Seq::~Seq SEQUENCE OF %s [size=%zu]",typeid(T).name(),this->m_.size()); + +}; + +template +void Seq::encode(asn1::context &ctx) +{ + iterator mit; + unsigned long pos = ctx.bytes(); + unsigned char *b = ctx.buffer(); + ASN1_BER_LOG_DEBUG("Seq::encode SEQUENCE-OF %s %s",typeid(T).name(),__FUNCTION__); + asn1::tag t_(0,16,true); + b[pos] = t_.byte() | 0x20; + ctx.nb_bits(16); + for (mit = begin(); + mit != end(); + ++mit) + { + ASN1_BER_LOG_DEBUG("Seq::encode call encode on item "); + (*mit).T::encode(ctx); + } + b[pos+1]= ctx.bytes()-pos-2; +} + +template +int Seq::decode(asn1::context &ctx) +{ + int ret = asn1::ok; + unsigned long pos = ctx.bytes(); + unsigned char *b = ctx.buffer(); + long llen = 0; + long i = 0; + long nb = 1; // I need to find a way to get the length + ASN1_BER_LOG_DEBUG("Seq::decode SEQUENCE-OF %s check_tag:%d b[pos]=%d b[pos+1]=%d b[pos+2]=%d",typeid(T).name(),ctx.check_tag(),b[pos], + static_cast(static_cast(b[pos+1])), + static_cast(static_cast(b[pos+2]))); + long len = asn1::types::length(&b[pos+1],&nb); + ctx.nb_bits(((nb)<<3)+8); + if (len == 0 ) + { + return 0; + } + do { + T element; + //ret = this->m_.back().decode(ctx); + ret = element.decode(ctx); + if (ret != asn1::ok) + break; + this->m_.resize(nb); + //this->m_.push_back(element); + this->m_[i++] = element; + nb++; + llen = ctx.bytes(); + } while ((llen-(long)pos) < len); + + if ((this->m_.size() == 0)) + { // Failed decoding .... + ctx.nb_bits(-1*(((nb)<<3)+8)); + } + ASN1_BER_LOG_DEBUG("Seq::decode SEQUENCE-OF %s %s GOT %lu END",typeid(T).name(),__FUNCTION__,this->m_.size()); + return ret; +} + +/** + * + */ +/** + * Set Template definition + */ +template +void Set::encode(asn1::context &ctx) +{ + iterator mit; + unsigned long pos = ctx.bytes(); + unsigned char *b = ctx.buffer(); + ASN1_BER_LOG_DEBUG("Set::encode SET-OF %s %s",typeid(T).name(),__FUNCTION__); + asn1::tag t_(0,17,true); + b[pos] = t_.byte() | 0x20; + ctx.nb_bits(16); + for (mit = begin(); + mit != end(); + ++mit) + { + ASN1_BER_LOG_DEBUG("Set::encode call encode on item "); + (*mit).encode(ctx); + } + b[pos+1]= ctx.bytes()-pos-2; +} + +template +int Set::decode(asn1::context &ctx) +{ + int ret = asn1::ok; + unsigned long pos = ctx.bytes(); + unsigned char *b = ctx.buffer(); + long llen = 0; + long i = 0; + long nb = 1; // I need to find a way to get the length + ASN1_BER_LOG_DEBUG("Set::decode SET-OF %s check_tag:%d b[pos]=%d b[pos+1]=%d b[pos+2]=%d",typeid(T).name(),ctx.check_tag(),b[pos], + static_cast(static_cast(b[pos+1])), + static_cast(static_cast(b[pos+2]))); + long len = asn1::types::length(&b[pos+1],&nb); + ctx.nb_bits(((nb)<<3)+8); + if (len == 0 ) + { + return 0; + } + do { + T element; + //ret = this->m_.back().decode(ctx); + ret = element.decode(ctx); + if (ret != asn1::ok) + break; + this->m_.resize(nb); + //this->m_.push_back(element); + this->m_[i++] = element; + nb++; + llen = ctx.bytes(); + } while ((llen-pos) < len); + + if ((this->m_.size() == 0)) + { // Failed decoding .... + ctx.nb_bits(-1*(((nb)<<3)+8)); + } + ASN1_BER_LOG_DEBUG("Set::decode SET-OF %s %s GOT %lu END" + ,typeid(T).name() + ,__FUNCTION__ + ,this->m_.size()); + return ret; +} + + +} diff --git a/rtasn1/asn1_types.inc b/rtasn1/asn1_types.inc new file mode 100644 index 0000000..863b7ac --- /dev/null +++ b/rtasn1/asn1_types.inc @@ -0,0 +1,39 @@ +#ifndef ASN1_TYPE_CLS +# define ASN1_TYPE_CLS(PrimType,TagType,TagNum,Asn1Type) +#endif + +ASN1_TYPE_CLS(asn1::prim::types::Boolean,asn1::types::UNIVERSAL,1,BOOLEAN) +ASN1_TYPE_CLS(asn1::prim::types::Integer,asn1::types::UNIVERSAL,2,INTEGER) +ASN1_TYPE_CLS(asn1::prim::types::Int8,asn1::types::UNIVERSAL,2,Int8) +ASN1_TYPE_CLS(asn1::prim::types::Int16,asn1::types::UNIVERSAL,2,Int16) +ASN1_TYPE_CLS(asn1::prim::types::Int32,asn1::types::UNIVERSAL,2,Int32) +ASN1_TYPE_CLS(asn1::prim::types::Int64,asn1::types::UNIVERSAL,2,Int64) +ASN1_TYPE_CLS(asn1::prim::types::UInt8,asn1::types::UNIVERSAL,2,UInt8) +ASN1_TYPE_CLS(asn1::prim::types::UInt16,asn1::types::UNIVERSAL,2,UInt16) +ASN1_TYPE_CLS(asn1::prim::types::UInt32,asn1::types::UNIVERSAL,2,UInt32) +ASN1_TYPE_CLS(asn1::prim::types::UInt64,asn1::types::UNIVERSAL,2,UInt64) +ASN1_TYPE_CLS(asn1::prim::types::BitString,asn1::types::UNIVERSAL,3,BIT_STRING) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,4,OCTET_STRING) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,4,STRING) +ASN1_TYPE_CLS(asn1::prim::types::Integer,asn1::types::UNIVERSAL,5,Null) +// ASN1_TYPE_CLS(asn1::prim::types::Integer,asn1::types::UNIVERSAL,6,OBJECT_IDENTIFIER) +ASN1_TYPE_CLS(asn1::prim::types::ObjectIdentifier,asn1::types::UNIVERSAL,6,OBJECT_IDENTIFIER_NG) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,8,EXTERNAL) +ASN1_TYPE_CLS(asn1::prim::types::UTCTime,asn1::types::UNIVERSAL,24,GeneralizedTime) +ASN1_TYPE_CLS(asn1::prim::types::UTCTime,asn1::types::UNIVERSAL,23,UTCTime) +ASN1_TYPE_CLS(asn1::prim::types::Real,asn1::types::UNIVERSAL,9,REAL) +ASN1_TYPE_CLS(asn1::prim::types::Integer,asn1::types::UNIVERSAL,10,ENUMERATED) +// typedef asn1::types::any_type ANY; +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,12,UTF8String) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,18,NumericString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,19,PrintableString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,20,TeletexString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,21,VideotexString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,22,IA5String) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,25,GraphicString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,26,VisibleString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,27,GeneralString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,29,UniversalString) +ASN1_TYPE_CLS(asn1::prim::types::String,asn1::types::UNIVERSAL,30,BMPString) + +#undef ASN1_TYPE_CLS diff --git a/rtasn1/cjson/LICENSE b/rtasn1/cjson/LICENSE new file mode 100644 index 0000000..fa0a438 --- /dev/null +++ b/rtasn1/cjson/LICENSE @@ -0,0 +1,20 @@ + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + diff --git a/rtasn1/cjson/README b/rtasn1/cjson/README new file mode 100644 index 0000000..7531c04 --- /dev/null +++ b/rtasn1/cjson/README @@ -0,0 +1,247 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +Welcome to cJSON. + +cJSON aims to be the dumbest possible parser that you can get your job done with. +It's a single file of C, and a single header file. + +JSON is described best here: http://www.json.org/ +It's like XML, but fat-free. You use it to move data around, store things, or just +generally represent your program's state. + + +First up, how do I build? +Add cJSON.c to your project, and put cJSON.h somewhere in the header search path. +For example, to build the test app: + +gcc cJSON.c test.c -o test -lm +./test + + +As a library, cJSON exists to take away as much legwork as it can, but not get in your way. +As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it +in one of two modes: Auto and Manual. Let's have a quick run-through. + + +I lifted some JSON from this page: http://www.json.org/fatfree.html +That page inspired me to write cJSON, which is a parser that tries to share the same +philosophy as JSON itself. Simple, dumb, out of the way. + +Some JSON: +{ + "name": "Jack (\"Bee\") Nimble", + "format": { + "type": "rect", + "width": 1920, + "height": 1080, + "interlace": false, + "frame rate": 24 + } +} + +Assume that you got this from a file, a webserver, or magic JSON elves, whatever, +you have a char * to it. Everything is a cJSON struct. +Get it parsed: + cJSON *root = cJSON_Parse(my_json_string); + +This is an object. We're in C. We don't have objects. But we do have structs. +What's the framerate? + + cJSON *format = cJSON_GetObjectItem(root,"format"); + int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint; + + +Want to change the framerate? + cJSON_GetObjectItem(format,"frame rate")->valueint=25; + +Back to disk? + char *rendered=cJSON_Print(root); + +Finished? Delete the root (this takes care of everything else). + cJSON_Delete(root); + +That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers +before you dereference them. If you want to see how you'd build this struct in code? + cJSON *root,*fmt; + root=cJSON_CreateObject(); + cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); + cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); + cJSON_AddStringToObject(fmt,"type", "rect"); + cJSON_AddNumberToObject(fmt,"width", 1920); + cJSON_AddNumberToObject(fmt,"height", 1080); + cJSON_AddFalseToObject (fmt,"interlace"); + cJSON_AddNumberToObject(fmt,"frame rate", 24); + +Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. +Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and +a few from elsewhere. + +What about manual mode? First up you need some detail. +Let's cover how the cJSON objects represent the JSON data. +cJSON doesn't distinguish arrays from objects in handling; just type. +Each cJSON has, potentially, a child, siblings, value, a name. + +The root object has: Object Type and a Child +The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: +Sibling has type Object, name "format", and a child. +That child has type String, name "type", value "rect", and a sibling: +Sibling has type Number, name "width", value 1920, and a sibling: +Sibling has type Number, name "height", value 1080, and a sibling: +Sibling hs type False, name "interlace", and a sibling: +Sibling has type Number, name "frame rate", value 24 + +Here's the structure: +typedef struct cJSON { + struct cJSON *next,*prev; + struct cJSON *child; + + int type; + + char *valuestring; + int valueint; + double valuedouble; + + char *string; +} cJSON; + +By default all values are 0 unless set by virtue of being meaningful. + +next/prev is a doubly linked list of siblings. next takes you to your sibling, +prev takes you back from your sibling to you. +Only objects and arrays have a "child", and it's the head of the doubly linked list. +A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0. +The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in +cJSON.h + +A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read +valuedouble. + +Any entry which is in the linked list which is the child of an object will have a "string" +which is the "name" of the entry. When I said "name" in the above example, that's "string". +"string" is the JSON name for the 'variable name' if you will. + +Now you can trivially walk the lists, recursively, and parse as you please. +You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take +the root object, and traverse the structure (which is, formally, an N-tree), +and tokenise as you please. If you wanted to build a callback style parser, this is how +you'd do it (just an example, since these things are very specific): + +void parse_and_callback(cJSON *item,const char *prefix) +{ + while (item) + { + char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2); + sprintf(newprefix,"%s/%s",prefix,item->name); + int dorecurse=callback(newprefix, item->type, item); + if (item->child && dorecurse) parse_and_callback(item->child,newprefix); + item=item->next; + free(newprefix); + } +} + +The prefix process will build you a separated list, to simplify your callback handling. +The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or +let you invoke it per-item. For the item above, your callback might look like this: + +int callback(const char *name,int type,cJSON *item) +{ + if (!strcmp(name,"name")) { /* populate name */ } + else if (!strcmp(name,"format/type") { /* handle "rect" */ } + else if (!strcmp(name,"format/width") { /* 800 */ } + else if (!strcmp(name,"format/height") { /* 600 */ } + else if (!strcmp(name,"format/interlace") { /* false */ } + else if (!strcmp(name,"format/frame rate") { /* 24 */ } + return 1; +} + +Alternatively, you might like to parse iteratively. +You'd use: + +void parse_object(cJSON *item) +{ + int i; for (i=0;ichild; + while (subitem) + { + // handle subitem + if (subitem->child) parse_object(subitem->child); + + subitem=subitem->next; + } +} + +Of course, this should look familiar, since this is just a stripped-down version +of the callback-parser. + +This should cover most uses you'll find for parsing. The rest should be possible +to infer.. and if in doubt, read the source! There's not a lot of it! ;) + + +In terms of constructing JSON data, the example code above is the right way to do it. +You can, of course, hand your sub-objects to other functions to populate. +Also, if you find a use for it, you can manually build the objects. +For instance, suppose you wanted to build an array of objects? + +cJSON *objects[24]; + +cJSON *Create_array_of_anything(cJSON **items,int num) +{ + int i;cJSON *prev, *root=cJSON_CreateArray(); + for (i=0;i<24;i++) + { + if (!i) root->child=objects[i]; + else prev->next=objects[i], objects[i]->prev=prev; + prev=objects[i]; + } + return root; +} + +and simply: Create_array_of_anything(objects,24); + +cJSON doesn't make any assumptions about what order you create things in. +You can attach the objects, as above, and later add children to each +of those objects. + +As soon as you call cJSON_Print, it renders the structure to text. + + + +The test.c code shows how to handle a bunch of typical cases. If you uncomment +the code, it'll load, parse and print a bunch of test files, also from json.org, +which are more complex than I'd care to try and stash into a const char array[]. + + +Enjoy cJSON! + + +- Dave Gamble, Aug 2009 diff --git a/rtasn1/cjson/cJSON.c b/rtasn1/cjson/cJSON.c new file mode 100644 index 0000000..31c43dd --- /dev/null +++ b/rtasn1/cjson/cJSON.c @@ -0,0 +1,596 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#include +#include +#include +#include +#include +#include +#include +#include "cJSON.h" + +static const char *ep; + +const char *cJSON_GetErrorPtr(void) {return ep;} + +static int cJSON_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} + +static void *(*cJSON_malloc)(size_t sz) = malloc; +static void (*cJSON_free)(void *ptr) = free; + +static char* cJSON_strdup(const char* str) +{ + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = (char*)cJSON_malloc(len))) return 0; + memcpy(copy,str,len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (!hooks) { /* Reset hooks */ + cJSON_malloc = malloc; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; + cJSON_free = (hooks->free_fn)?hooks->free_fn:free; +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(void) +{ + cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + if (node) memset(node,0,sizeof(cJSON)); + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_Delete(cJSON *c) +{ + cJSON *next; + while (c) + { + next=c->next; + if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); + if (c->string) cJSON_free(c->string); + cJSON_free(c); + c=next; + } +} + +/* Parse the input text to generate a number, and populate the result into item. */ +static const char *parse_number(cJSON *item,const char *num) +{ + double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; + + if (*num=='-') sign=-1,num++; /* Has sign? */ + if (*num=='0') num++; /* is zero */ + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ + if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ + if (*num=='e' || *num=='E') /* Exponent? */ + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ + } + + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ + + item->valuedouble=n; + item->valueint=(int)n; + item->type=cJSON_Number; + return num; +} + +/* Render the number nicely from the given item into a string. */ +static char *print_number(cJSON *item) +{ + char *str; + double d=item->valuedouble; + if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) + { + str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ + if (str) sprintf(str,"%d",item->valueint); + } + else + { + str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ + if (str) + { + if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } + } + return str; +} + +static unsigned parse_hex4(const char *str) +{ + unsigned h=0; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + h=h<<4;str++; + if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; + return h; +} + +/* Parse the input text into an unescaped cstring, and populate item. */ +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; + if (*str!='\"') {ep=str;return 0;} /* not a string! */ + + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ + + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ + if (!out) return 0; + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && *ptr) + { + if (*ptr!='\\') *ptr2++=*ptr++; + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': /* transcode utf16 to utf8. */ + uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ + + if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ + { + if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ + uc2=parse_hex4(ptr+3);ptr+=6; + if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ + uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); + } + + len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; + + switch (len) { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static char *print_string_ptr(const char *str) +{ + const char *ptr;char *ptr2,*out;int len=0;unsigned char token; + + if (!str) return cJSON_strdup(""); + ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} + + out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (token=*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +/* Invote print_string_ptr (which is useful) on an item. */ +static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} + +/* Predeclare these prototypes. */ +static const char *parse_value(cJSON *item,const char *value); +static char *print_value(cJSON *item,int depth,int fmt); +static const char *parse_array(cJSON *item,const char *value); +static char *print_array(cJSON *item,int depth,int fmt); +static const char *parse_object(cJSON *item,const char *value); +static char *print_object(cJSON *item,int depth,int fmt); + +/* Utility to jump whitespace and cr/lf */ +static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} + +/* Parse an object - create a new root, and populate. */ +cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) +{ + const char *end=0; + cJSON *c=cJSON_New_Item(); + ep=0; + if (!c) return 0; /* memory fail */ + + end=parse_value(c,skip(value)); + if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} + if (return_parse_end) *return_parse_end=end; + return c; +} +/* Default options for cJSON_Parse */ +cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} + +/* Render a cJSON item/entity/structure to text. */ +char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} +char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} + +/* Parser core - when encountering text, process appropriately. */ +static const char *parse_value(cJSON *item,const char *value) +{ + if (!value) return 0; /* Fail on null. */ + if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } + if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } + if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } + if (*value=='\"') { return parse_string(item,value); } + if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } + if (*value=='[') { return parse_array(item,value); } + if (*value=='{') { return parse_object(item,value); } + + ep=value;return 0; /* failure. */ +} + +/* Render a value to text. */ +static char *print_value(cJSON *item,int depth,int fmt) +{ + char *out=0; + if (!item) return 0; + switch ((item->type)&255) + { + case cJSON_NULL: out=cJSON_strdup("null"); break; + case cJSON_False: out=cJSON_strdup("false");break; + case cJSON_True: out=cJSON_strdup("true"); break; + case cJSON_Number: out=print_number(item);break; + case cJSON_String: out=print_string(item);break; + case cJSON_Array: out=print_array(item,depth,fmt);break; + case cJSON_Object: out=print_object(item,depth,fmt);break; + } + return out; +} + +/* Build an array from input text. */ +static const char *parse_array(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='[') {ep=value;return 0;} /* not an array! */ + + item->type=cJSON_Array; + value=skip(value+1); + if (*value==']') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; /* memory fail */ + value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_value(child,skip(value+1))); + if (!value) return 0; /* memory fail */ + } + + if (*value==']') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an array to text */ +static char *print_array(cJSON *item,int depth,int fmt) +{ + char **entries; + char *out=0,*ptr,*ret;int len=5; + cJSON *child=item->child; + int numentries=0,i=0,fail=0; + + /* How many entries in the array? */ + while (child) numentries++,child=child->next; + /* Explicitly handle numentries==0 */ + if (!numentries) + { + out=(char*)cJSON_malloc(3); + if (out) strcpy(out,"[]"); + return out; + } + /* Allocate an array to hold the values for each */ + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + /* Retrieve all the results: */ + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; + } + + /* If we didn't fail, try to malloc the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + /* If that fails, we fail. */ + if (!out) fail=1; + + /* Handle failure. */ + if (fail) + { + for (i=0;itype=cJSON_Object; + value=skip(value+1); + if (*value=='}') return value+1; /* empty array. */ + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; + value=skip(parse_string(child,skip(value))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_string(child,skip(value+1))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') {ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (!value) return 0; + } + + if (*value=='}') return value+1; /* end of array */ + ep=value;return 0; /* malformed. */ +} + +/* Render an object to text. */ +static char *print_object(cJSON *item,int depth,int fmt) +{ + char **entries=0,**names=0; + char *out=0,*ptr,*ret,*str;int len=7,i=0,j; + cJSON *child=item->child; + int numentries=0,fail=0; + /* Count the number of entries. */ + while (child) numentries++,child=child->next; + /* Explicitly handle empty object case */ + if (!numentries) + { + out=(char*)cJSON_malloc(fmt?depth+4:3); + if (!out) return 0; + ptr=out;*ptr++='{'; + if (fmt) {*ptr++='\n';for (i=0;ichild;depth++;if (fmt) len+=depth; + while (child) + { + names[i]=str=print_string_ptr(child->string); + entries[i++]=ret=print_value(child,depth,fmt); + if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; + child=child->next; + } + + /* Try to allocate the output string */ + if (!fail) out=(char*)cJSON_malloc(len); + if (!out) fail=1; + + /* Handle failure */ + if (fail) + { + for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} +cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +/* Utility for handling references. */ +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} + +/* Add item to array/object. */ +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} + +cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; + if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} +void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} + +/* Replace array/object items with new ones. */ +void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} + +/* Create basic types: */ +cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} + +/* Create Arrays: */ +cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} + +/* Duplication */ +cJSON *cJSON_Duplicate(cJSON *item,int recurse) +{ + cJSON *newitem,*cptr,*nptr=0,*newchild; + /* Bail on bad ptr */ + if (!item) return 0; + /* Create new item */ + newitem=cJSON_New_Item(); + if (!newitem) return 0; + /* Copy over all vars */ + newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; + if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} + if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} + /* If non-recursive, then we're done! */ + if (!recurse) return newitem; + /* Walk the ->next chain for the child. */ + cptr=item->child; + while (cptr) + { + newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) {cJSON_Delete(newitem);return 0;} + if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ + cptr=cptr->next; + } + return newitem; +} + +void cJSON_Minify(char *json) +{ + char *into=json; + while (*json) + { + if (*json==' ') json++; + else if (*json=='\t') json++; // Whitespace characters. + else if (*json=='\r') json++; + else if (*json=='\n') json++; + else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line. + else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments. + else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive. + else *into++=*json++; // All other characters. + } + *into=0; // and null-terminate. +} \ No newline at end of file diff --git a/rtasn1/cjson/cJSON.h b/rtasn1/cjson/cJSON.h new file mode 100644 index 0000000..867b7c3 --- /dev/null +++ b/rtasn1/cjson/cJSON.h @@ -0,0 +1,143 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* cJSON Types: */ +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +#define cJSON_IsReference 256 + +/* The cJSON structure: */ +typedef struct cJSON { + struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + + int type; /* The type of the item, as above. */ + + char *valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ + + char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ +} cJSON; + +typedef struct cJSON_Hooks { + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +/* Supply malloc, realloc and free functions to cJSON */ +extern void cJSON_InitHooks(cJSON_Hooks* hooks); + + +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ +extern cJSON *cJSON_Parse(const char *value); +/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ +extern char *cJSON_Print(cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ +extern char *cJSON_PrintUnformatted(cJSON *item); +/* Delete a cJSON entity and all subentities. */ +extern void cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +extern int cJSON_GetArraySize(cJSON *array); +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); +/* Get item "string" from object. Case insensitive. */ +extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +extern const char *cJSON_GetErrorPtr(void); + +/* These calls create a cJSON item of the appropriate type. */ +extern cJSON *cJSON_CreateNull(void); +extern cJSON *cJSON_CreateTrue(void); +extern cJSON *cJSON_CreateFalse(void); +extern cJSON *cJSON_CreateBool(int b); +extern cJSON *cJSON_CreateNumber(double num); +extern cJSON *cJSON_CreateString(const char *string); +extern cJSON *cJSON_CreateArray(void); +extern cJSON *cJSON_CreateObject(void); + +/* These utilities create an Array of count items. */ +extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); +extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); +extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); +extern cJSON *cJSON_CreateStringArray(const char **strings,int count); + +/* Append item to the specified array/object. */ +extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); +extern void cJSON_DeleteItemFromArray(cJSON *array,int which); +extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); +extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); + +/* Update array items. */ +extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); +extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ + +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); + +extern void cJSON_Minify(char *json); + +/* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rtasn1/cjson/test.c b/rtasn1/cjson/test.c new file mode 100644 index 0000000..b308a92 --- /dev/null +++ b/rtasn1/cjson/test.c @@ -0,0 +1,156 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include "cJSON.h" + +/* Parse text to JSON, then render back to text, and print! */ +void doit(char *text) +{ + char *out;cJSON *json; + + json=cJSON_Parse(text); + if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());} + else + { + out=cJSON_Print(json); + cJSON_Delete(json); + printf("%s\n",out); + free(out); + } +} + +/* Read a file, parse, render back, etc. */ +void dofile(char *filename) +{ + FILE *f=fopen(filename,"rb");fseek(f,0,SEEK_END);long len=ftell(f);fseek(f,0,SEEK_SET); + char *data=(char*)malloc(len+1);fread(data,1,len,f);fclose(f); + doit(data); + free(data); +} + +/* Used by some code below as an example datatype. */ +struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; }; + +/* Create a bunch of objects as demonstration. */ +void create_objects() +{ + cJSON *root,*fmt,*img,*thm,*fld;char *out;int i; /* declare a few. */ + + /* Here we construct some JSON standards, from the JSON site. */ + + /* Our "Video" datatype: */ + root=cJSON_CreateObject(); + cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); + cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); + cJSON_AddStringToObject(fmt,"type", "rect"); + cJSON_AddNumberToObject(fmt,"width", 1920); + cJSON_AddNumberToObject(fmt,"height", 1080); + cJSON_AddFalseToObject (fmt,"interlace"); + cJSON_AddNumberToObject(fmt,"frame rate", 24); + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); /* Print to text, Delete the cJSON, print it, release the string. */ + + /* Our "days of the week" array: */ + const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}; + root=cJSON_CreateStringArray(strings,7); + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + + /* Our matrix: */ + int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}}; + root=cJSON_CreateArray(); + for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3)); + +/* cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); */ + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + + + /* Our "gallery" item: */ + int ids[4]={116,943,234,38793}; + root=cJSON_CreateObject(); + cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject()); + cJSON_AddNumberToObject(img,"Width",800); + cJSON_AddNumberToObject(img,"Height",600); + cJSON_AddStringToObject(img,"Title","View from 15th Floor"); + cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject()); + cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943"); + cJSON_AddNumberToObject(thm,"Height",125); + cJSON_AddStringToObject(thm,"Width","100"); + cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4)); + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + + /* Our array of "records": */ + struct record fields[2]={ + {"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"}, + {"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}}; + + root=cJSON_CreateArray(); + for (i=0;i<2;i++) + { + cJSON_AddItemToArray(root,fld=cJSON_CreateObject()); + cJSON_AddStringToObject(fld, "precision", fields[i].precision); + cJSON_AddNumberToObject(fld, "Latitude", fields[i].lat); + cJSON_AddNumberToObject(fld, "Longitude", fields[i].lon); + cJSON_AddStringToObject(fld, "Address", fields[i].address); + cJSON_AddStringToObject(fld, "City", fields[i].city); + cJSON_AddStringToObject(fld, "State", fields[i].state); + cJSON_AddStringToObject(fld, "Zip", fields[i].zip); + cJSON_AddStringToObject(fld, "Country", fields[i].country); + } + +/* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); */ + + out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); + +} + +int main (int argc, const char * argv[]) { + /* a bunch of json: */ + char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\": \"rect\", \n\"width\": 1920, \n\"height\": 1080, \n\"interlace\": false,\"frame rate\": 24\n}\n}"; + char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]"; + char text3[]="[\n [0, -1, 0],\n [1, 0, 0],\n [0, 0, 1]\n ]\n"; + char text4[]="{\n \"Image\": {\n \"Width\": 800,\n \"Height\": 600,\n \"Title\": \"View from 15th Floor\",\n \"Thumbnail\": {\n \"Url\": \"http:/*www.example.com/image/481989943\",\n \"Height\": 125,\n \"Width\": \"100\"\n },\n \"IDs\": [116, 943, 234, 38793]\n }\n }"; + char text5[]="[\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.7668,\n \"Longitude\": -122.3959,\n \"Address\": \"\",\n \"City\": \"SAN FRANCISCO\",\n \"State\": \"CA\",\n \"Zip\": \"94107\",\n \"Country\": \"US\"\n },\n {\n \"precision\": \"zip\",\n \"Latitude\": 37.371991,\n \"Longitude\": -122.026020,\n \"Address\": \"\",\n \"City\": \"SUNNYVALE\",\n \"State\": \"CA\",\n \"Zip\": \"94085\",\n \"Country\": \"US\"\n }\n ]"; + + /* Process each json textblock by parsing, then rebuilding: */ + doit(text1); + doit(text2); + doit(text3); + doit(text4); + doit(text5); + + /* Parse standard testfiles: */ +/* dofile("../../tests/test1"); */ +/* dofile("../../tests/test2"); */ +/* dofile("../../tests/test3"); */ +/* dofile("../../tests/test4"); */ +/* dofile("../../tests/test5"); */ + + /* Now some samplecode for building objects concisely: */ + create_objects(); + + return 0; +} diff --git a/rtasn1/cjson/tests/test1 b/rtasn1/cjson/tests/test1 new file mode 100644 index 0000000..eacfbf5 --- /dev/null +++ b/rtasn1/cjson/tests/test1 @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} diff --git a/rtasn1/cjson/tests/test2 b/rtasn1/cjson/tests/test2 new file mode 100644 index 0000000..5600991 --- /dev/null +++ b/rtasn1/cjson/tests/test2 @@ -0,0 +1,11 @@ +{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}} diff --git a/rtasn1/cjson/tests/test3 b/rtasn1/cjson/tests/test3 new file mode 100644 index 0000000..5662b37 --- /dev/null +++ b/rtasn1/cjson/tests/test3 @@ -0,0 +1,26 @@ +{"widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } +}} \ No newline at end of file diff --git a/rtasn1/cjson/tests/test4 b/rtasn1/cjson/tests/test4 new file mode 100644 index 0000000..d540b57 --- /dev/null +++ b/rtasn1/cjson/tests/test4 @@ -0,0 +1,88 @@ +{"web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500}}, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2"}}, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet"}, + + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet"}, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true}}], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*"}, + + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} \ No newline at end of file diff --git a/rtasn1/cjson/tests/test5 b/rtasn1/cjson/tests/test5 new file mode 100644 index 0000000..49980ca --- /dev/null +++ b/rtasn1/cjson/tests/test5 @@ -0,0 +1,27 @@ +{"menu": { + "header": "SVG Viewer", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, + null, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, + null, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, + null, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, + null, + {"id": "Help"}, + {"id": "About", "label": "About Adobe CVG Viewer..."} + ] +}} diff --git a/rtasn1/cpp/CMakeLists.txt b/rtasn1/cpp/CMakeLists.txt new file mode 100644 index 0000000..f892f9f --- /dev/null +++ b/rtasn1/cpp/CMakeLists.txt @@ -0,0 +1,21 @@ + +ADD_LIBRARY(asn1cpp + prim_oid.cpp) + +# +# Install stull +# + +IF(APPLE) + INSTALL(TARGETS asn1cpp + COMPONENT RuntimeLibraries + LIBRARY DESTINATION Smartasn1.app/Contents/lib/ + ARCHIVE DESTINATION Smartasn1.app/Contents/lib/ + ) +ELSE(APPLE) + INSTALL(TARGETS asn1cpp + COMPONENT RuntimeLibraries + LIBRARY DESTINATION lib/ + ARCHIVE DESTINATION lib/ + ) +ENDIF(APPLE) diff --git a/rtasn1/cpp/prim_GeneralizedTime.h b/rtasn1/cpp/prim_GeneralizedTime.h new file mode 100644 index 0000000..ccb2c89 --- /dev/null +++ b/rtasn1/cpp/prim_GeneralizedTime.h @@ -0,0 +1,26 @@ +#ifndef PRIM_GENERALIZEDTIME_H +#define PRIM_GENERALIZEDTIME_H + +namespace ans1 { +namespace prim { +namespace types { + + +class GeneralizedTime { + public: + inline GeneralizedTime(int len,const char *v) : m_len(len),m_(v) {}; + inline GeneralizedTime(const GeneralizedTime &oid) {} + inline ~GeneralizedTime() {} + + inline bool operator==(const GeneralizedTime &o) { return true;}; + + protected: + int m_len; + const char *m_; + +}; + +} +} +} +#endif diff --git a/rtasn1/cpp/prim_UTCTime.h b/rtasn1/cpp/prim_UTCTime.h new file mode 100644 index 0000000..ef40d61 --- /dev/null +++ b/rtasn1/cpp/prim_UTCTime.h @@ -0,0 +1,27 @@ +#ifndef PRIM_UTCTIME_H +#define PRIM_UTCTIME_H + +namespace ans1 { +namespace prim { +namespace types { + + +class UTCTime { + public: + inline UTCTime(int len,const char *v) : m_len(len),m_(v) {}; + inline UTCTime(const UTCTime &oid) {} + inline ~UTCTime() {} + + inline bool operator==(const UTCTime &o) {return true;}; + + protected: + int m_len; + const char *m_; + +}; + +} +} +} +#endif + diff --git a/rtasn1/cpp/prim_oid.cpp b/rtasn1/cpp/prim_oid.cpp new file mode 100644 index 0000000..e913fc0 --- /dev/null +++ b/rtasn1/cpp/prim_oid.cpp @@ -0,0 +1,215 @@ + +#include +#include +#include +#include +#include "rtasn1/prim_types.h" +#include "rtasn1/cpp/prim_oid.h" + +#define GEN_LOG_DEBUG + +#define MIN(a,b) (((a)< (b))?(a):(b)) + +namespace asn1 { +namespace prim { +namespace types { + +/** + * Default constructor + */ +ObjectIdentifier::ObjectIdentifier(long len,const char *buf) + : m_len(len) +{ + memset(m_oid,0x00,MAX_OID_LEN); + m_ = m_oid; + assert(len < MAX_OID_LEN); + memcpy(m_,buf,MIN(len,MAX_OID_LEN)); +} + +ObjectIdentifier::ObjectIdentifier(const char *v) +{ + memset(m_oid,0x00,MAX_OID_LEN); + m_ = m_oid; + size_t len = strlen(v); + assert(len < MAX_OID_LEN); + memcpy(m_,v,MIN(len,MAX_OID_LEN)); +} + +// Compare +bool ObjectIdentifier::operator ==(const ObjectIdentifier &o) const +{ + return ( m_len == o.m_len ) && !strncmp(m_oid,o.m_oid,m_len); +} +// Copy constructor +ObjectIdentifier::ObjectIdentifier(const ObjectIdentifier &oid) +{ + if (oid.m_len > MAX_OID_LEN) + { + std::cerr<<"ObjectIdentifier::ObjectIdentifier MAX_OID_LEN exeeded "< 1)) { + intsize--; + integer <<=8; + } + mask = (0x7f << ((intsize-1)*7)); + long decal = (intsize -1)*7; + + while ((value & mask ) != 0) + { + long treat = ((value & mask)>>decal); + m_oid[m_len++] = (( treat & 0x7F) |0x80 ); + value<<=7; + intsize--; + } + if (intsize) + m_oid[m_len++] = 0; + m_oid[m_len -1 ] = m_oid[m_len - 1] & 0x7F; + //m_oid[m_len ] = m_oid[m_len ] & 0x7F; +} + +void +ObjectIdentifier::from_string(long len,const char *arcs) +{ + memset(m_oid,0x00,MAX_OID_LEN); + m_len = len; + assert(len < MAX_OID_LEN); + memcpy(m_oid,arcs,MIN(len,MAX_OID_LEN)); +} + +void +ObjectIdentifier::from_arc(long len,const long *arcs) +{ + long * pos = &m_len; + int first2 = 0; + *pos = 0; + assert(len < MAX_OID_LEN); + for ( int i = 0 ; i < len; i++) + { + long l = arcs[i]; + if (i == 0) + { + first2 = 40 * arcs[i]; + } else if (i == 1) + { + first2 = first2 + arcs[i]; + m_oid[*pos] = first2; + (*pos)++; + } else + { + encode_integer(l); + } + + } + assert(m_len < MAX_OID_LEN); +} + +void +ObjectIdentifier::to_arc(array_type &a) +{ + char *buf = const_cast(m_oid); + if (m_len) + { + for (int i = 0 ; i < m_len ; i++) + { + if (i == 0 ) + { + long byte = buf[i] / 40; + a.push_back(byte); + byte = buf[i] % 40; + a.push_back(byte); + + } else if (buf[i] & 0x80 ) { + long res = 0; + while ((buf[i] & 0x80)) + { + res = (res<<7) | (buf[i++] &0x7F); + } + res = (res<<7) | (buf[i] &0x7F); + a.push_back(res); + } else + { + long l = buf[i]; + a.push_back(l); + } + } + } +} + +// Compare +std::ostream & operator <<(std::ostream &os,const ObjectIdentifier &oid ) +{ + char *buf = const_cast(oid.m_oid); + + if (oid.m_len) + { + for (int i = 0 ; (i < oid.m_len) && (im_.push_back((T)byte); + os< + +namespace asn1 { +namespace prim { +namespace types { +#define MAX_OID_LEN 48 +/** + * ObjectIdentifier type + * Only store the encoded form. + * Decode the encoded form from display + */ +class ObjectIdentifier : public asn1::prim::types::prim< char *> +{ + public: + typedef std::vector array_type; + typedef array_type::iterator iterator; + + // Build from encoded ObjectIdentidier + ObjectIdentifier(long len=0,const char *v=NULL); + // Build from encoded ObjectIdentidier + ObjectIdentifier(const char *v); + + // Build string from ... 3 {1,3,5} + ObjectIdentifier(long len,const long *arcs); + + ObjectIdentifier(const ObjectIdentifier &oid); + + inline ~ObjectIdentifier() {} + // Build oid string from arcs + void from_arc(long len,const long *arcs); + // + void from_string(long len,const char *arcs); + + void to_arc(array_type &result); + // Copy operator + ObjectIdentifier &operator=(const ObjectIdentifier &oid); + // Compare + bool operator==(const ObjectIdentifier &oid) const; + + inline long get_oid_length() const { return m_len;} + friend std::ostream & operator <<(std::ostream &os,const ObjectIdentifier &oid ); + protected: + void encode_integer(long l); + protected: + char m_oid[MAX_OID_LEN] ; // Encoded Oid + long m_len; +}; + +std::ostream & operator <<(std::ostream &os,ObjectIdentifier &oid ); + +} +} +} +#endif diff --git a/rtasn1/json_token.h.inc b/rtasn1/json_token.h.inc new file mode 100644 index 0000000..a648a2f --- /dev/null +++ b/rtasn1/json_token.h.inc @@ -0,0 +1,19 @@ +#ifndef JER_TOKEN +#define JER_TOKEN(id,str) +#endif +JER_TOKEN(bool,"bool") +JER_TOKEN(colon,"colon") +JER_TOKEN(comma,"comma") +JER_TOKEN(eof,"eof") +JER_TOKEN(error,"error") +JER_TOKEN(left_brace,"lbrace") +JER_TOKEN(left_bracket,"lbracket") +JER_TOKEN(null,"null") +JER_TOKEN(integer,"integer") +JER_TOKEN(double,"double") +JER_TOKEN(right_brace,"rbrace") +JER_TOKEN(right_bracket,"rbracket") +JER_TOKEN(string,"string") +JER_TOKEN(string_with_escapes,"string_with_escapes") +JER_TOKEN(comment,"comment") +#undef JER_TOKEN diff --git a/rtasn1/prim_types.cpp b/rtasn1/prim_types.cpp new file mode 100644 index 0000000..bd37f97 --- /dev/null +++ b/rtasn1/prim_types.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include "rtasn1/asn1_config.h" +#include "prim_types.h" + +#if 0 +#include "rtasn1/cpp/prim_oid.h" +#include "rtasn1/cpp/prim_UTCTime.h" +#include "rtasn1/cpp/prim_GeneralizedTime.h" +#endif + +//#define NOTEMPLATE +namespace asn1 { +namespace prim { +namespace types { + +template struct prim; + +template <> +std::ostream &operator << (std::ostream &os,const prim &_p) +{ + bool b = _p.get_value(); + os<<"bool("< +std::ostream &operator << (std::ostream &os,const prim &_p) +{ + os<<" string ("; + + for (int i = 0 ; i < _p.m_.size(); i++) + { + char tmp[10]; + sprintf(tmp,"%02x",(unsigned char )_p.m_[i]); + os< &)(_p); + return os; +} + + + +// +#ifndef HAVE_STDINT_H +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +{ + os<<" long("<<_p.m_<<") "; + return os; +}; +#endif +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +{ + os<<" UI8("<(_p.m_)<<") "; + return os; +}; + +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +{ + os<<" UI16("<<_p.m_<<") "; + return os; +}; + +#ifdef HAVE_STDINT_H +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +#else +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +#endif +{ + os<<" UI32("<<_p.m_<<") "; + return os; +}; + +#ifdef HAVE_STDINT_H +/* int64_t is long ??? */ +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +#else +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +#endif +{ + os<<" I64("<<_p.m_<<") "; + return os; +}; + + + +#ifdef HAVE_STDINT_H +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +#else +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +#endif +{ + os<<" UI64("<<_p.m_<<") "; + return os; +}; + + + +template <> +std::ostream & operator << (std::ostream &os,const arithm_prim &_p ) +{ + os<<" +#include +#include +#include +#include "rtasn1/cpp/prim_UTCTime.h" +#include "rtasn1/cpp/prim_GeneralizedTime.h" + +//#define NOTEMPLATE +namespace asn1 { +namespace prim { +namespace types { + +template struct prim; + +template +std::ostream &operator <<(std::ostream &os,const prim &t); + + +/** + * + */ +template +struct prim { + + protected: + public: + typedef C prim_type; + typedef C* prim_pointer; + typedef C& prim_type_reference; + typedef const C & prim_type_const_reference; + + inline prim() : m_() {}; + inline prim(const C &c) : m_(c) {} + inline prim(const prim &v) : m_(v.m_) {}; + inline ~prim() {}; + // Copy assignement + inline prim &operator =(const prim &v) {m_ = v.m_; return *this;}; + inline prim &operator=(const C c) { m_ = c; return *this;} + // + inline bool operator==(const prim &c) const { return m_ == c.m_;} + // + inline bool operator!=(const prim &c) { return ! operator==(c);} + inline bool operator==(const C &c) const { return m_ == c;} + inline bool operator!=(const C &c) const { return m_ != c;} + //inline operator C() const {return m_;} + //template + friend std::ostream & operator << <>(std::ostream &os,const prim &_p ); + // Better than cast + prim_type_reference get_value() { return m_;} ; + prim_type_const_reference get_value() const { return m_;} ; +protected: + prim_type m_; +}; + + + +typedef prim Boolean; +//typedef prim String; + +/** + * + */ +class String : public prim +{ + public: + + String() {}; + String(const String &t): prim::prim(t.m_) {}; + String(const std::string &t): prim::prim(t) {}; + String(const char *t): prim::prim(t) {}; + ~String() {}; + + inline void operator=(const std::string &c) { m_ = c;} + + inline bool operator==(const String &c) const { return ! m_.compare(c.m_) ;} + + inline const std::string toString(void) const {return this->m_;}; + friend std::ostream & operator <<(std::ostream &os,const String &_p ); + + size_t size () const { return m_.size() ; } + + const char *c_str() const { return m_.c_str() ; } +}; + + +// Forward declation for array +template struct array ; +template +std::ostream &operator <<(std::ostream &os,const array &t); + +/** + * + */ +template +struct array { + public: + typedef C& reference; + typedef const C& const_reference; + typedef std::vector type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + + inline array(size_t sz = 0) :m_(sz) + { + //std::cout<<" build array "< &v) : m_(v.m_) + { + std::cout<<"array::array copy"< &)"< &operator =(const array &v) {m_ = v.m_;}; + inline ~array() {}; + inline iterator begin() {return m_.begin();}; + inline const_iterator begin() const {return m_.begin();}; + inline iterator end() {return m_.end();}; + inline size_t size() const {return m_.size();}; + //inline void operator=(const C c) { m_ = c;} + inline reference operator[](int c) { + if (m_.size() == 0) + { + m_.resize(c+1) ; + m_[c] = 0; + } else if (m_.size() <= c) + { + m_.resize(c+1); + m_[c] = 0; + } + return m_[c]; + } + inline const_reference operator[](int c) const { return m_[c];} +// inline bool operator==(const prim &c) { m_ == c;} + inline void operator=(const C &c) { m_[0] = c;} + inline void operator=(const prim &c) { m_ = c.m_;} + inline operator type () const {return m_;} + + friend std::ostream & operator <<(std::ostream &os,const array &_p ) + { + typename std::vector::const_iterator iter = _p.begin(); + os<<" array [";os<<_p.size()<<"] "; + os< +{ + public: + + UTCTime() {}; + UTCTime(const UTCTime &t): prim::prim(t.m_) {}; + UTCTime(const std::string &t): prim::prim(t) {}; + UTCTime(const char *t): prim::prim(t) {}; + ~UTCTime() {}; + + inline void operator=(const std::string &c) { m_ = c;} + + inline const std::string toString(void) const {return this->m_;}; + friend std::ostream & operator <<(std::ostream &os,const UTCTime &_p ); + + +}; + +// Forward declaration for arith_prim streaming +template class arithm_prim; + +template +std::ostream &operator <<(std::ostream &os,const arithm_prim &s); + +/** + * + */ +template +class arithm_prim : public prim +{ + public: + inline arithm_prim() {}; + inline arithm_prim(const arithm_prim &v) : prim(v) {}; + inline ~arithm_prim() {}; + inline arithm_prim(const C c) : prim(c) {}; + + inline void operator = (const C c) {prim::operator =(c);} + // Available in prim + // inline bool operator ==(const arithm_prim &c) { return this->m_ == (C)c.m_;}; + // inline bool operator ==(const C c) { return prim::operator ==(c);}; + inline C operator +=(const C v) {return this->m_+=v;} + inline C operator -=(const C v) {return this->m_-=v;} + inline C operator *=(const C v) {return this->m_*=v;} + inline C operator /=(const C v) {return this->m_/=v;} +#if 1 + inline arithm_prim &operator +=(const arithm_prim &v) + { prim::m_ += v.m_; return *this; } + inline arithm_prim &operator -=(const arithm_prim &v) + { prim::m_ -= v.m_; return *this; } + inline arithm_prim &operator *=(const arithm_prim &v) + { prim::m_ *= v.m_; return *this; } + inline arithm_prim &operator /=(const arithm_prim &v) + { prim::m_ /= v.m_; return *this; } +#endif + + //inline C operator --(const C v) {return --this->m_;} + //inline C operator ++(const C v) {return ++this->m_;} + // + friend std::ostream &operator << <>(std::ostream &os,const arithm_prim &_p); +}; + +/** + * Be aware the that what's below depends on the processor + * use it carefully. + * If stdint is available, I should use + * + */ +#ifdef HAVE_STDINT_H + +typedef arithm_prim UInt8; +typedef arithm_prim UInt16; +typedef arithm_prim UInt32; +typedef arithm_prim UInt64; + +typedef arithm_prim Int8; +typedef arithm_prim Int16; +typedef arithm_prim Int32; +typedef arithm_prim Int64; + +typedef arithm_prim Integer; +#else +typedef arithm_prim Integer; +typedef arithm_prim UInt8; +typedef arithm_prim UInt16; +typedef arithm_prim UInt32; +typedef arithm_prim UInt64; + +typedef arithm_prim Int8; +typedef arithm_prim Int16; +typedef arithm_prim Int32; +typedef arithm_prim Int64; +#endif + +typedef arithm_prim Real; + + +std::ostream & operator <<(std::ostream &os,const asn1::prim::types::UTCTime &_p ); +/** + * BIT STRING .... + * -> I use a template in order to be able to specify + * several size of bit strings (8, 16 , 32, and above) + */ +class bs_prim : public prim > +{ + public: + typedef unsigned char C; + + typedef std::vector prim_type; + typedef prim_type * prim_pointer; + typedef prim_type & prim_type_reference; + typedef const prim_type & prim_type_const_reference; + /* There is an inconsitency */ + typedef C* pointer; + typedef C& reference; + typedef const C& const_reference; + typedef std::vector type; + typedef type & type_reference; + typedef std::vector::iterator iterator; + typedef std::vector ::const_iterator const_iterator; + + bs_prim(size_t sz = 0) + : prim >() + { + } + bs_prim(const prim_type &c) + : prim >(c) + { + } + + bs_prim(const bs_prim &_bs) + : prim >(_bs.get_value()) + , m_NbBits(_bs.m_NbBits) + { + } + + ~bs_prim() + { + } +#if 0 + void set_data(const char *) + { + } + + void set_data(const std::string &_v) + { + m_NbBits = _v.size() << 3; + } +#endif + // + inline size_t size() const + { + return this->m_.size(); + } + // + void set_nb_bits( size_t _nb) + { + m_NbBits = _nb; + this->m_.resize(_nb/8+1); + }; + + // + inline size_t get_nb_bits() const + { + return m_NbBits; + }; + + // + void set_bit(int _bit) + { + int a,b; + unsigned char val = 1; + a = _bit / 8; + b = _bit % 8; + val = 1<m_[a] = this->m_[a] | val; + }; + + // + void clear_bit(int _bit) + { + int a,b; + unsigned char val = 1; + a = _bit / 8; + b = _bit % 8; + val = 1<m_[a] = this->m_[a] & ~val; + }; + + // + inline bool get_bit(int _bit) const + { + int a,b; + unsigned char val = 1; + a = _bit / 8; + b = _bit % 8; + val = 1<m_[a] & val)>0; + }; + + // + const_reference operator[](size_t c) const + { + return this->m_[c]; + } + // + reference operator[](size_t c) + { + if (this->m_.size() <= c) + { + this->m_.resize(c+1); + this->m_[c] = 0; + m_NbBits = c << 3; + } + return this->m_[c]; + } + + // + iterator begin() + { return this->m_.begin() ; } + // + const_iterator begin() const + { return this->m_.begin() ; } + // + iterator end() + { return this->m_.end() ; } + // + const_iterator end() const + { return this->m_.end() ; } + + + friend std::ostream & operator <<(std::ostream &os,const bs_prim &_p ) + { + size_t count = 0; + //const_iterator iter = _p.end(); + const_iterator iter = _p.begin(); iter+=_p.m_NbBits/8 - 1 ; + os<<" bs[";os<<_p.size()<<"] ("<<_p.m_NbBits<<")"; + //os<= _p.m_.begin() ; --iter) { + if (iter != _p.end() ) + os<<":"; + os< + +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-basic-types-choice.h" +#include "TEST_basic_types_choice.h" + +using namespace asn1; +using namespace TEST_basic_types_choice; + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_choice); + + +void TC_TEST_basic_types_choice::setUp() +{ + +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice_device() +{ + TEST_Choice c( TEST_Choice::typeof_device ); + c.get_device() = 3; + c.encode(m_ctx); + + const unsigned char seq[] = {0x02,0x01,0x03}; + int result = memcmp(m_ctx.buffer(),seq,3); + m_ctx.reset(); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice_name() +{ + TEST_Choice c( TEST_Choice::typeof_name ,asn1::tag(asn1::types::UNIVERSAL,22)); + c.get_name() = "Jones"; + c.encode(m_ctx); + + const unsigned char seq[] = {0x16,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + CppUnit::Message message(std::string("Failed encode name Jones")); + int result = memcmp(m_ctx.buffer(),seq,7); + m_ctx.reset(); + CPPUNIT_ASSERT(result==0); +} + + +void TC_TEST_basic_types_choice::encode_TEST_Choice_b1() +{ + asn1::streams::ber ctx; + TEST_Choice c( TEST_Choice::typeof_b1 ,asn1::tag(asn1::types::UNIVERSAL,1)); + c.get_b1() = false; + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + + const unsigned char seq[] = {0x01,0x01,0x00}; + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice_ip4() +{ + asn1::streams::ber ctx; + TEST_Choice c( TEST_Choice::typeof_ip4 ,asn1::tag(asn1::types::UNIVERSAL,16)); + + c.get_ip4().address = asn1::prim::types::String("\x0A\x03\x10\x21"); + c.get_ip4().portNumber.get() = INTEGER(asn1::prim::types::Integer(2)); + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + //10 09 04 04 0a 03 10 21 02 01 02 + //30 08 04 0a 03 10 21 02 01 02 + const unsigned char seq[] = {0x30,0x09,0x04,0x04,0x0A,0x03,0X10,0x21,0x02,0x1,0x02}; + int result = memcmp(ctx.buffer(),seq,11); + CPPUNIT_ASSERT(result==0); +} + + +void TC_TEST_basic_types_choice::encode_TEST_Choice1_deviceId() +{ + asn1::streams::ber ctx; + TEST_Choice1 c( TEST_Choice1::typeof_device ,asn1::tag(asn1::types::CONTEXT_SPECIFIC,0)); + c.get_device() = 9; + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + const unsigned char seq[] = {0x80,0x01,0x09}; + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice1_i2() +{ + asn1::streams::ber ctx; + TEST_Choice1 c( TEST_Choice1::typeof_i2,asn1::tag(asn1::types::CONTEXT_SPECIFIC,1) ); + c.get_i2() = 16; + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + const unsigned char seq[] = {0x81,0x01,0x10}; + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice1_b1() +{ + asn1::streams::ber ctx; + TEST_Choice1 c( TEST_Choice1::typeof_b1 , asn1::tag(asn1::types::CONTEXT_SPECIFIC,2)); + c.get_b1() = true; + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + const unsigned char seq[] = {0x82,0x01,0xFF}; + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice1_bs1() +{ + asn1::streams::ber ctx; + TEST_Choice1 c( TEST_Choice1::typeof_bs1,asn1::tag(asn1::types::CONTEXT_SPECIFIC,3) ); + c.get_bs1()[0] = 0x02; + c.get_bs1().set_nb_bits(2); + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + const unsigned char seq[] = {0x83,0x02,0x06,0x80}; + const unsigned char seq1[] = {0x83,0x07,0x04,0x0a,0x3B,0x5F,0x29,0x1c,0xd0}; + int result = memcmp(ctx.buffer(),seq,4); + ctx.reset(); + CPPUNIT_ASSERT(result==0); + c.get_bs1()[0] = 0xcd; + c.get_bs1()[1] = 0x91; + c.get_bs1()[2] = 0xf2; + c.get_bs1()[3] = 0xB5; + c.get_bs1()[4] = 0xA3; + c.get_bs1()[5] = 0x0; + c.get_bs1().set_nb_bits(44); + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + result = memcmp(ctx.buffer(),seq1,9); + CPPUNIT_ASSERT(result==0); + +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice1_os1() +{ + asn1::streams::ber ctx; + TEST_Choice1 c( TEST_Choice1::typeof_os1, asn1::tag(asn1::types::CONTEXT_SPECIFIC,4) ); + + c.get_os1() = asn1::prim::types::String("1"); + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + const unsigned char seq[] = {0x84,0x01,0x31}; + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_Choice1_nul() +{ + asn1::streams::ber ctx; + TEST_Choice1 c( TEST_Choice1::typeof_nul , asn1::tag(asn1::types::CONTEXT_SPECIFIC,5)); + CPPUNIT_ASSERT(c.check_create()); + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + const unsigned char seq[] = {0x85,0x00,0x0}; + int result = memcmp(ctx.buffer(),seq,2); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_ChoiceChoiceA() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x40,0x01,0x0b}; + //ChoiceChoice c(ChoiceChoice::typeof_choicea, asn1::tag(asn1::types::APPLICATION,0) ); + ChoiceChoice c(ChoiceChoice::typeof_choicea ); + //ChoiceChoice c(asn1::tag(asn1::types::CONTEXT_SPECIFIC,0)); + c.get_choicea().get_i() = 11; + c.encode(ctx); + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::encode_TEST_ChoiceChoiceB() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x81,0x01,0x0a}; + ChoiceChoice c(asn1::tag(asn1::types::CONTEXT_SPECIFIC,1)); + c.get_choiceb().get_ib() = 10; + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} +//decode + +void TC_TEST_basic_types_choice::decode_TEST_Choice_device() +{ + asn1::streams::ber ctx; + TEST_Choice c; + const unsigned char seq[] = {0x02,0x01,0x07}; + //c.get_device() = 3; + memcpy(ctx.buffer(),seq,3); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + + CPPUNIT_ASSERT(c.get_kind() == TEST_Choice::typeof_device); + CPPUNIT_ASSERT(c.get_device()== 7); +} +void TC_TEST_basic_types_choice::decode_TEST_Choice_name() +{ + asn1::streams::ber ctx; + TEST_Choice c; + const unsigned char seq[] = {0x16,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + +// asn1::prim::types::String s("Jones"); + + memcpy(ctx.buffer(),seq,7); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + + CPPUNIT_ASSERT(c.get_kind() == TEST_Choice::typeof_name); + //CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_choice::decode_TEST_Choice1_deviceId() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x80,0x01,0x0D}; + TEST_Choice1 c; + + memcpy(ctx.buffer(),seq,3); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_device()==13); + CPPUNIT_ASSERT(5==5); +} + +void TC_TEST_basic_types_choice::decode_TEST_Choice1_i2() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x81,0x01,0x0D}; + //TEST_Choice1 c( TEST_Choice1::typeof_i2 ); + TEST_Choice1 c( TEST_Choice1::typeof_i2,asn1::tag(asn1::types::CONTEXT_SPECIFIC,1) ); + c.get_i2() = 14; + memcpy(ctx.buffer(),seq,3); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_i2()==13); +} + +void TC_TEST_basic_types_choice::decode_TEST_Choice1_b1() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x82,0x01,0xFF}; + TEST_Choice1 c( TEST_Choice1::typeof_i2,asn1::tag(asn1::types::CONTEXT_SPECIFIC,1) ); + c.get_i2() = 14; + memcpy(ctx.buffer(),seq,3); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_kind() == TEST_Choice1::typeof_b1); + CPPUNIT_ASSERT(c.get_b1() == true); +} + +void TC_TEST_basic_types_choice::decode_TEST_Choice1_bs1() +{ + asn1::streams::ber ctx; + //const unsigned char seq[] = {0x83,0x02,0x00,0x0D}; + const unsigned char seq[] = {0x83,0x07,0x04,0x0a,0x3B,0x5F,0x29,0x1c,0xd0}; + TEST_Choice1 c( TEST_Choice1::typeof_i2 ); + memcpy(ctx.buffer(),seq,9); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_kind() == TEST_Choice1::typeof_bs1); + CPPUNIT_ASSERT(c.get_bs1()[0] == 0xcd); + CPPUNIT_ASSERT(c.get_bs1()[1] == 0x91); + CPPUNIT_ASSERT(c.get_bs1()[2] == 0xf2); + CPPUNIT_ASSERT(c.get_bs1()[3] == 0xb5); +} + +void TC_TEST_basic_types_choice::decode_TEST_Choice1_os1() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x84,0x01,0x32}; + TEST_Choice1 c( TEST_Choice1::typeof_i2,asn1::tag(asn1::types::CONTEXT_SPECIFIC,1) ); + c.get_i2() = 14; + memcpy(ctx.buffer(),seq,3); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_kind() == TEST_Choice1::typeof_os1); + CPPUNIT_ASSERT(std::string("2").compare(c.get_os1().get_sys_value() ) == 0); +} + +void TC_TEST_basic_types_choice::decode_TEST_Choice1_nul() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x85,0x00,0x00}; + TEST_Choice1 c( TEST_Choice1::typeof_i2 ); + memcpy(ctx.buffer(),seq,2); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_kind() == TEST_Choice1::typeof_nul); +} + +void TC_TEST_basic_types_choice::decode_TEST_ChoiceChoiceA() +{ + asn1::streams::ber ctx; + //const unsigned char seq[] = {0x40,0x01,0x0b}; + const unsigned char seq[] = {0x80,0x03,0x40,0x01,0x0b}; + ChoiceChoice c( 0, asn1::tag(asn1::types::APPLICATION,0) ); + memcpy(ctx.buffer(),seq,5); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_choicea().get_i()== 11); +} + +void TC_TEST_basic_types_choice::decode_TEST_ChoiceChoiceB() +{ + asn1::streams::ber ctx; + //const unsigned char seq[] = {0x81,0x01,0x0a}; + const unsigned char seq[] = {0x81,0x03,0x81,0x01,0x0a}; + ChoiceChoice c(asn1::tag(asn1::types::CONTEXT_SPECIFIC,1)); + c.get_choiceb().get_ib() = 0; + memcpy(ctx.buffer(),seq,5); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + CPPUNIT_ASSERT(c.get_choiceb().get_ib() == 10); +} + diff --git a/tests/UNIT-TEST-basic-types-choice.h b/tests/UNIT-TEST-basic-types-choice.h new file mode 100644 index 0000000..cbf0689 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-choice.h @@ -0,0 +1,70 @@ +#ifndef TESTCASE_SIMPLETYPE_H +#define TESTCASE_SIMPLETYPE_H + +#include +#include "TEST_basic_types.h" + + +class TC_TEST_basic_types_choice : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_choice ); + CPPUNIT_TEST(encode_TEST_Choice_device); + CPPUNIT_TEST(encode_TEST_Choice_name); + CPPUNIT_TEST(encode_TEST_Choice_b1); + CPPUNIT_TEST(encode_TEST_Choice_ip4); + CPPUNIT_TEST(encode_TEST_Choice1_deviceId); + CPPUNIT_TEST(encode_TEST_Choice1_i2); + CPPUNIT_TEST(encode_TEST_Choice1_b1); + CPPUNIT_TEST(encode_TEST_Choice1_bs1); + CPPUNIT_TEST(encode_TEST_Choice1_os1); + CPPUNIT_TEST(encode_TEST_Choice1_nul); + CPPUNIT_TEST(encode_TEST_ChoiceChoiceA); + CPPUNIT_TEST(encode_TEST_ChoiceChoiceB); + CPPUNIT_TEST(decode_TEST_Choice_device); + CPPUNIT_TEST(decode_TEST_Choice_name); + CPPUNIT_TEST(decode_TEST_Choice1_deviceId); + CPPUNIT_TEST(decode_TEST_Choice1_i2); + CPPUNIT_TEST(decode_TEST_Choice1_b1); + CPPUNIT_TEST(decode_TEST_Choice1_bs1); + CPPUNIT_TEST(decode_TEST_Choice1_os1); + CPPUNIT_TEST(decode_TEST_Choice1_nul); + CPPUNIT_TEST(decode_TEST_ChoiceChoiceA); + CPPUNIT_TEST(decode_TEST_ChoiceChoiceB); + + + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_TEST_Choice_device(); + void encode_TEST_Choice_name(); + void encode_TEST_Choice_b1(); + void encode_TEST_Choice_ip4(); + void encode_TEST_Choice1_deviceId(); + void encode_TEST_Choice1_i2(); + void encode_TEST_Choice1_b1(); + void encode_TEST_Choice1_bs1(); + void encode_TEST_Choice1_os1(); + void encode_TEST_Choice1_nul(); + void encode_TEST_ChoiceChoiceA(); + void encode_TEST_ChoiceChoiceB(); + // + // + void decode_TEST_Choice_device(); + void decode_TEST_Choice_name(); + void decode_TEST_Choice1_deviceId(); + void decode_TEST_Choice1_i2(); + void decode_TEST_Choice1_b1(); + void decode_TEST_Choice1_bs1(); + void decode_TEST_Choice1_os1(); + void decode_TEST_Choice1_nul(); + void decode_TEST_ChoiceChoiceA(); + void decode_TEST_ChoiceChoiceB(); + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types-enum.cpp b/tests/UNIT-TEST-basic-types-enum.cpp new file mode 100644 index 0000000..1d17a61 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-enum.cpp @@ -0,0 +1,65 @@ + + +#include + +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types_enum.h" +#include "UNIT-TEST-basic-types-enum.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_enum); + +using namespace TEST_basic_types_enum; + +void TC_TEST_basic_types_enum::setUp() +{ + +} + +void TC_TEST_basic_types_enum::encode_TEST_Enum() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x0a,0x01,0x02}; + //S.m_value = TEST_Enum::two; + asn1::prim::types::Integer I(TEST_Enum::two); + TEST_Enum S; + //S = I; + S = TEST_Enum::two; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result == 0); +} +void TC_TEST_basic_types_enum::encode_TEST_SeqEnum() +{ + const unsigned char seq[] = {0x31,0x05,0x02,0x01,0x06,0x05,0x00}; + asn1::streams::ber ctx; + TEST_SeqEnum S; + S.enum1 = TEST_Enum::one ; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,7); +// CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_enum::decode_TEST_Enum() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x0a,0x01,0x01}; + TEST_Enum S; + memcpy(ctx.buffer(),seq,3); + //S.codec(ctx,S,asn1::CODEC_DECODE); + S.decode(ctx); + CPPUNIT_ASSERT( S == TEST_Enum::one); +} + +void TC_TEST_basic_types_enum::decode_TEST_SeqEnum() +{ + asn1::streams::ber ctx; + asn1::INTEGER i(asn1::prim::types::Integer(10)),i2(asn1::prim::types::Integer(12)); +} + diff --git a/tests/UNIT-TEST-basic-types-enum.h b/tests/UNIT-TEST-basic-types-enum.h new file mode 100644 index 0000000..be0f4e5 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-enum.h @@ -0,0 +1,33 @@ +#ifndef TESTCASE_SIMPLETYPE_H +#define TESTCASE_SIMPLETYPE_H + +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-basic-types-enum.h" + +class TC_TEST_basic_types_enum : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_enum ); + CPPUNIT_TEST(encode_TEST_Enum); + CPPUNIT_TEST(encode_TEST_SeqEnum); + CPPUNIT_TEST(decode_TEST_Enum); + CPPUNIT_TEST(decode_TEST_SeqEnum); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_TEST_Enum(); + void encode_TEST_SeqEnum(); + void decode_TEST_Enum(); + void decode_TEST_SeqEnum(); + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types-explicit.cpp b/tests/UNIT-TEST-basic-types-explicit.cpp new file mode 100644 index 0000000..2121617 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-explicit.cpp @@ -0,0 +1,126 @@ +#include + +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-basic-types-explicit.h" +#include "TEST_basic_types_explicit.h" +#include "TEST_basic_types_explicit_codec.hpp" + +using namespace asn1; +using namespace TEST_basic_types_explicit; + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_explicit); + + +void TC_TEST_basic_types_explicit::setUp() +{ + +} + +void TC_TEST_basic_types_explicit::encode_Test() +{ + asn1::streams::ber ctx; + Test i; + i.get_value() = 5; + + //i.codec(ctx,i,asn1::CODEC_ENCODE); + i.encode(ctx); + const unsigned char seq[] = {0x60,0x03,0x02,0x01,0x05}; + int result = memcmp(ctx.buffer(),seq,5); + CPPUNIT_ASSERT(result==0); +} + + +void TC_TEST_basic_types_explicit::encode_O_String() +{ + const unsigned char seq[] = {0x61,0x06,0x04,0x04,0x64,0x65,0x64,0x65}; + asn1::streams::ber ctx; + std::string dede("dede"); + O_String q; + q.get_value() = dede; + q.encode(ctx); + int result = memcmp(ctx.buffer(),seq,8); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_explicit::encode_B_String() +{ + const unsigned char seq[] = { 0x62,0x04,0x03,0x02,0x00,0x55 }; + asn1::streams::ber ctx; + B_String q; + q[0]=0x55; + q.set_nb_bits(8); + //m_codec.encode(ctx,q); + q.encode(ctx); + int result = memcmp(ctx.buffer(),seq,6); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_explicit::encode_Bool_String() +{ + const unsigned char seq[] = { 0x63,0x03,0x01,0x01,0xFF }; + asn1::streams::ber ctx; + Bool_String q; + q .get_value() = true; + q.encode(ctx); + int result = memcmp(ctx.buffer(),seq,5); + CPPUNIT_ASSERT(result==0); +} + +/** + * + */ +void TC_TEST_basic_types_explicit::decode_Test() +{ + asn1::streams::ber ctx; + Test q; + const unsigned char seq[] = {0x60,0x03,0x02,0x01,0x09}; + + memcpy(ctx.buffer(),seq,5); + int r = q.decode(ctx); + + CPPUNIT_ASSERT(r == asn1::ok); + CPPUNIT_ASSERT(q.get_value() == 9); +} + +void TC_TEST_basic_types_explicit::decode_O_String() +{ + asn1::streams::ber ctx; + O_String q; + const unsigned char seq[] = {0x61,0x06,0x04,0x04,0x64,0x65,0x64,0x65}; + + memcpy(ctx.buffer(),seq,8); + int r = q.decode(ctx); + + CPPUNIT_ASSERT(r == asn1::ok); +} + +void TC_TEST_basic_types_explicit::decode_B_String() +{ + asn1::streams::ber ctx; + B_String q; + //const unsigned char seq[] = { 0x62,0x07,0x30,0x05,0x0a,0x01,0x01,0x16,0x00 }; + const unsigned char seq[] = { 0x62,0x04,0x03,0x02,0x00,0x51 }; + + memcpy(ctx.buffer(),seq,6); + int r = q.decode(ctx); + + CPPUNIT_ASSERT(r == asn1::ok); + CPPUNIT_ASSERT(q[0] == 0x51); +} + +void TC_TEST_basic_types_explicit::decode_Bool_String() +{ + asn1::streams::ber ctx; + Bool_String q; + const unsigned char seq[] = { 0x63,0x03,0x01,0x01,0x00 }; + + memcpy(ctx.buffer(),seq,5); + int r = q.decode(ctx); + + CPPUNIT_ASSERT(r == asn1::ok); +} diff --git a/tests/UNIT-TEST-basic-types-explicit.h b/tests/UNIT-TEST-basic-types-explicit.h new file mode 100644 index 0000000..2b9cab7 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-explicit.h @@ -0,0 +1,43 @@ +#ifndef TESTCASE_IMPLICITTYPE_H +#define TESTCASE_IMPLICITTYPE_H + +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types_explicit.h" + +class TC_TEST_basic_types_explicit : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_explicit ); + CPPUNIT_TEST(encode_Test); + CPPUNIT_TEST(encode_O_String); + CPPUNIT_TEST(encode_B_String); + CPPUNIT_TEST(encode_Bool_String); + // Decoding + CPPUNIT_TEST(decode_Test); + CPPUNIT_TEST(decode_O_String); + CPPUNIT_TEST(decode_B_String); + CPPUNIT_TEST(decode_Bool_String); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_Test(); + void encode_O_String(); + void encode_B_String(); + void encode_Bool_String(); + + void decode_Test(); + void decode_O_String(); + void decode_B_String(); + void decode_Bool_String(); + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types-implicit.cpp b/tests/UNIT-TEST-basic-types-implicit.cpp new file mode 100644 index 0000000..119af98 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-implicit.cpp @@ -0,0 +1,80 @@ +#include + +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-basic-types-implicit.h" +#include "TEST_basic_types_implicit.h" + +using namespace asn1; +using namespace TEST_basic_types_implicit; + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_implicit); + + +void TC_TEST_basic_types_implicit::setUp() +{ + +} + +void TC_TEST_basic_types_implicit::encode_Ti() +{ + asn1::streams::ber ctx; + Ti i; + i.get_value() = 5; + + //i.codec(ctx,i,asn1::CODEC_ENCODE); + i.encode(ctx); + const unsigned char seq[] = {0x88,0x01,0x05}; + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result==0); +} + + +void TC_TEST_basic_types_implicit::encode_query_device() +{ + const unsigned char seq[] = { 0xa2,0x07,0x30,0x05,0x0a,0x01,0x01,0x16,0x00 }; + asn1::streams::ber ctx; + ListForwardParameters_type lfp; + lfp.forwardingType = 1; + QueryDeviceResult q( QueryDeviceResult::typeof_deviceInformation,asn1::tag(2,0,true) ); + q.get_deviceInformation().set_tag(asn1::tag(2,2)); + q.get_deviceInformation().get_forward().push_back(lfp);; + //q.codec(ctx,q,asn1::CODEC_ENCODE); + q.encode(ctx); + + int result = memcmp(ctx.buffer(),seq,9); + CPPUNIT_ASSERT(result==0); +} + +/** + * + */ +void TC_TEST_basic_types_implicit::decode_Ti() +{ + asn1::streams::ber ctx; + Ti q; + const unsigned char seq[] = { 0x88,0x01,0x0a}; + + memcpy(ctx.buffer(),seq,3); + int r = q.decode(ctx); + + CPPUNIT_ASSERT(r == asn1::ok); + CPPUNIT_ASSERT(q.get_value() == 10); +} + +void TC_TEST_basic_types_implicit::decode_query_device() +{ + asn1::streams::ber ctx; + QueryDeviceResult q( QueryDeviceResult::typeof_deviceInformation ); + const unsigned char seq[] = { 0xa1,0x07,0x30,0x05,0x0a,0x01,0x01,0x16,0x00 }; + + memcpy(ctx.buffer(),seq,9); + int r = q.decode(ctx); + + CPPUNIT_ASSERT(r == asn1::ok); +} + diff --git a/tests/UNIT-TEST-basic-types-implicit.h b/tests/UNIT-TEST-basic-types-implicit.h new file mode 100644 index 0000000..93f6ff6 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-implicit.h @@ -0,0 +1,35 @@ +#ifndef TESTCASE_IMPLICITTYPE_H +#define TESTCASE_IMPLICITTYPE_H + +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types_implicit.h" + +class TC_TEST_basic_types_implicit : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_implicit ); + CPPUNIT_TEST(encode_Ti); + CPPUNIT_TEST(encode_query_device); + // Decoding + CPPUNIT_TEST(decode_Ti); + CPPUNIT_TEST(decode_query_device); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_Ti(); + void encode_query_device(); + + void decode_Ti(); + void decode_query_device(); + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types-optional.cpp b/tests/UNIT-TEST-basic-types-optional.cpp new file mode 100644 index 0000000..243695f --- /dev/null +++ b/tests/UNIT-TEST-basic-types-optional.cpp @@ -0,0 +1,432 @@ +#include +#include +#include +#define MAIN +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types_optional.h" +#include "UNIT-TEST-basic-types-optional.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_optional); + +using namespace TEST_basic_types_optional; + +/** + * + */ +void TC_TEST_basic_types_optional::setUp() +{ + +} +/** + requestID INTEGER, + extention Extention OPTIONAL + */ +void TC_TEST_basic_types_optional::encode_Request() +{ + asn1::INTEGER i(asn1::prim::types::Integer(4)); + Request r; + r.requestID = i; + + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + //ctx.nb_bits(-1*ctx.nb_read_bits()); + + //r.codec(ctx,str,CODEC_ENCODE); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 5); +} + +/** + * + */ +void TC_TEST_basic_types_optional::decode_Request() +{ + const unsigned char seq[] = {0x30,0x03,0x02,0x01,0x04}; + Request r; + asn1::streams::ber ctx; + + memcpy(ctx.buffer(),seq,5); + + r.decode(ctx); + + CPPUNIT_ASSERT(r.requestID==4); +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqDefaultInt() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + ReqDefaultInt r; + //r.extID = i; + + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 4); + + CPPUNIT_ASSERT( memcmp(ctx.buffer(),seq,4) == 0); + +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqDefaultIntOther() +{ + const unsigned char seq[] = {0x30,0x05,0x02,0x01,0x03,0x05,0x00}; + ReqDefaultInt r; + // Why should an attribute with a default value be tagged as shared ptr ? + //r.extID = asn1::intrusive_ptr(new INTEGER(3)); + r.extID = 3; + r.bit_mask.set(ReqDefaultInt::extID_present); + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 7); + + CPPUNIT_ASSERT( memcmp(ctx.buffer(),seq,7) == 0); + +} + + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqDefaultBool() +{ + ReqDefaultBool r; + //r.extID = i; + + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 4); +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqDefaultBoolOther() +{ + const unsigned char seq[] = {0x30,0x05,0x01,0x01,0x00,0x05,0x00}; + ReqDefaultBool r; + //r.extID = i; + //r.extID = asn1::intrusive_ptr(new BOOLEAN(false)); + r.extID = true; + r.bit_mask.set(ReqDefaultBool::extID_present); + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 7); +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqDefaultString() +{ + ReqDefaultString r; + //r.extID = i; + + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 4); +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqDefaultStringOther() +{ + const unsigned char seq[] = {0x30,0x08,0x16,0x04,0x64,0x65,0x64,0x65,0x05,0x00}; + ReqDefaultString r; + //r.extID = i; + asn1::prim::types::String ps = std::string("dede"); + //r.extID = asn1::intrusive_ptr(new IA5String()); + (r.extID) = ps; + r.bit_mask.set(ReqDefaultString::extID_present); + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 10); +} + + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqOptInt() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + const unsigned char seqopt[] = {0x30,0x03,0x02,0x01,0x04}; + ReqOptInt r; + asn1::intrusive_ptr i( new INTEGER(asn1::prim::types::Integer(3))); + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 4); + // Set the optional value + ctx.reset(); + + r.extID = i; + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 7); +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqOptBool() +{ + ReqOptBool r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 4); +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ReqOptString() +{ + ReqOptString r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + r.encode(ctx); + + CPPUNIT_ASSERT( (ctx.nb_read_bits() / 8) == 4) ; +} + + +/** +Extension ::= SEQUENCE { + extID INTEGER DEFAULT 2, + data OCTET STRING, + bits BitSTR DEFAULT {bit1} , + boolean BOOLEAN DEFAULT TRUE, + toto BitSTR DEFAULT {} +} +*/ + + +/** + * + */ +void TC_TEST_basic_types_optional::encode_Extension() +{ + const unsigned char seq[] = {0x30,0x02,0x04,0x00}; + Extension e; + + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + e.encode(ctx); + CPPUNIT_ASSERT((ctx.nb_read_bits()/8) == 4); +} + +/** + * + */ +void TC_TEST_basic_types_optional::encode_ExtensionOther() +{ + // 30 08 02 01 04 04 00 01 01 00 + Extension e; + e.extID = 4; + e.bit_mask.set(Extension::extID_present); + e.boolean = false; + e.bit_mask.set(Extension::boolean_present); + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + e.encode(ctx); + CPPUNIT_ASSERT((ctx.nb_read_bits()/8) == 10); +} + + +/** + * + */ +void TC_TEST_basic_types_optional::decode_Extension() +{ + const unsigned char seq[] = { 0x30,0x08,0x02,0x01,0x04,0x04,0x00,0x01,0x01,0x00 }; + Extension e; + + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + memcpy(ctx.buffer(),seq,10); + e.decode(ctx); + CPPUNIT_ASSERT(e.boolean == false); + CPPUNIT_ASSERT(e.extID == 4); +} + +void TC_TEST_basic_types_optional::decode_ReqDefaultInt() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + const unsigned char seqopt[] = {0x30,0x03,0x02,0x01,0x04,0x05,0x00}; + ReqDefaultInt r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + memcpy(ctx.buffer(),seq,4); + r.decode(ctx); + + CPPUNIT_ASSERT( r.extID == 2); + // Set the optional value + ctx.reset(); + memcpy(ctx.buffer(),seqopt,7); + + r.decode(ctx); + + CPPUNIT_ASSERT(r.extID == 4 ); +} +/** + * + */ +void TC_TEST_basic_types_optional::decode_ReqDefaultBool() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + const unsigned char seqopt[] = {0x30,0x03,0x01,0x01,0x04,0x05,0x00}; + ReqDefaultBool r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + memcpy(ctx.buffer(),seq,4); + r.decode(ctx); + + //CPPUNIT_ASSERT( r.extID.is_nul() == true); + CPPUNIT_ASSERT( r.extID == false); + // Set the optional value + ctx.reset(); + memcpy(ctx.buffer(),seqopt,7); + + r.decode(ctx); + + //CPPUNIT_ASSERT( r.extID.is_nul() == false); + CPPUNIT_ASSERT(r.extID == true ); +} + +/** + * + */ +void TC_TEST_basic_types_optional::decode_ReqDefaultString() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + const unsigned char seqopt[] = {0x30,0x06,0x16,0x02,0x30,0x31,0x05,0x00}; + ReqDefaultString r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + memcpy(ctx.buffer(),seq,4); + r.decode(ctx); + + CPPUNIT_ASSERT(std::string("james").compare(r.extID.get_sys_value()) == 0 ); + // Set the optional value + ctx.reset(); + memcpy(ctx.buffer(),seqopt,8); + + r.decode(ctx); + + CPPUNIT_ASSERT(std::string("01").compare(r.extID.get_sys_value()) == 0 ); +} + +/** + * + */ +void TC_TEST_basic_types_optional::decode_ReqOptInt() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + const unsigned char seqopt[] = {0x30,0x03,0x02,0x01,0x04,0x05,0x00}; + ReqOptInt r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + memcpy(ctx.buffer(),seq,4); + r.decode(ctx); + + CPPUNIT_ASSERT( r.extID.is_nul() == true); + // Set the optional value + ctx.reset(); + memcpy(ctx.buffer(),seqopt,7); + + r.decode(ctx); + + CPPUNIT_ASSERT(**(r.extID) == 4 ); +} +/** + * + */ +void TC_TEST_basic_types_optional::decode_ReqOptBool() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + const unsigned char seqopt[] = {0x30,0x03,0x01,0x01,0x04,0x05,0x00}; + ReqOptBool r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + memcpy(ctx.buffer(),seq,4); + r.decode(ctx); + + CPPUNIT_ASSERT( r.extID.is_nul() == true); + // Set the optional value + ctx.reset(); + memcpy(ctx.buffer(),seqopt,7); + + r.decode(ctx); + + CPPUNIT_ASSERT( r.extID.is_nul() == false); + CPPUNIT_ASSERT(**(r.extID) == true ); +} + +/** + * + */ +void TC_TEST_basic_types_optional::decode_ReqOptString() +{ + const unsigned char seq[] = {0x30,0x02,0x05,0x00}; + const unsigned char seqopt[] = {0x30,0x06,0x16,0x02,0x30,0x31,0x05,0x00}; + ReqOptString r; + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + + memcpy(ctx.buffer(),seq,4); + r.decode(ctx); + + CPPUNIT_ASSERT( r.extID.is_nul() == true); + // Set the optional value + ctx.reset(); + memcpy(ctx.buffer(),seqopt,8); + + r.decode(ctx); + + CPPUNIT_ASSERT( r.extID.is_nul() == false); + CPPUNIT_ASSERT(std::string("01").compare(r.extID->get_sys_value()) == 0 ); +} + diff --git a/tests/UNIT-TEST-basic-types-optional.h b/tests/UNIT-TEST-basic-types-optional.h new file mode 100644 index 0000000..439bb05 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-optional.h @@ -0,0 +1,63 @@ +#ifndef TESTCASE_BTYPE_OPT_H +#define TESTCASE_BTYPE_OPT_H + +#include + + +class TC_TEST_basic_types_optional : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_optional ); + CPPUNIT_TEST(encode_Request); + CPPUNIT_TEST(encode_ReqDefaultInt); + CPPUNIT_TEST(encode_ReqDefaultIntOther); + CPPUNIT_TEST(encode_ReqDefaultBool); + CPPUNIT_TEST(encode_ReqDefaultBoolOther); + CPPUNIT_TEST(encode_ReqDefaultString); + CPPUNIT_TEST(encode_ReqDefaultStringOther); + CPPUNIT_TEST(encode_Extension); + CPPUNIT_TEST(encode_ExtensionOther); + CPPUNIT_TEST(encode_ReqOptInt); + CPPUNIT_TEST(encode_ReqOptBool); + CPPUNIT_TEST(encode_ReqOptString); + + CPPUNIT_TEST(decode_Request); + CPPUNIT_TEST(decode_Extension); + CPPUNIT_TEST(decode_ReqDefaultInt); + CPPUNIT_TEST(decode_ReqDefaultBool); + CPPUNIT_TEST(decode_ReqDefaultString); + CPPUNIT_TEST(decode_ReqOptInt); + CPPUNIT_TEST(decode_ReqOptBool); + CPPUNIT_TEST(decode_ReqOptString); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_Request(); + void encode_ReqDefaultInt(); + void encode_ReqDefaultIntOther(); + void encode_ReqDefaultBool(); + void encode_ReqDefaultBoolOther(); + void encode_ReqDefaultString(); + void encode_ReqDefaultStringOther(); + void encode_Extension(); + void encode_ExtensionOther(); + void encode_ReqOptInt(); + void encode_ReqOptBool(); + void encode_ReqOptString(); + + void decode_Request(); + void decode_Extension(); + void decode_ReqDefaultInt(); + void decode_ReqDefaultBool(); + void decode_ReqDefaultString(); + void decode_ReqOptInt(); + void decode_ReqOptBool(); + void decode_ReqOptString(); + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types-sequence.cpp b/tests/UNIT-TEST-basic-types-sequence.cpp new file mode 100644 index 0000000..1fc2059 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-sequence.cpp @@ -0,0 +1,88 @@ +#include + +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types_sequence.h" +#include "UNIT-TEST-basic-types-sequence.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_sequence); + +using namespace TEST_basic_types_sequence; + +void TC_TEST_basic_types_sequence::setUp() +{ + +} + +void TC_TEST_basic_types_sequence::decode_Sequence() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x30,0x05,0x02,0x01,0x05,0x05,0x00}; + unsigned char *table = ctx.buffer(); + memcpy(table,seq,7); + TEST_Sequence S; + S.decode(ctx); + CPPUNIT_ASSERT(S.device==5); +} +void TC_TEST_basic_types_sequence::decode_ImplicitSequence() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x30,0x07,0x80,0x02,0x61,0x62,0x82,0x1,0x63}; + unsigned char *table = ctx.buffer(); + memcpy(table,seq,9); + TEST_Implicit_Sequence S; + S.decode(ctx); + CPPUNIT_ASSERT(std::string("ab").compare(S.s1.get_sys_value())==0); +} +void TC_TEST_basic_types_sequence::decode_IntegerList() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = { 0x30, 0x06, 0x02, 0x01, 0x0a, 0x02, 0x01, 0x0c}; + unsigned char *table = ctx.buffer(); + memcpy(table,seq,8); + Seq S; + S.decode(ctx); + CPPUNIT_ASSERT(S[0]==10); +} + +void TC_TEST_basic_types_sequence::encode_Sequence() +{ + const unsigned char seq[] = {0x30,0x05,0x02,0x01,0x06,0x05,0x00}; + asn1::streams::ber ctx; + TEST_Sequence S; + S.device = 6; + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); +} +void TC_TEST_basic_types_sequence::encode_ImplicitSequence() +{ + asn1::streams::ber ctx; + TEST_Implicit_Sequence S; + IA5String s(asn1::prim::types::String("ab")); + S.s1 = s; + //S.s2.get() = "c"; + S.s3.get() = "d"; + //S.encode(ctx); + m_codec.encode(ctx,S); + unsigned char seq[] = {0x30, 0x07, 0x80, 0x02, 0x61, 0x62, 0x82, 0x01,0x64 }; + int result = memcmp(ctx.buffer(),seq,9); + CPPUNIT_ASSERT(result==0); +} +void TC_TEST_basic_types_sequence::encode_IntegerList() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = { 0x30, 0x06, 0x02, 0x01, 0x0a, 0x02, 0x01, 0x0c}; + TEST_IntegerList S; + //Seq S; + asn1::INTEGER i(10),i2(12); + S.push_back(i); + S.push_back(i2); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,8); + CPPUNIT_ASSERT(result==0); +} diff --git a/tests/UNIT-TEST-basic-types-sequence.h b/tests/UNIT-TEST-basic-types-sequence.h new file mode 100644 index 0000000..c671f8f --- /dev/null +++ b/tests/UNIT-TEST-basic-types-sequence.h @@ -0,0 +1,39 @@ +#ifndef TESTCASE_SIMPLETYPE_H +#define TESTCASE_SIMPLETYPE_H + +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-basic-types-sequence.h" + +class TC_TEST_basic_types_sequence : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_sequence ); + + CPPUNIT_TEST(encode_IntegerList); + CPPUNIT_TEST(encode_Sequence); + CPPUNIT_TEST(encode_ImplicitSequence); + CPPUNIT_TEST(decode_IntegerList); + CPPUNIT_TEST(decode_Sequence); + CPPUNIT_TEST(decode_ImplicitSequence); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void decode_Sequence(); + void decode_IntegerList(); + void decode_ImplicitSequence(); + + void encode_IntegerList(); + void encode_ImplicitSequence(); + void encode_Sequence(); + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types-set.cpp b/tests/UNIT-TEST-basic-types-set.cpp new file mode 100644 index 0000000..503659a --- /dev/null +++ b/tests/UNIT-TEST-basic-types-set.cpp @@ -0,0 +1,89 @@ + + +#include + +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types_set.h" +#include "UNIT-TEST-basic-types-set.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_set); + +using namespace TEST_basic_types_set; + +void TC_TEST_basic_types_set::setUp() +{ + +} + +void TC_TEST_basic_types_set::encode_Set() +{ + const unsigned char seq[] = {0x31,0x05,0x02,0x01,0x06,0x05,0x00}; + asn1::streams::ber ctx; + TEST_Set S; + S.device = 6; + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_set::encode_SetOfInt() +{ + const unsigned char seq[] = {0x31,0x06,0x02,0x01,0x05,0x02,0x01,0x04}; + asn1::streams::ber ctx; + TEST_SetOfInt S; + Int i; + i = 5; + S.push_back(i); + i = 4; + S.push_back(i); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,8); + + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_set::encode_ImplicitSequence() +{ + asn1::streams::ber ctx; + // TEST_Implicit_Sequence S; + IA5String s(asn1::prim::types::String("ab")); +} + +void TC_TEST_basic_types_set::encode_IntegerList() +{ + asn1::streams::ber ctx; + asn1::INTEGER i(10),i2(12); +} + +/** + * Decode Stuff + */ + +void TC_TEST_basic_types_set::decode_Set() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x31,0x05,0x02,0x01,0x05,0x05,0x00}; + unsigned char *table = ctx.buffer(); + memcpy(table,seq,7); + TEST_Set S; + S.decode(ctx); + CPPUNIT_ASSERT(S.device==5); +} + +void TC_TEST_basic_types_set::decode_SetOfInt() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x31,0x06,0x02,0x01,0x03,0x02,0x01,0x08}; + unsigned char *table = ctx.buffer(); + memcpy(table,seq,8); + TEST_SetOfInt S; + S.decode(ctx); + CPPUNIT_ASSERT(S.size() == 2); +} + + diff --git a/tests/UNIT-TEST-basic-types-set.h b/tests/UNIT-TEST-basic-types-set.h new file mode 100644 index 0000000..d6a4875 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-set.h @@ -0,0 +1,39 @@ +#ifndef TESTCASE_SIMPLETYPE_H +#define TESTCASE_SIMPLETYPE_H + +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-basic-types-set.h" + +class TC_TEST_basic_types_set : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_set ); + CPPUNIT_TEST(encode_Set); + CPPUNIT_TEST(encode_SetOfInt); + CPPUNIT_TEST(encode_IntegerList); + CPPUNIT_TEST(encode_ImplicitSequence); + + CPPUNIT_TEST(decode_Set); + CPPUNIT_TEST(decode_SetOfInt); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_Set(); + void encode_IntegerList(); + void encode_ImplicitSequence(); + void encode_SetOfInt(); + + void decode_Set(); + void decode_SetOfInt(); + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types-tagged.cpp b/tests/UNIT-TEST-basic-types-tagged.cpp new file mode 100644 index 0000000..e002ea9 --- /dev/null +++ b/tests/UNIT-TEST-basic-types-tagged.cpp @@ -0,0 +1,291 @@ + + +#include + +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types_tagged.h" +#include "UNIT-TEST-basic-types-tagged.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types_tagged); + +using namespace TEST_basic_types_tagged; + +void TC_TEST_basic_types_tagged::setUp() +{ + +} + +void TC_TEST_basic_types_tagged::encode_TaggedInteger() +{ + asn1::streams::ber ctx; +// const unsigned char seq[] = {0x43,0x03,0x02,0x01,0x03}; + // Explicit tagging is constructed + const unsigned char seq[] = {0x63,0x03,0x02,0x01,0x03}; + Int S; + asn1::prim::types::Integer i = 3; + S = i; + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,5); + CPPUNIT_ASSERT(result == 0); +} + +void TC_TEST_basic_types_tagged::encode_TaggedSeq() +{ + const unsigned char seq[] = {0x62,0x07,0x30,0x05,0x02,0x01,0x06,0x05,0x00}; + asn1::streams::ber ctx; + SeqE S; + asn1::prim::types::Integer i = 6; + S.one = i; + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,9); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_tagged::encode_TaggedSeqE1() +{ + // Explicit tagging is construted + const unsigned char seq[] = {0x64,0x09,0x30,0x07,0x63,0x03,0x02,0x01,0x0A,0x05,0x00}; + asn1::streams::ber ctx; + SeqE1 S; + asn1::prim::types::Integer i = 10; + S.one = i; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,11); + CPPUNIT_ASSERT(result==0); +} + + +void TC_TEST_basic_types_tagged::encode_TaggedSeqI() +{ + const unsigned char seq[] = {0x65,0x05,0x55,0x01,0x06,0x56,0x00}; + asn1::streams::ber ctx; + SeqI S; + asn1::prim::types::Integer i = 6; + S.one = i; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_tagged::encode_TaggedInSeq() +{ + //const unsigned char seq[] = {0x30,0x0a,0xa0,0x03,0x02,0x01,0x06,0x43,0x03,0x02,0x01,0x09}; + // Explicit is constructed + // 30 06 a0 03 02 01 06 63 03 43 01 09 + const unsigned char seq[] = {0x30,0x0a,0xa0,0x03,0x02,0x01,0x06,0x63,0x03,0x02,0x01,0x09}; + asn1::streams::ber ctx; + InSeq S; + asn1::prim::types::Integer i = 6; + S.one = i; + Int nu; i= 9; + nu = i; + S.nu = nu; + //S.encode(ctx); + m_codec.encode(ctx,S); + int result = memcmp(ctx.buffer(),seq,12); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_tagged::encode_TaggedChoice() +{ + //const unsigned char seq[] = {0xa2,0x09,0x30,0x07,0x83,0x03,0x02,0x01,0x06,0x05,0x00}; + const unsigned char seq[] = {0x64,0x03,0x40,0x01,0x06}; + asn1::streams::ber ctx; + Choice S(Choice::typeof_one); + asn1::prim::types::Integer i = 6; + S.get_one() = i; + //S.kind_ = Choice::typeof_one; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,5); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_tagged::encode_TaggedChoiceSeqE() +{ + //const unsigned char seq[] = {0x62,0x07,0x30,0x05,0x02,0x01,0x06,0x05,0x00}; + //const unsigned char seq[] = {0xa2,0x09,0x30,0x07,0x83,0x03,0x02,0x01,0x06,0x05,0x00}; + const unsigned char seq[] = {0x64,0x09,0x62,0x07,0x30,0x05,0X02,0x01,0x6,0x05,0x00}; + asn1::streams::ber ctx; + Choice S(Choice::typeof_seqe,asn1::tag(asn1::types::APPLICATION,2)); + S.get_seqe().one = 6; + //S.kind_ = Choice::typeof_one; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,5); + CPPUNIT_ASSERT(result==0); +} + + +void TC_TEST_basic_types_tagged::encode_TaggedSetE() +{ + // 64 07 30 05 02 01 06 05 00 + const unsigned char seq[] = {0x64,0x07,0x31,0x05,0x02,0x01,0x06,0x05,0x00}; + asn1::streams::ber ctx; + TSetE S; + asn1::prim::types::Integer i = 6; + S.one = i; + S.encode(ctx); + int result = memcmp(ctx.buffer(),seq,9); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_tagged::encode_IntILT62() +{ + const unsigned char seq[] = {0x5F,0x3E,0x01,0x05}; + asn1::streams::ber ctx; + IntILT62 I; + I = 5; + I.encode(ctx); + int result = memcmp(ctx.buffer(),seq,4); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_tagged::encode_IntILT432() +{ + const unsigned char seq[] = {0x5F,0x83,0x30,0x01,0x05}; + asn1::streams::ber ctx; + IntILT432 I; + I = 5; + I.encode(ctx); + int result = memcmp(ctx.buffer(),seq,5); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types_tagged::encode_IntELT72() +{ + // 7f 48 03 02 01 05 + const unsigned char seq[] = {0x5F,0x83,0x30,0x01,0x05}; + asn1::streams::ber ctx; + IntELT72 I; + I = 5; + //I.encode(ctx); + m_codec.encode(ctx,I); + int result = memcmp(ctx.buffer(),seq,5); + CPPUNIT_ASSERT(result==0); +} + + + + + +#if 0 +void TC_TEST_basic_types_tagged::decode_TEST_SeqEnum() +{ + asn1::streams::ber ctx; + asn1::INTEGER i(10),i2(12); +} + +#endif + +void TC_TEST_basic_types_tagged::decode_IntILT62() +{ + const unsigned char seq[] = {0x5F,0x3E,0x01,0x05}; + asn1::streams::ber ctx; + IntILT62 I; + memcpy(ctx.buffer(),seq,4); + I.decode(ctx); + CPPUNIT_ASSERT(I.get_value()==5); +} + +void TC_TEST_basic_types_tagged::decode_IntILT432() +{ + const unsigned char seq[] = {0x5F,0x83,0x30,0x01,0x0a}; + asn1::streams::ber ctx; + IntILT432 I; + memcpy(ctx.buffer(),seq,5); + I.decode(ctx); + CPPUNIT_ASSERT(I.get_value()==10); +} + +void TC_TEST_basic_types_tagged::decode_IntELT72() +{ +} + + +void TC_TEST_basic_types_tagged::decode_TaggedInteger() +{ + asn1::streams::ber ctx; + //const unsigned char seq[] = {0x43,0x03,0x02,0x01,0x07}; + const unsigned char seq[] = {0x63,0x03,0x02,0x01,0x07}; + Int S; + memcpy(ctx.buffer(),seq,5); + //S.codec(ctx,S,asn1::CODEC_DECODE); + S.decode(ctx); + CPPUNIT_ASSERT( S.get_value() == 7); +} + + +void TC_TEST_basic_types_tagged::decode_TaggedSeq() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x62,0x07,0x30,0x05,0x02,0x01,0x06,0x05,0x00}; + SeqE S; + memcpy(ctx.buffer(),seq,9); + //S.codec(ctx,S,asn1::CODEC_DECODE); + S.decode(ctx); + CPPUNIT_ASSERT( S.one == 6); +} +void TC_TEST_basic_types_tagged::decode_TaggedSeqE1() +{ + asn1::streams::ber ctx; + //const unsigned char seq[] = {0x64,0x09,0x30,0x07,0x43,0x03,0x02,0x01,0x06,0x05,0x00}; + const unsigned char seq[] = {0x64,0x09,0x30,0x07,0x63,0x03,0x02,0x01,0x06,0x05,0x00}; + SeqE1 S; + memcpy(ctx.buffer(),seq,11); + S.decode(ctx); + CPPUNIT_ASSERT( S.one.get_value() == 6); +} + +void TC_TEST_basic_types_tagged::decode_TaggedSeqI() +{ + const unsigned char seq[] = {0x65,0x05,0x55,0x01,0x06,0x56,0x00}; + asn1::streams::ber ctx; + SeqI S; + memcpy(ctx.buffer(),seq,11); + S.decode(ctx); + int result = memcmp(ctx.buffer(),seq,7); + // CPPUNIT_ASSERT(result==0); + CPPUNIT_ASSERT( S.one.get_value() == 6); +} + + +void TC_TEST_basic_types_tagged::decode_TaggedInSeq() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x30,0x0a,0xa0,0x03,0x02,0x01,0x06,0x43,0x03,0x02,0x01,0x09}; + InSeq S; + memcpy(ctx.buffer(),seq,12); + S.decode(ctx); + CPPUNIT_ASSERT( S.one.get_value() == 6); +} + +void TC_TEST_basic_types_tagged::decode_TaggedChoice() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x64,0x03,0x40,0x01,0x06}; + Choice S; + memcpy(ctx.buffer(),seq,5); + S.decode(ctx); + CPPUNIT_ASSERT( S.get_one() == 6); +} + +void TC_TEST_basic_types_tagged::decode_TaggedSetE() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x64,0x07,0x31,0x05,0x02,0x01,0x06,0x05,0x00}; + TSetE S; + memcpy(ctx.buffer(),seq,9); + S.decode(ctx); + CPPUNIT_ASSERT( S.one == 6); +} + + + diff --git a/tests/UNIT-TEST-basic-types-tagged.h b/tests/UNIT-TEST-basic-types-tagged.h new file mode 100644 index 0000000..4861a0a --- /dev/null +++ b/tests/UNIT-TEST-basic-types-tagged.h @@ -0,0 +1,75 @@ +#ifndef TESTCASE_SIMPLETYPE_H +#define TESTCASE_SIMPLETYPE_H + +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-basic-types-tagged.h" + +class TC_TEST_basic_types_tagged : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_basic_types_tagged ); + CPPUNIT_TEST(encode_TaggedInteger); + CPPUNIT_TEST(encode_TaggedSeq); + CPPUNIT_TEST(encode_TaggedSeqE1); + CPPUNIT_TEST(encode_TaggedSeqI); + CPPUNIT_TEST(encode_TaggedInSeq); + CPPUNIT_TEST(encode_TaggedChoice); + CPPUNIT_TEST(encode_TaggedChoiceSeqE); + CPPUNIT_TEST(encode_TaggedSetE); + CPPUNIT_TEST(encode_IntILT62); + CPPUNIT_TEST(encode_IntILT432); + CPPUNIT_TEST(encode_IntELT72); + + CPPUNIT_TEST(decode_IntILT62); + CPPUNIT_TEST(decode_IntILT432); + CPPUNIT_TEST(decode_IntELT72); + CPPUNIT_TEST(decode_TaggedInteger); + CPPUNIT_TEST(decode_TaggedSeq); + CPPUNIT_TEST(decode_TaggedSeqE1); + CPPUNIT_TEST(decode_TaggedSeqI); + CPPUNIT_TEST(decode_TaggedInSeq); + CPPUNIT_TEST(decode_TaggedChoice); + CPPUNIT_TEST(decode_TaggedSetE); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_TaggedInteger(); + void encode_TaggedSeq(); + void encode_TaggedSeqE1(); + void encode_TaggedSeqI(); + void encode_TaggedInSeq(); + void encode_TaggedChoice(); + void encode_TaggedChoiceSeqE(); + void encode_TaggedSetE(); + void encode_IntILT62(); + void encode_IntILT432(); + void encode_IntELT72(); + + void decode_IntILT62(); + void decode_IntILT432(); + void decode_IntELT72(); + void decode_TaggedInteger(); + void decode_TaggedSeq(); + void decode_TaggedSeqE1(); + void decode_TaggedSeqI(); + void decode_TaggedInSeq(); + void decode_TaggedChoice(); + void decode_TaggedSetE(); +#if 0 + void encode_TaggedSeq(); + void decode_TaggedSeq(); + void decode_TEST_Enum(); + void decode_TEST_SeqEnum(); +#endif + protected: + asn1::streams::ber m_ctx; + asn1::codecBER m_codec; +}; + +#endif diff --git a/tests/UNIT-TEST-basic-types.cpp b/tests/UNIT-TEST-basic-types.cpp new file mode 100644 index 0000000..d2e7b23 --- /dev/null +++ b/tests/UNIT-TEST-basic-types.cpp @@ -0,0 +1,280 @@ +#include +#include +#include +#define MAIN +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "TEST_basic_types.h" +#include "UNIT-TEST-basic-types.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_basic_types); + +using namespace TEST_basic_types; + +void TC_TEST_basic_types::setUp() +{ + +} + +void TC_TEST_basic_types::encode_Test() +{ + std::string s("Jones"); + asn1::prim::types::String ps = s; + VisibleString os =ps; + VString1 vs1(os); + VString2 str; + str = vs1; + + asn1::streams::ber ctx; + unsigned char *table = ctx.buffer(); + table[0] = '\02'; table[1] = '\01';table[2] = '\05'; + TEST_basic_types::Test test; + //asn1::streams::ber::codec(ctx,test,asn1::CODEC_DECODE); + //test.codec(ctx,test,asn1::CODEC_DECODE); + test.decode(ctx); + ctx.nb_bits(-1*ctx.nb_read_bits()); + //str.codec(ctx,str,CODEC_ENCODE); + str.encode(ctx); + CPPUNIT_ASSERT(test.get_value()==5); +} + +void TC_TEST_basic_types::encode_TestI() +{ + const unsigned char seq[] = {0x02,0x01,0x01}; + TEST_basic_types::TestI i; + i = TEST_basic_types::TestI::one; + + asn1::streams::ber ctx; + + i.encode(ctx); + + int result = memcmp(ctx.buffer(),seq,3); + CPPUNIT_ASSERT(result == 0); +} + + +void TC_TEST_basic_types::encode_VString1() +{ + asn1::streams::ber ctx; + asn1::prim::types::String s("Jones"); + VString1 str; + str = s; + //str.codec(ctx,str,asn1::CODEC_ENCODE); + str.encode(ctx); + + const unsigned char seq[] = {0x1a,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types::encode_VString2() +{ + asn1::streams::ber ctx; + asn1::prim::types::String s("Jones"); + VString2 str; + str = VString1(s); + //codec(ctx,str,asn1::CODEC_ENCODE); + //str.codec(ctx,str,asn1::CODEC_ENCODE); + str.encode(ctx); + + const unsigned char seq[] = {0x43,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types::encode_VString3() +{ + asn1::streams::ber ctx; + asn1::prim::types::String s("Jones"); + // (VString2(VString1((std::string("Jones"))))); + VString2 str2; + str2 = VString1(s); + VString3 str; + str = str2; + + //str.codec(ctx,str,asn1::CODEC_ENCODE); + str.encode(ctx); + const unsigned char seq[] = {0xa2,0x07,0x43,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + int result = memcmp(ctx.buffer(),seq,9); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types::encode_VString4() +{ + asn1::streams::ber ctx; + asn1::prim::types::String s("Jones"); + //(VString3(VString2(VString1((std::string("Jones")))))); + VString2 str2; + str2 = VString1(s); + VString3 str3; + str3 = str2; + VString4 str; + str = str3; + //str = s; Fails during compilation + //str.codec(ctx,str,asn1::CODEC_ENCODE); + str.encode(ctx); + + const unsigned char seq[] = {0x67,0x07,0x43,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + int result = memcmp(ctx.buffer(),seq,9); + CPPUNIT_ASSERT(result==0); +} + +void TC_TEST_basic_types::encode_VString5() +{ + asn1::streams::ber ctx; + asn1::prim::types::String s("Jones"); + VString5 str ; + VString2 str2; + VString1 str1(s); + str2 = str1; + str = str2; + //str.codec(ctx,str,asn1::CODEC_ENCODE); + str.encode(ctx); + const unsigned char seq[] = {0x82,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); + +} + +void TC_TEST_basic_types::encode_BString() +{ + asn1::streams::ber ctx; + B_String str; + str[0]= 0x0a; + //str.codec(ctx,str,asn1::CODEC_ENCODE); + str.encode(ctx); + + const unsigned char seq[] = {0x03,0x02,0x04,0xa0}; + //int result = memcmp(ctx.buffer(),seq,4); + CPPUNIT_ASSERT_EQUAL((unsigned long)4,ctx.bytes()); + CPPUNIT_ASSERT_EQUAL(0,memcmp(ctx.buffer(),seq,4)); + +} + +// Decode string + +void TC_TEST_basic_types::decode_Test() +{ +} + +void TC_TEST_basic_types::decode_TestI() +{ + const unsigned char seq[] = {0x02,0x01,0x02}; + TEST_basic_types::TestI i; + asn1::streams::ber ctx; + + memcpy(ctx.buffer(),seq,3); + + i.decode(ctx); + + CPPUNIT_ASSERT(i.get_value() == 2); +} + +void TC_TEST_basic_types::decode_VString1() +{ + const unsigned char seq[] = {0x1a,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + asn1::streams::ber ctx; + memcpy(ctx.buffer(),seq,7); + VString1 str; + //str.codec(ctx,str,asn1::CODEC_DECODE); + str.decode(ctx); + CPPUNIT_ASSERT(std::string("Jones").compare(str.get_sys_value())==0); +} +void TC_TEST_basic_types::decode_VString2() +{ + const unsigned char seq[] = {0x43,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + asn1::streams::ber ctx; + memcpy(ctx.buffer(),seq,7); + VString2 str; + //str.codec(ctx,str,asn1::CODEC_DECODE); + str.decode(ctx); + CPPUNIT_ASSERT(std::string("Jones").compare(str.get_sys_value())==0); +} +void TC_TEST_basic_types::decode_VString3() +{ + const unsigned char seq[] = {0xa2,0x07,0x43,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + asn1::streams::ber ctx; + memcpy(ctx.buffer(),seq,9); + VString3 str; + //str.codec(ctx,str,asn1::CODEC_DECODE); + str.decode(ctx); + CPPUNIT_ASSERT(std::string("Jones").compare(str.get_sys_value())==0); +} +void TC_TEST_basic_types::decode_VString4() +{ + const unsigned char seq[] = {0x67,0x07,0x43,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + asn1::streams::ber ctx; + memcpy(ctx.buffer(),seq,9); + VString4 str; + //str.codec(ctx,str,asn1::CODEC_DECODE); + str.decode(ctx); + CPPUNIT_ASSERT(std::string("Jones").compare(str.get_sys_value())==0); +} +void TC_TEST_basic_types::decode_VString5() +{ + const unsigned char seq[] = {0x82,0x05,0x4a,0x6f,0x6e,0x65,0x73}; + asn1::streams::ber ctx; + memcpy(ctx.buffer(),seq,7); + VString5 str; + //str.codec(ctx,str,asn1::CODEC_DECODE); + str.decode(ctx); + CPPUNIT_ASSERT(std::string("Jones").compare(str.get_sys_value())==0); +} + +void TC_TEST_basic_types::decode_BString() +{ + const unsigned char seq[] = {0x03,0x02,0x04,0xa0}; + asn1::streams::ber ctx; + + B_String str; + memcpy(ctx.buffer(),seq,4); + //str.codec(ctx,str,asn1::CODEC_DECODE); + str.decode(ctx); + CPPUNIT_ASSERT(str[0]==0x0a); +} + +/** + * OCTET STRING TESTS + */ +void TC_TEST_basic_types::ostring_equal() +{ + O_String a,b; + asn1::prim::types::String s("Jones"); + a = s; + b = a; + CPPUNIT_ASSERT(a == b); + // b = std::string("toto"); + //CPPUNIT_ASSERT(a != b); +} + +void TC_TEST_basic_types::ostring_copy() +{ + O_String a,b; + a = std::string("toto"); + b = a; + CPPUNIT_ASSERT(a == b); +} + +/** + * OBJECT IDENTIFIER TESTS + */ +void TC_TEST_basic_types::oid_equal() +{ + TestOid a,b; + id_1 v; + a = id_1(); + b = v; + std::cerr<<"ARRAY: a="< +#include "rtasn1/asn1.h" + + +class TC_TEST_primary_types : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_primary_types ); + CPPUNIT_TEST(encode_Null); + CPPUNIT_TEST(encode_Boolean); + CPPUNIT_TEST(encode_Integer); + CPPUNIT_TEST(encode_Integer1); + CPPUNIT_TEST(encode_Integer127); + CPPUNIT_TEST(encode_Integer128); + CPPUNIT_TEST(encode_Integer256); + CPPUNIT_TEST(encode_Integer_n128); + CPPUNIT_TEST(encode_Integer_n129); + CPPUNIT_TEST(encode_Integer235); + CPPUNIT_TEST(encode_Real); + CPPUNIT_TEST(encode_BitString); + CPPUNIT_TEST(encode_OctetString); + CPPUNIT_TEST(encode_UTF8String); + CPPUNIT_TEST(encode_NumericString); + CPPUNIT_TEST(encode_PrintableString); + CPPUNIT_TEST(encode_TeletexString); + CPPUNIT_TEST(encode_VideotexString); + CPPUNIT_TEST(encode_IA5String); + CPPUNIT_TEST(encode_GraphicString); + CPPUNIT_TEST(encode_VisibleString); + CPPUNIT_TEST(encode_GeneralString); + CPPUNIT_TEST(encode_UniversalString); + CPPUNIT_TEST(encode_BMPString); + CPPUNIT_TEST(encode_Oid); + CPPUNIT_TEST(decode_Null); + CPPUNIT_TEST(decode_Boolean); + CPPUNIT_TEST(decode_Integer); + CPPUNIT_TEST(decode_Integer1); + CPPUNIT_TEST(decode_Integer127); + CPPUNIT_TEST(decode_Integer128); + CPPUNIT_TEST(decode_Integer256); + CPPUNIT_TEST(decode_Integer_n128); + CPPUNIT_TEST(decode_Integer_n129); + CPPUNIT_TEST(decode_Integer235); + CPPUNIT_TEST(decode_Real); + CPPUNIT_TEST(decode_BitString); + CPPUNIT_TEST(decode_OctetString); + + CPPUNIT_TEST(decode_UTF8String); + CPPUNIT_TEST(decode_NumericString); + CPPUNIT_TEST(decode_PrintableString); + CPPUNIT_TEST(decode_TeletexString); + CPPUNIT_TEST(decode_VideotexString); + CPPUNIT_TEST(decode_IA5String); + CPPUNIT_TEST(decode_GraphicString); + CPPUNIT_TEST(decode_VisibleString); + CPPUNIT_TEST(decode_GeneralString); + CPPUNIT_TEST(decode_UniversalString); + CPPUNIT_TEST(decode_BMPString); + CPPUNIT_TEST(decode_Oid); + CPPUNIT_TEST_SUITE_END(); +/** + typedef asn1::types::EXPLICIT UTF8String; + + typedef asn1::types::EXPLICIT NumericString; + typedef asn1::types::EXPLICIT PrintableString; + typedef asn1::types::EXPLICIT TeletexString; + typedef asn1::types::EXPLICIT VideotexString; + typedef asn1::types::EXPLICIT IA5String; + typedef asn1::types::EXPLICIT GraphicString; + typedef asn1::types::EXPLICIT VisibleString; + typedef asn1::types::EXPLICIT GeneralString; + typedef asn1::types::EXPLICIT UniversalString; + typedef asn1::types::EXPLICIT BMPString; +*/ + + public: + void setUp(); + protected: + + void encode_Null(); + void encode_Boolean(); + void encode_Integer(); + void encode_Integer1(); + void encode_Integer127(); + void encode_Integer128(); + void encode_Integer256(); + void encode_Integer_n128(); + void encode_Integer_n129(); + void encode_Integer235(); + void encode_Real(); + void encode_BitString(); + void encode_OctetString(); + void encode_UTF8String(); + void encode_NumericString(); + void encode_PrintableString(); + void encode_TeletexString(); + void encode_VideotexString(); + void encode_IA5String(); + void encode_GraphicString(); + void encode_VisibleString(); + void encode_GeneralString(); + void encode_UniversalString(); + void encode_BMPString(); + void encode_Oid(); + + //decoging program + void decode_Null(); + void decode_Boolean(); + void decode_Integer(); + void decode_Integer1(); + void decode_Integer127(); + void decode_Integer128(); + void decode_Integer256(); + void decode_Integer_n128(); + void decode_Integer_n129(); + void decode_Integer235(); + void decode_Real(); + void decode_BitString(); + void decode_OctetString(); + void decode_UTF8String(); + void decode_NumericString(); + void decode_PrintableString(); + void decode_TeletexString(); + void decode_VideotexString(); + void decode_IA5String(); + void decode_GraphicString(); + void decode_VisibleString(); + void decode_GeneralString(); + void decode_UniversalString(); + void decode_BMPString(); + void decode_Oid(); + protected: + asn1::codecBER m_codec; + asn1::streams::ber m_ctx; +}; + +#endif diff --git a/tests/UNIT-TEST-private-types-choice.cpp b/tests/UNIT-TEST-private-types-choice.cpp new file mode 100644 index 0000000..56e38c5 --- /dev/null +++ b/tests/UNIT-TEST-private-types-choice.cpp @@ -0,0 +1,175 @@ +#include +#include +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-private-types-choice.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( TC_TEST_private_types_choice); + +using namespace TEST_private_types_choice; + +void TC_TEST_private_types_choice::setUp() +{ + +} + +void TC_TEST_private_types_choice::encode_len() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x30,0x05,0x02,0x01,0x0b,0x05,0x00}; + TEST_Sequence S; + S.device.set_tag(asn1::tag(asn1::types::UNIVERSAL,2)); + S.device.get_len() = 11; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); +} + + +void TC_TEST_private_types_choice::encode_number() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x30,0x05,0x80,0x01,0x0d,0x05,0x00}; + TEST_Sequence S; + //TEST_Sequence::device_t dev(TEST_Sequence::device_t::typeof_number,asn1::tag(asn1::types::CONTEXT_SPECIFIC,0)); + TEST_Sequence_device dev(TEST_Sequence_device::typeof_number,asn1::tag(asn1::types::CONTEXT_SPECIFIC,0)); + dev.get_number() = 13; + S.device.set_tag(asn1::tag(asn1::types::CONTEXT_SPECIFIC,0)); + S.device = dev; + //S.codec(ctx,S,asn1::CODEC_ENCODE); + S.encode(ctx); + + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result==0); +} +/** +TEST-ChoiceCplx ::= CHOICE { + cseq SEQUENCE { + s1 INTEGER + }, + cset SET { + s2 BOOLEAN, + s21 BOOLEAN + }, + cchoice CHOICE { + s3 OCTET STRING, + s31 NULL + } +} +*/ +void TC_TEST_private_types_choice::encode_cseq() +{ + const unsigned char seq[] = {0xa1,0x05,0x30,0x03,0x02,0x01,0x09}; + asn1::streams::ber ctx; + TEST_ChoiceCplx c(TEST_ChoiceCplx::typeof_cseq); + + c.get_cseq().s1 = 9; + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + + int result = memcmp(ctx.buffer(),seq,7); + CPPUNIT_ASSERT(result == 0); +} + +void TC_TEST_private_types_choice::encode_cset() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0xa1,0x08,0x31,0x06,0x01,0x01,0xFF,0x01,0x1,0x00}; + //TEST_ChoiceCplx c(TEST_ChoiceCplx::typeof_cset,asn1::tag(0,TEST_ChoiceCplx::typeof_cset)); + TEST_ChoiceCplx c(TEST_ChoiceCplx::typeof_cset,asn1::tag(0,17)); + + c.get_cset().s2 = true; + c.get_cset().s21 = false; + //c.encode(ctx); + //c.codec(ctx,c,asn1::CODEC_ENCODE); + c.encode(ctx); + + int result = memcmp(ctx.buffer(),seq,10); + CPPUNIT_ASSERT(result == 0); +} + +void TC_TEST_private_types_choice::encode_cchoice() +{ + const unsigned char seq[] = {0xa1,0x04,0xa2,0x02,0x81,0x00}; + //const unsigned char seq[] = {0xa1,0x02,0x81,0x00,0x00,0x00}; + asn1::streams::ber ctx; + TEST_ChoiceCplx c(TEST_ChoiceCplx::typeof_cchoice,asn1::tag(2,2)); + + c.get_cchoice().get_s31(); + c.encode(ctx); + + int result = memcmp(ctx.buffer(),seq,6); + CPPUNIT_ASSERT(result == 0); +} +// decoding + +void TC_TEST_private_types_choice::decode_len() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x30,0x05,0x02,0x01,0x0d,0x05,0x00}; + TEST_Sequence S; + memcpy(ctx.buffer(),seq,7); + //S.codec(ctx,S,asn1::CODEC_DECODE); + S.decode(ctx); + + CPPUNIT_ASSERT(S.device.get_len()==13); +} +void TC_TEST_private_types_choice::decode_number() +{ + asn1::streams::ber ctx; + const unsigned char seq[] = {0x30,0x05,0x80,0x01,0x0d,0x05,0x00}; + TEST_Sequence S; + memcpy(ctx.buffer(),seq,7); + //S.codec(ctx,S,asn1::CODEC_DECODE); + S.decode(ctx); + + CPPUNIT_ASSERT(S.device.get_number()==13); +} + +void TC_TEST_private_types_choice::decode_cseq() +{ + const unsigned char seq[] = {0xa1,0x05,0x30,0x03,0x02,0x01,0x08}; + asn1::streams::ber ctx; + TEST_ChoiceCplx c(TEST_ChoiceCplx::typeof_cseq); + + memcpy(ctx.buffer(),seq,7); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + + CPPUNIT_ASSERT(c.get_cseq().s1 == 8); +} +void TC_TEST_private_types_choice::decode_cset() +{ + const unsigned char seq[] = {0xa1,0x08,0x31,0x06,0x01,0x01,0xFF,0x01,0x1,0x00}; + asn1::streams::ber ctx; + TEST_ChoiceCplx c(TEST_ChoiceCplx::typeof_cseq); + + memcpy(ctx.buffer(),seq,10); + //c.codec(ctx,c,asn1::CODEC_DECODE); + c.decode(ctx); + + CPPUNIT_ASSERT( (c.get_cset().s21 == false) && (c.get_cset().s2 == true)); +} + +/** + * + */ +void TC_TEST_private_types_choice::decode_cchoice() +{ + const unsigned char seq[] = {0xa1,0x04,0xa2,0x02,0x81,0x00}; + asn1::streams::ber ctx; + //TEST_ChoiceCplx c(TEST_ChoiceCplx::typeof_cchoice,asn1::tag(0,5)); + TEST_ChoiceCplx c; + + memcpy(ctx.buffer(),seq,6); + int res = c.decode(ctx); + std::cerr<<"Kind:"< +#include "TEST_private_types_choice.h" + + +class TC_TEST_private_types_choice : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_private_types_choice ); + CPPUNIT_TEST(encode_len); + CPPUNIT_TEST(encode_number); + CPPUNIT_TEST(encode_cseq); + CPPUNIT_TEST(encode_cset); + CPPUNIT_TEST(encode_cchoice); + CPPUNIT_TEST(decode_len); + CPPUNIT_TEST(decode_number); + CPPUNIT_TEST(decode_cseq); + CPPUNIT_TEST(decode_cset); + CPPUNIT_TEST(decode_cchoice); + + + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_len(); + void encode_number(); + void encode_cseq(); + void encode_cset(); + void encode_cchoice(); + + void decode_len(); + void decode_number(); + void decode_cseq(); + void decode_cset(); + void decode_cchoice(); + protected: + asn1::codecBER m_codec; + asn1::streams::ber m_ctx; +}; + +#endif diff --git a/tests/UNIT-TEST-type-parameter.h b/tests/UNIT-TEST-type-parameter.h new file mode 100644 index 0000000..8d993f5 --- /dev/null +++ b/tests/UNIT-TEST-type-parameter.h @@ -0,0 +1,29 @@ +#ifndef TESTCASE_SIMPLETYPE_H +#define TESTCASE_SIMPLETYPE_H + +#include + +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "UNIT-TEST-type-parameter.h" + +class TC_TEST_type_parameter : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( TC_TEST_type_parameter ); + CPPUNIT_TEST(encode_call); + CPPUNIT_TEST(decode_call); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp(); + protected: + + void encode_call(); + void decode_call(); + protected: + asn1::codecBER m_codec; + asn1::streams::ber m_ctx; +}; + +#endif diff --git a/tests/main_asn1_type_sizes.cpp b/tests/main_asn1_type_sizes.cpp new file mode 100644 index 0000000..302f272 --- /dev/null +++ b/tests/main_asn1_type_sizes.cpp @@ -0,0 +1,62 @@ +#include +#include +//#define MAIN +#include "rtasn1/asn1_config.h" +#include "rtasn1/asn1.h" +#include "rtasn1/asn1_codec.h" +#include "rtasn1/asn1_codec_ber.h" +#include "rtasn1/asn1_codec_jer.h" + +void test_codec() +{ + asn1::INTEGER i; + asn1::streams::ber ctx(500); + asn1::codecBER cb; + + cb.encode(ctx,i); + +} + +void test_codec_jer() +{ + asn1::INTEGER i; + asn1::streams::jer ctx(500); + asn1::codecJER cb; + + cb.encode(ctx,i); + +} + + +/** + * The aim of this program is to display the + * size of all basic objects. + */ +int main(int argc,char **argv) +{ + asn1::Set setof; + asn1::Seq seqof; + + std::cout<<"Asn1p runtime library, size of type"< 1) && strcmp(argv[1],"-r") == 0) + asn1::types::debug_level = 1; + + // Create the event manager and test controller + CPPUNIT_NS::TestResult controller; + + // Add a listener that colllects test result + CPPUNIT_NS::TestResultCollector result; + controller.addListener( &result ); + + // Add a listener that print dots as test run. + CPPUNIT_NS::BriefTestProgressListener progress; + controller.addListener( &progress ); + + // Add the top suite to the test runner + CPPUNIT_NS::TestRunner runner; + runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() ); + runner.run( controller ); + + // Print test in a compiler compatible format. + CPPUNIT_NS::CompilerOutputter outputter( &result, CPPUNIT_NS::stdCOut() ); + outputter.write(); + + // Test xml output + std::ofstream xmlFile("Asn1TestResults.xml"); + CPPUNIT_NS::XmlOutputter xmlOutput(&result,xmlFile); + xmlOutput.write(); + return result.wasSuccessful() ? 0 : 1; + +} diff --git a/tests/modules.txt b/tests/modules.txt new file mode 100644 index 0000000..1095751 --- /dev/null +++ b/tests/modules.txt @@ -0,0 +1,11 @@ +TEST-basic-types +TEST-basic-types-integer-limits +TEST-basic-types-implicit +TEST-basic-types-explicit +TEST-basic-types-sequence +TEST-basic-types-set +TEST-basic-types-enum +TEST-basic-types-choice +TEST-private-types-choice +TEST-basic-types-tagged +TEST-basic-types-optional diff --git a/tests/poc-codec.h b/tests/poc-codec.h new file mode 100644 index 0000000..d8f0dbc --- /dev/null +++ b/tests/poc-codec.h @@ -0,0 +1,22 @@ + + +/** + * Should be initiliazed with an array of functions + * constrains, + * each type of the project has is pair of encoding/decoding function + */ +class PocCodecBER : public asn1::codecBER +{ + public: + PocCodecBER(); + + void encode(asn1::context &ctx,const long l); + + long &decode(asn1::context &ctx,long &l); + + +}; + +/* + * vim: et sw=2 ts=2 list: + */ diff --git a/tests/poc-codec.hpp b/tests/poc-codec.hpp new file mode 100644 index 0000000..96173af --- /dev/null +++ b/tests/poc-codec.hpp @@ -0,0 +1,4 @@ + +template <> +asn1::codecBER::encode(asn1::context &ctx,long l) +{ static_cast(this)->encode(ctx,l); }; diff --git a/tests/source.asn1 b/tests/source.asn1 new file mode 100644 index 0000000..6e4d23b --- /dev/null +++ b/tests/source.asn1 @@ -0,0 +1,872 @@ +-- +-- Test-basic-types +-- +TEST-basic-types {iso(1) identified-organization(3) 1} +DEFINITIONS ::= +BEGIN +Test::=INTEGER +TestI ::=INTEGER { one(1), two(2) ,tree(3)} +TestOid ::= OBJECT IDENTIFIER +O-String::= OCTET STRING(SIZE(1..32)) + +B-String ::= BIT STRING { + default(0), + one(1), + two(2) +} + +VString1 ::= VisibleString + +VString2 ::= [APPLICATION 3] IMPLICIT VString1 + +VString3 ::= [2] EXPLICIT VString2 + +VString4 ::= [APPLICATION 7] IMPLICIT VString3 + +VString5 ::= [2] IMPLICIT VString2 + +id-1 OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7} +id-2 OBJECT IDENTIFIER ::= { 1 3 } +id-3 OBJECT IDENTIFIER ::= { 1 2 } +END + +-- +-- Test-basic-types-integer-limits +-- +TEST-basic-types-integer-limits {iso(1) identified-organization(3) 1 2} +DEFINITIONS ::= +BEGIN + +SByte ::=INTEGER(-127..128) +UByte ::=INTEGER(0..255) + +SWord ::= INTEGER(-32767..3232768) +UWord ::= INTEGER(0..65535) + +SDWord ::= INTEGER(-2147483647..2147483648) +UDWord ::= INTEGER(0..4294967295) + +END + + +-- +-- Test-basic-types-explicit +-- +TEST-basic-values {iso(1) identified-organization(3) 2 } +DEFINITIONS ::= +BEGIN + +vi INTEGER ::= 8 + +nul IA5String ::= { 0, 0} + +soh IA5String ::= { 0, 1} + +latinCapitalLetterA BMPString ::= {0,0,0,65} + +OpCode ::= CHOICE +{ + local INTEGER, + global OBJECT IDENTIFIER +} + +gsr1 OpCode ::= local : 5 + +gsr2 OpCode ::= global : { iso(1) 3} +END + +-- +-- Test-basic-types-explicit +-- +TEST-basic-types-explicit {iso(1) identified-organization(3) 3} +DEFINITIONS ::= +BEGIN +Test::= [APPLICATION 0] EXPLICIT INTEGER + +O-String::= [APPLICATION 1] EXPLICIT OCTET STRING(SIZE(1..32)) + +B-String::= [APPLICATION 2] EXPLICIT BIT STRING(SIZE(1..16)) + +Bool-String::= [APPLICATION 3] EXPLICIT BOOLEAN +END + +-- +-- Test-basic-types-implicit +-- +TEST-basic-types-implicit {iso(1) identified-organization(3) 4} +DEFINITIONS ::= +BEGIN +Test::=INTEGER + +Ti ::= [8] IMPLICIT INTEGER + +TEST-Seq::= SEQUENCE { + t1 INTEGER OPTIONAL, + t2 [0] IMPLICIT INTEGER OPTIONAL, + t3 [1] IMPLICIT INTEGER OPTIONAL +} + +TEST-Choice::= CHOICE { + c1 [0] IMPLICIT INTEGER , + c2 [1] IMPLICIT INTEGER , + c3 [2] IMPLICIT INTEGER +} + + + +TEST-IntegerList ::= SEQUENCE OF INTEGER + +NumberDigits ::= IA5String +DeviceInfo ::= NULL +AgentState ::= NULL +CSTAPrivateData ::= BOOLEAN +ForwardingType ::= ENUMERATED { + un(1) + , deux(2) +} + +ListForwardParameters ::= SEQUENCE OF SEQUENCE + { forwardingType ForwardingType, + forwardDN NumberDigits } + +QueryDeviceInformation ::= CHOICE { + msgWaitingOn [0] IMPLICIT BOOLEAN, + doNotDisturbOn [1] IMPLICIT BOOLEAN, + forward [2] IMPLICIT ListForwardParameters, + lastDialedNumber [3] IMPLICIT NumberDigits, + deviceInfo [4] IMPLICIT DeviceInfo, + agentState [5] IMPLICIT AgentState } + +QueryDeviceResult ::= --snacc isPdu:"TRUE" -- CHOICE + { deviceInformation [0] QueryDeviceInformation, + [1] SEQUENCE + { deviceInfoBis QueryDeviceInformation, + extensions CSTAPrivateData OPTIONAL } } + + + + +END + +-- +-- Test-basic-types-choice +-- +TEST-basic-types-choice {iso(1) identified-organization(3) 5} +DEFINITIONS ::= +BEGIN + +IP4Address ::= SEQUENCE +{ + address OCTET STRING (SIZE(4)), + portNumber INTEGER(0..65535) OPTIONAL +} + +TEST-Choice::=CHOICE { + device INTEGER, + name IA5String, + b1 BOOLEAN, + ip4 IP4Address +} + +TEST-Choice1::=CHOICE { + device [0] IMPLICIT INTEGER, + i2 [1] IMPLICIT INTEGER, + b1 [2] IMPLICIT BOOLEAN, + bs1 [3] IMPLICIT BIT STRING, + os1 [4] IMPLICIT OCTET STRING, + nul [5] IMPLICIT NULL +} +-- application level tags +ChoiceA ::= CHOICE { + i [APPLICATION 0] IMPLICIT INTEGER, + b [APPLICATION 1] IMPLICIT BOOLEAN +} +-- context specific tags +ChoiceB ::= CHOICE { + ib [1] IMPLICIT INTEGER, + bb [2] IMPLICIT BOOLEAN +} +-- Simulate csta acse apdu... +ChoiceChoice ::= CHOICE { + -- Tag is required for ChoiceA because the underlying type is a Choice as + -- well. + choicea [0] ChoiceA, + choiceb [1] ChoiceB +} + + +END + +-- +-- Test-basic-types-sequence +-- +TEST-basic-types-sequence {iso(1) identified-organization(3) 6} +DEFINITIONS ::= +BEGIN + +TEST-Sequence::= SEQUENCE { + device INTEGER, + name NULL +} + +TEST-SeqSeq ::= SEQUENCE { + ss1 SEQUENCE { + ss2 IA5String + } +} + +TEST-Implicit-Sequence ::= SEQUENCE { + s1 [0] IMPLICIT IA5String, + s2 [1] IMPLICIT IA5String OPTIONAL, + s3 [2] IMPLICIT IA5String OPTIONAL + +} + +TEST-IntegerList ::= SEQUENCE OF INTEGER + +TEST-SeqOfSeq ::= SEQUENCE OF SEQUENCE { + device INTEGER, + present BOOLEAN +} + +TEST-CplxSeq ::= SEQUENCE { + s1 VisibleString(SIZE(0..64)), + i1 [0] IMPLICIT SEQUENCE OF INTEGER OPTIONAL, + i2 [1] IMPLICIT SEQUENCE OF SEQUENCE { + b1 BOOLEAN, + n NULL + } +} + +TEST-CplxSeqNm ::= SEQUENCE { + i2 [1] IMPLICIT SEQUENCE OF nmSeq SEQUENCE { + b1 BOOLEAN, + n NULL + } +} + +END + +-- +-- TEST-basic-types-set +-- +TEST-basic-types-set {iso(1) identified-organization(3) 7} +DEFINITIONS ::= +BEGIN + +TEST-Set::= SET { + device INTEGER, + name NULL +} + +TEST-Set1 ::= SET { + device INTEGER, + devices SEQUENCE OF INTEGER, + deviceSet SET OF INTEGER +} + +Int ::= INTEGER + +OString ::= OCTET STRING (SIZE(0..64)) + +TEST-SetOfOString ::= SET OF OString + +TEST-SetOfInt ::= SET SIZE(1..4) OF Int + +END + +-- +-- TEST-basic-types-enum +-- +TEST-basic-types-enum {iso(1) identified-organization(3) 8} +DEFINITIONS ::= +BEGIN + +TEST-Enum::= ENUMERATED { + null(0), + one(1), + two(2) +} + +TEST-SeqEnum ::= SEQUENCE { + enum1 TEST-Enum, + enum2 ENUMERATED { no(0), yes(1)}, + enum3 ENUMERATED {true } OPTIONAL +} + +Presence ::= ENUMERATED {optional,conditional,mandatory} + +Criticality::= ENUMERATED {reject,ignore,notify} +END + +-- +-- TEST-basic-types-tagged +-- +TEST-basic-types-tagged {iso(1) identified-organization(3) 9} +DEFINITIONS ::= +BEGIN + +Int ::= [APPLICATION 3] INTEGER +IntELT72 ::= [APPLICATION 72] INTEGER (0..255) + +SeqE ::= [APPLICATION 2] EXPLICIT SEQUENCE { + one INTEGER, + nu NULL +} + +SeqE1 ::= [APPLICATION 4] EXPLICIT SEQUENCE { + one Int, + nu NULL +} + +IntI ::= [APPLICATION 21] IMPLICIT INTEGER +OctI ::= [APPLICATION 22] IMPLICIT OCTET STRING +IntILT62 ::= [APPLICATION 62] IMPLICIT INTEGER +IntILT432 ::= [APPLICATION 432] IMPLICIT INTEGER + + +SeqI ::= [APPLICATION 5] IMPLICIT SEQUENCE { + one IntI, + two OctI +} + +SeqI1 ::= [APPLICATION 6] IMPLICIT SEQUENCE { + one Int, + nu NULL +} + +SeqP ::= [APPLICATION 5] SEQUENCE { + seq [APPLICATION 10] SEQUENCE { + one INTEGER, + two BOOLEAN + }, + nu NULL +} + + + +Choice ::= [APPLICATION 4] CHOICE { + one [APPLICATION 0] IMPLICIT INTEGER, + nu NULL, + seqe SeqE +} + +InSeq ::= SEQUENCE { + one [0 ] INTEGER, + nu Int +} + +TSetE ::= [APPLICATION 4] SET { + one INTEGER, + nu NULL +} + +TSetI ::= [APPLICATION 6] IMPLICIT SET { + one INTEGER, + nu NULL +} +END + + + +-- +-- TEST-private-types-choice +-- +TEST-private-types-choice {iso(1) identified-organization(3) 10} +DEFINITIONS ::= +BEGIN + +TEST-Sequence::= SEQUENCE { + device CHOICE { + len INTEGER, + number [0] IMPLICIT INTEGER + }, + name NULL +} + +TEST-SeqChoiceSeq ::= SEQUENCE { + v CHOICE { + s1 [0] IMPLICIT SEQUENCE { + name VisibleString, + n NULL + }, + s2 [1] IMPLICIT SEQUENCE { + n NULL, + nm VisibleString + } + -- Does not work yet !!!! + , + s3 [2] IMPLICIT SEQUENCE OF SEQUENCE { + p GraphicString, + pm VisibleString OPTIONAL + } + } +} + +-- +-- Working on generator to support this case !!!! +-- Main issue with CHOICE SET. SET does not handle private structure +-- missing scope + +TEST-ChoiceCplx ::= [1] CHOICE { + cseq SEQUENCE { + s1 INTEGER + }, + cset SET { + s2 BOOLEAN, + s21 BOOLEAN + }, + cchoice [2] CHOICE { + s3 [0] IMPLICIT OCTET STRING, + s31 [1] IMPLICIT NULL + } +} + + +END + +TEST-private-types-seq-of {iso(1) identified-organization(3) 11} +DEFINITIONS ::= +BEGIN + +TEST-Sequence::= SEQUENCE { + device CHOICE { + len INTEGER, + number [0] IMPLICIT INTEGER + }, + name NULL +} + +TEST-SeqChoiceSeq ::= SEQUENCE { + v CHOICE { + s1 [0] IMPLICIT SEQUENCE { + name VisibleString, + n NULL + }, + s2 [1] IMPLICIT SET OF CHOICE { + n NULL, + nm VisibleString + }, + s3 [2] IMPLICIT SEQUENCE OF SEQUENCE { + p GraphicString, + pm VisibleString OPTIONAL + } + } + + +} +END + + +-- +-- TEST-basic-types-selection +-- +TEST-basic-types-selection {iso(1) identified-organization(3) 12} +DEFINITIONS ::= +BEGIN + +TEST-Selection::= SEQUENCE { + -- len nm < TEST-SeqSelectReference , + number [0] IMPLICIT INTEGER, + name NULL +} + +TEST-SeqSelectReference ::= CHOICE { + name VisibleString, + n NULL, + s2 [1] BOOLEAN, + nm VisibleString +} + + +END + +-- +-- Test optionnal +-- +TEST-basic-types-optional {iso(1) identified-organization(3) 13} +DEFINITIONS ::= +BEGIN + +Request ::= SEQUENCE { + requestID INTEGER, + extention Extension OPTIONAL +} + +ReqDefaultInt ::= SEQUENCE { + extID INTEGER DEFAULT 2, + nul NULL +} + +ReqDefaultBool ::= SEQUENCE { + extID BOOLEAN DEFAULT FALSE, + nul NULL +} +-- Still bug +ReqDefaultString ::= SEQUENCE { + extID IA5String DEFAULT "james" , + nul NULL +} + +ReqOptInt ::= SEQUENCE { + extID INTEGER OPTIONAL, + nul NULL +} + +ReqOptBool ::= SEQUENCE { + extID BOOLEAN OPTIONAL, + nul NULL +} + +ReqOptString ::= SEQUENCE { + extID IA5String OPTIONAL, + nul NULL +} + +Extension ::= SEQUENCE { + extID INTEGER DEFAULT 2, + data OCTET STRING, + bits BitSTR DEFAULT {bit1} , + boolean BOOLEAN DEFAULT TRUE, + toto BitSTR DEFAULT {} +} + +BitSTR ::= BIT STRING { + nul(0), + bit1(1), + bit2(2), + bit3(3) +} + +END + + +-- +--- H323 needs parameterized support +-- + +-- +-- Simple parametered type +-- +TEST-type-parameter {iso(1) identified-organization(3) 14} +DEFINITIONS ::= +BEGIN + + Aa ::= INTEGER +--TEST-PSeq{MyType}::= SEQUENCE { +-- 2017/07/27 Still issue with otag. Suspect that +-- reparenting does not work with parameterized types +-- in this case. +-- device CHOICE { +-- type [0] MyType, +-- number [1] IMPLICIT INTEGER +-- }, +-- name NULL, +-- simpler MyType +-- } + +-- Call::=TEST-PSeq{INTEGER} +MyType ::= INTEGER +END + +-- +-- H323 actively uses extensible structures +-- +TEST-type-extensible {iso(1) identified-organization(3) 15} +DEFINITIONS ::= +BEGIN + +TEST-ExtendSeq ::= SEQUENCE { + device SEQUENCE { + type MyType, + number [0] IMPLICIT INTEGER, + ... + }, + name NULL, + ... +} + +TEST-ExtendSeqE ::= SEQUENCE { + device SEQUENCE { + typeE MyType, + numberE [0] IMPLICIT INTEGER, + ... + }, + nameE NULL, + ... , + add1 BOOLEAN, + add2 INTEGER, + ... +} + + +TEST-ExtendChoice ::= CHOICE { + c1 INTEGER, + c2 SEQUENCE { + a1 INTEGER, + b1 BOOLEAN + }, + ... +} + + +MyType ::= INTEGER +END + +-- +-- basic type value constraint +-- +TEST-basic-type-value-constraint {iso(1) identified-organization(3) 16} +DEFINITIONS ::= +BEGIN + + Aa ::= INTEGER + Bb::= [1] INTEGER + Cc::= [2] INTEGER (0..6,...) + Dd::= [2] INTEGER (0..6,...,7) + Ee::= INTEGER (7..20) + + Ff::= INTEGER {red(0), white(1), blue(2), green(3), purple(4)} + -- Value Assignements !!!! + a Aa ::= 3 + b Bb::= 4 + c Cc::= 5 + d Dd::= 6 + e Ee::= 7 + f Ff::= green + g INTEGER ::= 10 + +W ::= SEQUENCE {w1 Aa DEFAULT a} + +x Aa ::= a +Y ::= Aa(1..a) + +END + +-- +-- CSTA needs ROS supports +-- + +-- +-- Ros definition +-- +TEST-rose {iso (1) id(2)} +DEFINITIONS ::= +BEGIN + +OpCode ::= CHOICE +{ + local INTEGER, + global OBJECT IDENTIFIER +} + +InvokeId ::= CHOICE {present INTEGER, + absent NULL +} + +ERROR ::= CLASS +{ + &ErrorCode +} + +OPERATION ::= CLASS +{ + &ArgumentType OPTIONAL, + &argumentTypeOptional BOOLEAN OPTIONAL, + &returnResult BOOLEAN DEFAULT TRUE, + &ResultType OPTIONAL, + &resultTypeOptional BOOLEAN OPTIONAL, + &Errors ERROR OPTIONAL, + &Linked OPERATION OPTIONAL, + &alwaysReturns BOOLEAN DEFAULT TRUE, + &operationCode OpCode UNIQUE OPTIONAL +} +WITH SYNTAX +{ + [ARGUMENT &ArgumentType [OPTIONAL &argumentTypeOptional]] + [RESULT &ResultType [OPTIONAL &resultTypeOptional]] + [RETURN RESULT &returnResult] + [ERRORS &Errors] + [LINKED &Linked] + [ALWAYS RESPONDS &alwaysReturns] + [CODE &operationCode] +} + +ROS {InvokeId : IdSet , OPERATION : Invokable} ::= CHOICE { + invoke [1] Invoke{{IdSet},{Invokable}} +} + +Invoke{InvokeId:InvokeIdSet,OPERATION:Operations,INTEGER:IntegerSet,INTEGER:integerValue} ::= SEQUENCE +{ + invokeId InvokeId(InvokeIdSet), + invokeI INTEGER(IntegerSet), + opcode OPERATION.&operationCode +} +END + + +-- +-- Test ROS operation +-- +TEST-rose-operation {iso (1) id(2) 2} +DEFINITIONS ::= +BEGIN +--IMPORTS OPERATION FROM Remote-Operations-Information-Objects {iso (1)}; + +InvokeId ::= CHOICE {present INTEGER, + absent NULL +} + +Code ::= CHOICE +{ + local INTEGER, + global OBJECT IDENTIFIER +} + +OpCode ::= CHOICE +{ + local INTEGER, + global OBJECT IDENTIFIER +} + +Priority ::= INTEGER + +OPERATION ::= CLASS +{ + &ArgumentType OPTIONAL, + &argumentTypeOptional BOOLEAN OPTIONAL, + &returnResult BOOLEAN DEFAULT TRUE, + &ResultType OPTIONAL, + &resultTypeOptional BOOLEAN OPTIONAL, + &Errors ERROR OPTIONAL, + &Linked OPERATION OPTIONAL, + &alwaysReturns BOOLEAN DEFAULT TRUE, + &operationCode OpCode UNIQUE OPTIONAL +} +WITH SYNTAX +{ + [ARGUMENT &ArgumentType [OPTIONAL &argumentTypeOptional]] + [RESULT &ResultType [OPTIONAL &resultTypeOptional]] + [RETURN RESULT &returnResult] + [ERRORS &Errors] + [LINKED &Linked] + [ALWAYS RESPONDS &alwaysReturns] + [CODE &operationCode] +} +ERROR ::= CLASS +{ + &ParameterType OPTIONAL, + ¶meterTypeOptional BOOLEAN OPTIONAL, + &ErrorPriority Priority OPTIONAL, + &errorCode Code UNIQUE OPTIONAL +} +WITH SYNTAX +{ + [PARAMETER &ParameterType [OPTIONAL ¶meterTypeOptional]] + [PRIORITY &ErrorPriority] + [CODE &errorCode] +} + + +Invoke{InvokeId:InvokeIdSet,OPERATION:Operations,INTEGER:IntegerSet,INTEGER:integerValue} ::= SEQUENCE +{ + invokeId InvokeId(InvokeIdSet), + invokeI INTEGER(IntegerSet), + opcode OPERATION.&operationCode +} + +eventReport OPERATION ::= +{ + ARGUMENT EventReportArgument + ALWAYS RESPONDS FALSE + CODE local:12 +} + +makeCall OPERATION ::= +{ + ARGUMENT MakeCallArgument + RESULT MakeCallResult + ERRORS {failures} + CODE local:13 +} + + +EventReportArgument ::= SEQUENCE { + test INTEGER, + spec BOOLEAN +} + +MakeCallArgument ::= SEQUENCE { + deviceID INTEGER +} + +MakeCallResult ::= SEQUENCE { + ok BOOLEAN OPTIONAL +} + +failures ERROR ::= { + PARAMETER LocalFailures + CODE local:1 +} + +LocalFailures ::=CHOICE { + num INTEGER +} +END + +-- +-- Test ValueSet +-- +TEST-value-set {iso (1) id(2) 3} +DEFINITIONS ::= +BEGIN +IMPORTS OPERATION FROM Remote-Operations-Information-Objects {iso (1) 2 2}; + +ValueSet INTEGER ::= { 1 | 2 | 3 } + +ObjectValueSet OPERATION ::= { op1 | op2 | op3 } + + +END + + +-- +-- Test Container +-- +TEST-container {iso (1) id(2) 4} +DEFINITIONS ::= +BEGIN +IMPORTS OPERATION FROM Remote-Operations-Information-Objects {iso (1) 2 2}; + +Counter ::= INTEGER(0..65535) + +TEST-CALL ::= CLASS { + &id Counter UNIQUE, + &Value +} WITH SYNTAX { + ID &id + TYPE &Value +} + +ValueSet INTEGER ::= { 1 | 2 | 3 } + +MySeq ::= SEQUENCE { + is INTEGER, + vals Proto-Container { {ObjectValueSet } }, + -- vals Proto-Container ( { {ObjectValueSet } }), + ... +} + + +ObjectValueSet TEST-CALL ::= { {ID 1 TYPE INTEGER}| {ID 2 TYPE BOOLEAN} | { ID 3 TYPE Counter} } + +Proto-Container {TEST-CALL : CallSet } ::= SEQUENCE OF Proto-Field {{CallSet}} + +Proto-Field { TEST-CALL : CallSet } ::= SEQUENCE{ + id TEST-CALL.&id ({CallSet}), + value TEST-CALL.&Value({CallSet}{@id}) +} + +END + + -- 2.30.2