From 48e0c3df27ac60176ee525480a9bc6caad9cd246 Mon Sep 17 00:00:00 2001 From: "jk7744.park" Date: Wed, 9 Sep 2015 01:33:31 +0900 Subject: [PATCH] tizen 2.3.1 release --- .gitignore | 21 + CMakeLists.txt | 203 + LICENSE | 203 + NOTICE | 1 + build/CMakeLists.txt | 36 + build/certificate_dao/CMakeLists.txt | 21 + .../wrt-commons-certificate-dao.pc.in | 12 + build/core/CMakeLists.txt | 80 + build/core/DESCRIPTION | 2 + build/core/dpl-efl.pc.in | 11 + build/custom_handler_dao/CMakeLists.txt | 21 + .../wrt-commons-custom-handler-dao-ro.pc.in | 12 + .../wrt-commons-custom-handler-dao-rw.pc.in | 12 + build/db/CMakeLists.txt | 70 + build/db/dpl-db-efl.pc.in | 11 + build/dbus/CMakeLists.txt | 72 + build/dbus/dpl-dbus-efl.pc.in | 11 + build/event/CMakeLists.txt | 71 + build/event/dpl-event-efl.pc.in | 11 + build/i18n/CMakeLists.txt | 20 + build/i18n/wrt-commons-i18n-dao-ro.pc.in | 12 + build/log/CMakeLists.txt | 65 + build/log/dpl-log-efl.pc.in | 11 + build/rpc/CMakeLists.txt | 75 + build/rpc/dpl-rpc-efl.pc.in | 11 + build/security_origin_dao/CMakeLists.txt | 21 + .../wrt-commons-security-origin-dao.pc.in | 12 + build/socket/CMakeLists.txt | 72 + build/socket/dpl-socket-efl.pc.in | 11 + build/support/CMakeLists.txt | 26 + build/support/wrt-plugins-types.pc.in | 11 + build/test/CMakeLists.txt | 70 + build/test/dpl-test-efl.pc.in | 11 + build/utils/CMakeLists.txt | 84 + build/utils/dpl-utils-efl.pc.in | 11 + build/widget_dao/CMakeLists.txt | 21 + build/widget_dao/dpl-wrt-dao-ro.pc.in | 12 + build/widget_dao/dpl-wrt-dao-rw.pc.in | 12 + build/widget_interface_dao/CMakeLists.txt | 21 + .../wrt-commons-widget-interface-dao.pc.in | 12 + dir-struct.py | 140 + doc/DESCRIPTION | 1 + doc/doxyfile | 1600 ++++ doc/dpl_programming_guide.docx | Bin 0 -> 250036 bytes doc/dpl_programming_guide.pdf | Bin 0 -> 851605 bytes etc/CMakeLists.txt | 8 + etc/DESCRIPTION | 1 + etc/wrt_commons_create_clean_db.sh | 72 + etc/wrt_commons_reset_db.sh | 73 + examples/CMakeLists.txt | 41 + examples/DESCRIPTION | 2 + examples/binary_queue/CMakeLists.txt | 32 + examples/binary_queue/binary_queue.cpp | 63 + examples/copy/CMakeLists.txt | 32 + examples/copy/copy.cpp | 49 + examples/crypto_hash/CMakeLists.txt | 32 + examples/crypto_hash/crypto_hash.cpp | 82 + examples/dbus/client-example/CMakeLists.txt | 24 + examples/dbus/client-example/client-example.cpp | 38 + examples/dbus/server-example/CMakeLists.txt | 26 + examples/dbus/server-example/server-example.cpp | 125 + examples/fake_rpc/CMakeLists.txt | 33 + examples/fake_rpc/fake_rpc.cpp | 289 + examples/metronome/CMakeLists.txt | 38 + examples/metronome/metronome_client.cpp | 115 + examples/metronome/metronome_server.cpp | 168 + examples/rpc/CMakeLists.txt | 32 + examples/rpc/rpc.cpp | 275 + examples/simple/CMakeLists.txt | 32 + examples/simple/simple.cpp | 32 + examples/single_instance/CMakeLists.txt | 32 + examples/single_instance/single_instance.cpp | 56 + examples/socket/CMakeLists.txt | 32 + examples/socket/socket.cpp | 155 + examples/tcpsock/CMakeLists.txt | 32 + examples/tcpsock/tcpsock.cpp | 111 + examples/timed_event/CMakeLists.txt | 32 + examples/timed_event/timed_event.cpp | 102 + modules/CMakeLists.txt | 38 + modules/certificate_dao/CMakeLists.txt | 58 + modules/certificate_dao/dao/certificate_dao.cpp | 256 + .../certificate_dao/dao/certificate_dao_types.cpp | 30 + .../certificate_dao/dao/certificate_database.cpp | 19 + .../wrt-commons/certificate-dao/certificate_dao.h | 59 + .../certificate-dao/certificate_dao_types.h | 65 + .../certificate-dao/certificate_database.h | 50 + modules/certificate_dao/orm/certificate_db | 9 + .../certificate_dao/orm/certificate_db_definitions | 5 + .../orm/certificate_db_sql_generator.h | 27 + .../orm/orm_generator_certificate.h | 24 + modules/core/DESCRIPTION | 1 + modules/core/config.cmake | 153 + modules/core/include/DESCRIPTION | 2 + modules/core/include/dpl/abstract_input.h | 58 + modules/core/include/dpl/abstract_input_output.h | 38 + modules/core/include/dpl/abstract_output.h | 60 + modules/core/include/dpl/abstract_waitable_input.h | 39 + .../include/dpl/abstract_waitable_input_adapter.h | 46 + .../include/dpl/abstract_waitable_input_output.h | 38 + .../dpl/abstract_waitable_input_output_adapter.h | 40 + .../core/include/dpl/abstract_waitable_output.h | 39 + .../include/dpl/abstract_waitable_output_adapter.h | 46 + modules/core/include/dpl/address.h | 59 + modules/core/include/dpl/aligned.h | 28 + modules/core/include/dpl/application.h | 110 + modules/core/include/dpl/apply.h | 199 + modules/core/include/dpl/assert.h | 50 + modules/core/include/dpl/atomic.h | 49 + modules/core/include/dpl/availability.h | 30 + modules/core/include/dpl/binary_queue.h | 296 + modules/core/include/dpl/bind.h | 87 + modules/core/include/dpl/bool_operator.h | 45 + modules/core/include/dpl/char_traits.h | 38 + modules/core/include/dpl/colors.h | 73 + modules/core/include/dpl/copy.h | 59 + modules/core/include/dpl/enable_shared_from_this.h | 68 + modules/core/include/dpl/errno_string.h | 35 + modules/core/include/dpl/exception.h | 385 + modules/core/include/dpl/file_input.h | 62 + modules/core/include/dpl/file_output.h | 62 + modules/core/include/dpl/foreach.h | 61 + modules/core/include/dpl/framework_appcore.h | 23 + modules/core/include/dpl/framework_efl.h | 25 + modules/core/include/dpl/framework_vconf.h | 24 + modules/core/include/dpl/generic_event.h | 639 ++ modules/core/include/dpl/lexical_cast.h | 43 + modules/core/include/dpl/main.h | 93 + modules/core/include/dpl/mutable_task_list.h | 53 + modules/core/include/dpl/mutex.h | 66 + modules/core/include/dpl/named_base_pipe.h | 48 + modules/core/include/dpl/named_input_pipe.h | 36 + modules/core/include/dpl/named_output_pipe.h | 63 + modules/core/include/dpl/noncopyable.h | 38 + modules/core/include/dpl/once.h | 45 + modules/core/include/dpl/optional.h | 176 + modules/core/include/dpl/optional_typedefs.h | 33 + modules/core/include/dpl/platform.h | 107 + modules/core/include/dpl/preprocessor.h | 35 + modules/core/include/dpl/read_write_mutex.h | 80 + modules/core/include/dpl/recursive_mutex.h | 67 + modules/core/include/dpl/scope_guard.h | 111 + modules/core/include/dpl/scoped_array.h | 68 + modules/core/include/dpl/scoped_close.h | 71 + modules/core/include/dpl/scoped_dir.h | 50 + modules/core/include/dpl/scoped_fclose.h | 72 + modules/core/include/dpl/scoped_free.h | 57 + modules/core/include/dpl/scoped_gpointer.h | 78 + modules/core/include/dpl/scoped_ptr.h | 73 + modules/core/include/dpl/scoped_resource.h | 80 + modules/core/include/dpl/semaphore.h | 131 + modules/core/include/dpl/serialization.h | 327 + modules/core/include/dpl/shared_ptr.h | 286 + modules/core/include/dpl/single_instance.h | 55 + modules/core/include/dpl/singleton.h | 57 + modules/core/include/dpl/singleton_impl.h | 53 + modules/core/include/dpl/singleton_safe_impl.h | 45 + modules/core/include/dpl/sstream.h | 38 + modules/core/include/dpl/static_block.h | 45 + modules/core/include/dpl/string.h | 157 + modules/core/include/dpl/task.h | 168 + modules/core/include/dpl/thread.h | 396 + modules/core/include/dpl/type_list.h | 159 + modules/core/include/dpl/union_cast.h | 44 + modules/core/include/dpl/waitable_event.h | 59 + modules/core/include/dpl/waitable_handle.h | 115 + .../include/dpl/waitable_handle_watch_support.h | 155 + modules/core/include/dpl/workaround.h | 43 + modules/core/include/dpl/zip_input.h | 166 + modules/core/src/DESCRIPTION | 1 + .../core/src/abstract_waitable_input_adapter.cpp | 43 + .../src/abstract_waitable_input_output_adapter.cpp | 32 + .../core/src/abstract_waitable_output_adapter.cpp | 44 + modules/core/src/address.cpp | 66 + modules/core/src/application.cpp | 194 + modules/core/src/apply.cpp | 31 + modules/core/src/assert.cpp | 71 + modules/core/src/atomic.cpp | 56 + modules/core/src/binary_queue.cpp | 312 + modules/core/src/char_traits.cpp | 34 + modules/core/src/colors.cpp | 70 + modules/core/src/copy.cpp | 138 + modules/core/src/errno_string.cpp | 98 + modules/core/src/exception.cpp | 57 + modules/core/src/file_input.cpp | 142 + modules/core/src/file_output.cpp | 122 + modules/core/src/generic_event.cpp | 31 + modules/core/src/lexical_cast.cpp | 31 + modules/core/src/main.cpp | 473 ++ modules/core/src/mutable_task_list.cpp | 104 + modules/core/src/mutex.cpp | 92 + modules/core/src/named_base_pipe.cpp | 59 + modules/core/src/named_output_pipe.cpp | 101 + modules/core/src/noncopyable.cpp | 31 + modules/core/src/once.cpp | 47 + modules/core/src/read_write_mutex.cpp | 85 + modules/core/src/recursive_mutex.cpp | 71 + modules/core/src/scoped_dir.cpp | 112 + modules/core/src/semaphore.cpp | 225 + modules/core/src/serialization.cpp | 31 + modules/core/src/single_instance.cpp | 125 + modules/core/src/singleton.cpp | 31 + modules/core/src/string.cpp | 250 + modules/core/src/task.cpp | 32 + modules/core/src/thread.cpp | 623 ++ modules/core/src/type_list.cpp | 31 + modules/core/src/union_cast.cpp | 31 + modules/core/src/waitable_event.cpp | 77 + modules/core/src/waitable_handle.cpp | 162 + modules/core/src/waitable_handle_watch_support.cpp | 394 + modules/core/src/zip_input.cpp | 637 ++ modules/custom_handler_dao/CMakeLists.txt | 84 + .../dao/CustomHandlerDatabase.cpp | 45 + .../custom_handler_dao/dao/custom_handler_dao.cpp | 313 + .../dao/custom_handler_dao_read_only.cpp | 215 + .../custom-handler-dao-ro/CustomHandlerDatabase.h | 64 + .../custom-handler-dao-ro/common_dao_types.h | 63 + .../custom_handler_dao_read_only.h | 86 + .../custom-handler-dao-rw/custom_handler_dao.h | 73 + modules/custom_handler_dao/orm/custom_handler_db | 34 + .../orm/custom_handler_db_definitions | 6 + .../orm/custom_handler_db_sql_generator.h | 27 + modules/custom_handler_dao/orm/gen_db_md5.sh | 19 + .../orm/orm_generator_custom_handler.h | 24 + modules/custom_handler_dao/orm/version_db | 5 + modules/db/config.cmake | 45 + .../include/dpl/db/naive_synchronization_object.h | 45 + modules/db/include/dpl/db/orm.h | 1116 +++ modules/db/include/dpl/db/orm_generator.h | 382 + modules/db/include/dpl/db/orm_interface.h | 48 + modules/db/include/dpl/db/orm_macros.h | 34 + modules/db/include/dpl/db/sql_connection.h | 513 ++ .../db/include/dpl/db/thread_database_support.h | 300 + modules/db/src/naive_synchronization_object.cpp | 44 + modules/db/src/orm.cpp | 102 + modules/db/src/sql_connection.cpp | 869 ++ modules/db/src/thread_database_support.cpp | 23 + modules/dbus/config.cmake | 56 + modules/dbus/include/dpl/dbus/connection.h | 207 + modules/dbus/include/dpl/dbus/dbus_client.h | 237 + .../dbus/include/dpl/dbus/dbus_deserialization.h | 224 + .../include/dpl/dbus/dbus_interface_dispatcher.h | 105 + modules/dbus/include/dpl/dbus/dbus_serialization.h | 158 + .../include/dpl/dbus/dbus_server_deserialization.h | 178 + .../include/dpl/dbus/dbus_server_serialization.h | 95 + modules/dbus/include/dpl/dbus/dbus_signature.h | 256 + modules/dbus/include/dpl/dbus/dispatcher.h | 99 + modules/dbus/include/dpl/dbus/exception.h | 47 + modules/dbus/include/dpl/dbus/glib_util.h | 30 + modules/dbus/include/dpl/dbus/interface.h | 113 + modules/dbus/include/dpl/dbus/method_proxy.h | 228 + modules/dbus/include/dpl/dbus/object.h | 72 + modules/dbus/include/dpl/dbus/object_proxy.h | 84 + modules/dbus/include/dpl/dbus/server.h | 90 + modules/dbus/src/connection.cpp | 275 + modules/dbus/src/dispatcher.cpp | 50 + modules/dbus/src/interface.cpp | 187 + modules/dbus/src/object.cpp | 47 + modules/dbus/src/object_proxy.cpp | 42 + modules/dbus/src/server.cpp | 114 + modules/event/config.cmake | 55 + .../event/include/dpl/event/abstract_event_call.h | 51 + .../include/dpl/event/abstract_event_dispatcher.h | 66 + modules/event/include/dpl/event/controller.h | 160 + modules/event/include/dpl/event/event_listener.h | 45 + modules/event/include/dpl/event/event_support.h | 721 ++ .../event/include/dpl/event/generic_event_call.h | 97 + .../include/dpl/event/inter_context_delegate.h | 392 + .../include/dpl/event/main_event_dispatcher.h | 120 + modules/event/include/dpl/event/model.h | 48 + .../event/include/dpl/event/model_bind_to_dao.h | 73 + modules/event/include/dpl/event/property.h | 517 ++ .../include/dpl/event/thread_event_dispatcher.h | 56 + modules/event/src/abstract_event_call.cpp | 33 + modules/event/src/abstract_event_dispatcher.cpp | 34 + modules/event/src/controller.cpp | 31 + modules/event/src/event_listener.cpp | 31 + modules/event/src/event_support.cpp | 39 + modules/event/src/generic_event_call.cpp | 31 + modules/event/src/inter_context_delegate.cpp | 31 + modules/event/src/main_event_dispatcher.cpp | 382 + modules/event/src/model.cpp | 30 + modules/event/src/thread_event_dispatcher.cpp | 114 + modules/i18n/CMakeLists.txt | 1 + modules/i18n/dao/CMakeLists.txt | 65 + .../wrt-commons/i18n-dao-ro/i18n_dao_read_only.h | 39 + .../wrt-commons/i18n-dao-ro/i18n_database.h | 56 + modules/i18n/dao/orm/gen_db_md5.sh | 19 + modules/i18n/dao/orm/i18n_db_definitions | 6 + modules/i18n/dao/orm/i18n_db_sql_generator.h | 27 + modules/i18n/dao/orm/iana_db | 8957 ++++++++++++++++++++ modules/i18n/dao/orm/orm_generator_i18n.h | 24 + modules/i18n/dao/orm/version_db | 5 + modules/i18n/dao/src/i18n_dao_read_only.cpp | 45 + modules/i18n/dao/src/i18n_database.cpp | 43 + modules/localization/config.cmake | 39 + .../localization/include/LanguageTagsProvider.h | 92 + .../include/dpl/localization/localization_utils.h | 77 + .../dpl/localization/w3c_file_localization.h | 74 + modules/localization/src/LanguageTagsProvider.cpp | 173 + modules/localization/src/w3c_file_localization.cpp | 575 ++ modules/log/config.cmake | 42 + .../log/include/dpl/log/abstract_log_provider.h | 59 + modules/log/include/dpl/log/dlog_log_provider.h | 73 + modules/log/include/dpl/log/log.h | 171 + .../log/include/dpl/log/old_style_log_provider.h | 84 + modules/log/include/dpl/log/secure_log.h | 92 + modules/log/src/abstract_log_provider.cpp | 34 + modules/log/src/dlog_log_provider.cpp | 117 + modules/log/src/log.cpp | 222 + modules/log/src/old_style_log_provider.cpp | 200 + modules/rpc/config.cmake | 52 + .../rpc/include/dpl/rpc/abstract_rpc_connection.h | 96 + .../rpc/include/dpl/rpc/abstract_rpc_connector.h | 53 + .../rpc/include/dpl/rpc/generic_rpc_connection.h | 60 + .../include/dpl/rpc/generic_socket_rpc_client.h | 187 + .../dpl/rpc/generic_socket_rpc_connection.h | 42 + .../include/dpl/rpc/generic_socket_rpc_server.h | 194 + modules/rpc/include/dpl/rpc/rpc_function.h | 212 + .../rpc/include/dpl/rpc/unix_socket_rpc_client.h | 44 + .../include/dpl/rpc/unix_socket_rpc_connection.h | 40 + .../rpc/include/dpl/rpc/unix_socket_rpc_server.h | 44 + modules/rpc/src/abstract_rpc_connection.cpp | 31 + modules/rpc/src/abstract_rpc_connector.cpp | 31 + modules/rpc/src/generic_rpc_connection.cpp | 225 + modules/rpc/src/generic_socket_rpc_client.cpp | 32 + modules/rpc/src/generic_socket_rpc_connection.cpp | 32 + modules/rpc/src/generic_socket_rpc_server.cpp | 31 + modules/rpc/src/unix_socket_rpc_client.cpp | 44 + modules/rpc/src/unix_socket_rpc_connection.cpp | 33 + modules/rpc/src/unix_socket_rpc_server.cpp | 44 + modules/security_origin_dao/CMakeLists.txt | 56 + .../dao/security_origin_dao.cpp | 337 + .../dao/security_origin_dao_types.cpp | 29 + .../security-origin-dao/security_origin_dao.h | 71 + .../security_origin_dao_types.h | 96 + .../orm/orm_generator_security_origin.h | 24 + modules/security_origin_dao/orm/security_origin_db | 13 + .../orm/security_origin_db_definitions | 5 + .../orm/security_origin_db_sql_generator.h | 27 + modules/socket/config.cmake | 40 + .../socket/include/dpl/socket/abstract_socket.h | 215 + modules/socket/include/dpl/socket/generic_socket.h | 934 ++ modules/socket/include/dpl/socket/unix_socket.h | 77 + ...itable_input_output_execution_context_support.h | 100 + modules/socket/src/generic_socket.cpp | 31 + modules/socket/src/unix_socket.cpp | 119 + ...able_input_output_execution_context_support.cpp | 312 + modules/support/config.cmake | 26 + modules/support/wrt_plugin_export.h | 292 + modules/test/config.cmake | 54 + .../test/include/dpl/test/abstract_input_parser.h | 57 + .../test/include/dpl/test/abstract_input_reader.h | 110 + .../include/dpl/test/abstract_input_tokenizer.h | 86 + modules/test/include/dpl/test/process_pipe.h | 62 + .../test/include/dpl/test/test_results_collector.h | 96 + modules/test/include/dpl/test/test_runner.h | 227 + modules/test/include/dpl/test/test_runner_child.h | 91 + .../include/dpl/test/test_runner_multiprocess.h | 60 + .../test/include/dpl/test/value_separated_parser.h | 94 + .../include/dpl/test/value_separated_policies.h | 47 + .../test/include/dpl/test/value_separated_reader.h | 63 + .../include/dpl/test/value_separated_tokenizer.h | 149 + .../test/include/dpl/test/value_separated_tokens.h | 44 + modules/test/src/process_pipe.cpp | 83 + modules/test/src/test_results_collector.cpp | 987 +++ modules/test/src/test_runner.cpp | 700 ++ modules/test/src/test_runner_child.cpp | 326 + modules/test/src/test_runner_multiprocess.cpp | 275 + modules/test/src/value_separated_policies.cpp | 68 + modules/test/src/value_separated_tokens.cpp | 44 + modules/utils/config.cmake | 49 + modules/utils/include/dpl/utils/bash_utils.h | 36 + modules/utils/include/dpl/utils/folder_size.h | 37 + modules/utils/include/dpl/utils/mime_type_utils.h | 57 + modules/utils/include/dpl/utils/path.h | 237 + modules/utils/include/dpl/utils/warp_iri.h | 64 + modules/utils/include/dpl/utils/widget_version.h | 131 + .../utils/include/dpl/utils/wrt_global_settings.h | 38 + modules/utils/include/dpl/utils/wrt_utility.h | 84 + modules/utils/src/bash_utils.cpp | 44 + modules/utils/src/folder_size.cpp | 155 + modules/utils/src/mime_type_utils.cpp | 162 + modules/utils/src/path.cpp | 540 ++ modules/utils/src/warp_iri.cpp | 210 + modules/utils/src/widget_version.cpp | 401 + modules/utils/src/wrt_global_settings.cpp | 161 + modules/utils/src/wrt_utility.cpp | 179 + modules/widget_dao/CMakeLists.txt | 141 + modules/widget_dao/dao/WrtDatabase.cpp | 65 + modules/widget_dao/dao/common_dao_types.cpp | 24 + modules/widget_dao/dao/config_parser_data.cpp | 494 ++ modules/widget_dao/dao/feature_dao.cpp | 164 + modules/widget_dao/dao/feature_dao_read_only.cpp | 449 + modules/widget_dao/dao/path_builder.cpp | 125 + modules/widget_dao/dao/plugin_dao.cpp | 243 + modules/widget_dao/dao/plugin_dao_read_only.cpp | 458 + modules/widget_dao/dao/property_dao.cpp | 167 + modules/widget_dao/dao/property_dao_read_only.cpp | 199 + modules/widget_dao/dao/webruntime_database.cpp | 26 + modules/widget_dao/dao/widget_dao.cpp | 807 ++ modules/widget_dao/dao/widget_dao_read_only.cpp | 1192 +++ modules/widget_dao/dao/widget_dao_types.cpp | 39 + .../include/dpl/wrt-dao-ro/WrtDatabase.h | 39 + .../include/dpl/wrt-dao-ro/common_dao_types.h | 387 + .../include/dpl/wrt-dao-ro/config_parser_data.h | 416 + .../include/dpl/wrt-dao-ro/feature_dao_read_only.h | 88 + .../include/dpl/wrt-dao-ro/feature_model.h | 75 + .../include/dpl/wrt-dao-ro/global_config.h | 321 + .../include/dpl/wrt-dao-ro/path_builder.h | 55 + .../include/dpl/wrt-dao-ro/plugin_dao_read_only.h | 116 + .../dpl/wrt-dao-ro/property_dao_read_only.h | 93 + .../include/dpl/wrt-dao-ro/webruntime_database.h | 58 + .../include/dpl/wrt-dao-ro/widget_config.h | 112 + .../include/dpl/wrt-dao-ro/widget_dao_read_only.h | 698 ++ .../include/dpl/wrt-dao-ro/widget_dao_types.h | 49 + .../include/dpl/wrt-dao-ro/wrt_db_types.h | 38 + .../include/dpl/wrt-dao-rw/feature_dao.h | 39 + .../widget_dao/include/dpl/wrt-dao-rw/plugin_dao.h | 61 + .../include/dpl/wrt-dao-rw/property_dao.h | 59 + .../widget_dao/include/dpl/wrt-dao-rw/widget_dao.h | 214 + modules/widget_dao/orm/gen_db_md5.sh | 19 + modules/widget_dao/orm/orm_generator_wrt.h | 24 + modules/widget_dao/orm/version_db | 5 + modules/widget_dao/orm/wrt_db | 314 + modules/widget_dao/orm/wrt_db_definitions | 6 + modules/widget_dao/orm/wrt_db_sql_generator.h | 28 + modules/widget_interface_dao/CMakeLists.txt | 46 + .../dao/widget_interface_dao.cpp | 299 + .../widget-interface-dao/widget_interface_dao.h | 72 + .../orm/orm_generator_widget_interface.h | 24 + .../widget_interface_dao/orm/widget_interface_db | 17 + .../orm/widget_interface_db_definitions | 5 + .../orm/widget_interface_db_sql_generator.h | 28 + packaging/wrt-commons.spec | 146 + tests/CMakeLists.txt | 30 + tests/CMakeUtils.txt | 178 + tests/common/include/glib_interface.h | 32 + tests/common/include/loop_control.h | 38 + tests/common/src/loop_control.cpp | 70 + tests/core/CMakeLists.txt | 66 + tests/core/DESCRIPTION | 2 + tests/core/data/sample.zip | Bin 0 -> 174 bytes tests/core/main.cpp | 28 + tests/core/test_address.cpp | 70 + tests/core/test_binary_queue.cpp | 468 + tests/core/test_bind.cpp | 98 + tests/core/test_foreach.cpp | 119 + tests/core/test_log_unhandled_exception.cpp | 97 + tests/core/test_once.cpp | 109 + tests/core/test_scope_guard.cpp | 124 + tests/core/test_scoped_array.cpp | 82 + tests/core/test_scoped_close.cpp | 27 + tests/core/test_scoped_dir.cpp | 55 + tests/core/test_scoped_fclose.cpp | 83 + tests/core/test_scoped_free.cpp | 68 + tests/core/test_scoped_ptr.cpp | 79 + tests/core/test_semaphore.cpp | 88 + tests/core/test_serialization.cpp | 303 + tests/core/test_shared_ptr.cpp | 116 + tests/core/test_single_instance.cpp | 43 + tests/core/test_static_block.cpp | 56 + tests/core/test_string.cpp | 479 ++ tests/core/test_thread.cpp | 105 + tests/core/test_type_list.cpp | 46 + tests/core/test_waitable_handle_watch.cpp | 169 + tests/core/test_zip_input.cpp | 104 + tests/dao/CMakeLists.txt | 37 + tests/dao/README | 11 + tests/dao/TestCases_CertificateDAO.cpp | 149 + tests/dao/TestCases_CustomHandlerDAO.cpp | 301 + tests/dao/TestCases_FeatureDAO.cpp | 417 + tests/dao/TestCases_PluginDAO.cpp | 499 ++ tests/dao/TestCases_PropertyDAO.cpp | 211 + tests/dao/TestCases_SecurityOriginDAO.cpp | 204 + tests/dao/TestCases_WidgetDAO.cpp | 1636 ++++ tests/dao/TestCases_WidgetInterfaceDAO.cpp | 423 + tests/dao/tests_dao.cpp | 53 + tests/dao/wrt_dao_tests_prepare_db.sh | 151 + tests/db/CMakeLists.txt | 49 + tests/db/main.cpp | 28 + tests/db/orm/CMakeLists.txt | 11 + tests/db/orm/dpl_orm_test_db | 88 + tests/db/orm/dpl_orm_test_db_definitions | 5 + tests/db/orm/dpl_orm_test_db_sql_generator.h | 28 + tests/db/orm/dpl_orm_test_db_sql_generator.h.gch | Bin 0 -> 6521 bytes tests/db/orm/generator_dpl_orm_test.h | 24 + tests/db/test_orm.cpp | 1140 +++ tests/db/test_sql_connection.cpp | 490 ++ tests/dbus/CMakeLists.txt | 63 + tests/dbus/data/org.tizen.DBusTestService.service | 3 + tests/dbus/dbus_test.cpp | 117 + tests/dbus/dbus_test.h | 91 + tests/dbus/main.cpp | 36 + tests/dbus/test_cases.cpp | 273 + tests/dbus/test_service.cpp | 88 + tests/event/CMakeLists.txt | 42 + tests/event/main.cpp | 28 + tests/event/test_controller.cpp | 426 + tests/event/test_event_support.cpp | 151 + tests/event/test_ic_delegate.cpp | 602 ++ tests/event/test_property.cpp | 115 + tests/files_localization/CMakeLists.txt | 43 + tests/files_localization/files/CMakeLists.txt | 31 + tests/files_localization/files/icon | 0 tests/files_localization/files/icon2 | 0 tests/files_localization/files/one | 0 tests/files_localization/files/two.html | 0 tests/files_localization/test_localization.cpp | 48 + tests/files_localization/test_suite01.cpp | 426 + .../wrt_db_localization_prepare.sh | 58 + tests/i18n/CMakeLists.txt | 40 + tests/i18n/main.cpp | 28 + tests/i18n/test_i18n_dao_read_only.cpp | 53 + tests/localizationTagsProvider/CMakeLists.txt | 42 + .../Localization_testcases.cpp | 162 + tests/localizationTagsProvider/README | 13 + tests/localizationTagsProvider/tests_miscunit.cpp | 33 + tests/test/CMakeLists.txt | 35 + tests/test/main.cpp | 28 + tests/test/runner_child.cpp | 155 + tests/test/runner_multiprocess.cpp | 309 + tests/test/test_abstract_input_reader.cpp | 149 + tests/test/test_process_pipe.cpp | 119 + tests/test/test_value_separated_reader.cpp | 83 + tests/unused/test_caller.cpp | 129 + tests/unused/test_crypto_hash.cpp | 117 + tests/unused/test_message_queue.cpp | 164 + tests/unused/test_shm.cpp | 1660 ++++ tests/unused/test_sql_connection.cpp | 44 + tests/unused/test_task.cpp | 92 + tests/utils/CMakeLists.txt | 34 + tests/utils/bash_utils.cpp | 52 + tests/utils/main.cpp | 28 + tests/utils/path_tests.cpp | 958 +++ tests/utils/widget_version.cpp | 641 ++ tests/utils/wrt_utility.cpp | 190 + uncrustify.cfg | 170 + uncrustify.sh | 1 + wrt-commons | 204 + wrt-commons.manifest | 15 + 540 files changed, 77835 insertions(+) create mode 100755 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 NOTICE create mode 100644 build/CMakeLists.txt create mode 100755 build/certificate_dao/CMakeLists.txt create mode 100644 build/certificate_dao/wrt-commons-certificate-dao.pc.in create mode 100644 build/core/CMakeLists.txt create mode 100644 build/core/DESCRIPTION create mode 100644 build/core/dpl-efl.pc.in create mode 100644 build/custom_handler_dao/CMakeLists.txt create mode 100644 build/custom_handler_dao/wrt-commons-custom-handler-dao-ro.pc.in create mode 100644 build/custom_handler_dao/wrt-commons-custom-handler-dao-rw.pc.in create mode 100644 build/db/CMakeLists.txt create mode 100644 build/db/dpl-db-efl.pc.in create mode 100644 build/dbus/CMakeLists.txt create mode 100644 build/dbus/dpl-dbus-efl.pc.in create mode 100644 build/event/CMakeLists.txt create mode 100644 build/event/dpl-event-efl.pc.in create mode 100644 build/i18n/CMakeLists.txt create mode 100644 build/i18n/wrt-commons-i18n-dao-ro.pc.in create mode 100644 build/log/CMakeLists.txt create mode 100644 build/log/dpl-log-efl.pc.in create mode 100644 build/rpc/CMakeLists.txt create mode 100644 build/rpc/dpl-rpc-efl.pc.in create mode 100644 build/security_origin_dao/CMakeLists.txt create mode 100644 build/security_origin_dao/wrt-commons-security-origin-dao.pc.in create mode 100644 build/socket/CMakeLists.txt create mode 100644 build/socket/dpl-socket-efl.pc.in create mode 100644 build/support/CMakeLists.txt create mode 100644 build/support/wrt-plugins-types.pc.in create mode 100644 build/test/CMakeLists.txt create mode 100644 build/test/dpl-test-efl.pc.in create mode 100644 build/utils/CMakeLists.txt create mode 100644 build/utils/dpl-utils-efl.pc.in create mode 100644 build/widget_dao/CMakeLists.txt create mode 100644 build/widget_dao/dpl-wrt-dao-ro.pc.in create mode 100644 build/widget_dao/dpl-wrt-dao-rw.pc.in create mode 100644 build/widget_interface_dao/CMakeLists.txt create mode 100644 build/widget_interface_dao/wrt-commons-widget-interface-dao.pc.in create mode 100755 dir-struct.py create mode 100644 doc/DESCRIPTION create mode 100644 doc/doxyfile create mode 100644 doc/dpl_programming_guide.docx create mode 100644 doc/dpl_programming_guide.pdf create mode 100644 etc/CMakeLists.txt create mode 100644 etc/DESCRIPTION create mode 100755 etc/wrt_commons_create_clean_db.sh create mode 100755 etc/wrt_commons_reset_db.sh create mode 100644 examples/CMakeLists.txt create mode 100644 examples/DESCRIPTION create mode 100644 examples/binary_queue/CMakeLists.txt create mode 100644 examples/binary_queue/binary_queue.cpp create mode 100644 examples/copy/CMakeLists.txt create mode 100644 examples/copy/copy.cpp create mode 100644 examples/crypto_hash/CMakeLists.txt create mode 100644 examples/crypto_hash/crypto_hash.cpp create mode 100755 examples/dbus/client-example/CMakeLists.txt create mode 100644 examples/dbus/client-example/client-example.cpp create mode 100755 examples/dbus/server-example/CMakeLists.txt create mode 100644 examples/dbus/server-example/server-example.cpp create mode 100644 examples/fake_rpc/CMakeLists.txt create mode 100644 examples/fake_rpc/fake_rpc.cpp create mode 100644 examples/metronome/CMakeLists.txt create mode 100644 examples/metronome/metronome_client.cpp create mode 100644 examples/metronome/metronome_server.cpp create mode 100644 examples/rpc/CMakeLists.txt create mode 100644 examples/rpc/rpc.cpp create mode 100644 examples/simple/CMakeLists.txt create mode 100644 examples/simple/simple.cpp create mode 100644 examples/single_instance/CMakeLists.txt create mode 100644 examples/single_instance/single_instance.cpp create mode 100644 examples/socket/CMakeLists.txt create mode 100644 examples/socket/socket.cpp create mode 100644 examples/tcpsock/CMakeLists.txt create mode 100644 examples/tcpsock/tcpsock.cpp create mode 100644 examples/timed_event/CMakeLists.txt create mode 100644 examples/timed_event/timed_event.cpp create mode 100644 modules/CMakeLists.txt create mode 100755 modules/certificate_dao/CMakeLists.txt create mode 100644 modules/certificate_dao/dao/certificate_dao.cpp create mode 100755 modules/certificate_dao/dao/certificate_dao_types.cpp create mode 100755 modules/certificate_dao/dao/certificate_database.cpp create mode 100644 modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao.h create mode 100755 modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao_types.h create mode 100755 modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_database.h create mode 100755 modules/certificate_dao/orm/certificate_db create mode 100644 modules/certificate_dao/orm/certificate_db_definitions create mode 100755 modules/certificate_dao/orm/certificate_db_sql_generator.h create mode 100755 modules/certificate_dao/orm/orm_generator_certificate.h create mode 100644 modules/core/DESCRIPTION create mode 100644 modules/core/config.cmake create mode 100644 modules/core/include/DESCRIPTION create mode 100644 modules/core/include/dpl/abstract_input.h create mode 100644 modules/core/include/dpl/abstract_input_output.h create mode 100644 modules/core/include/dpl/abstract_output.h create mode 100644 modules/core/include/dpl/abstract_waitable_input.h create mode 100644 modules/core/include/dpl/abstract_waitable_input_adapter.h create mode 100644 modules/core/include/dpl/abstract_waitable_input_output.h create mode 100644 modules/core/include/dpl/abstract_waitable_input_output_adapter.h create mode 100644 modules/core/include/dpl/abstract_waitable_output.h create mode 100644 modules/core/include/dpl/abstract_waitable_output_adapter.h create mode 100644 modules/core/include/dpl/address.h create mode 100644 modules/core/include/dpl/aligned.h create mode 100644 modules/core/include/dpl/application.h create mode 100644 modules/core/include/dpl/apply.h create mode 100644 modules/core/include/dpl/assert.h create mode 100644 modules/core/include/dpl/atomic.h create mode 100644 modules/core/include/dpl/availability.h create mode 100644 modules/core/include/dpl/binary_queue.h create mode 100644 modules/core/include/dpl/bind.h create mode 100644 modules/core/include/dpl/bool_operator.h create mode 100644 modules/core/include/dpl/char_traits.h create mode 100644 modules/core/include/dpl/colors.h create mode 100644 modules/core/include/dpl/copy.h create mode 100644 modules/core/include/dpl/enable_shared_from_this.h create mode 100644 modules/core/include/dpl/errno_string.h create mode 100644 modules/core/include/dpl/exception.h create mode 100644 modules/core/include/dpl/file_input.h create mode 100644 modules/core/include/dpl/file_output.h create mode 100644 modules/core/include/dpl/foreach.h create mode 100644 modules/core/include/dpl/framework_appcore.h create mode 100644 modules/core/include/dpl/framework_efl.h create mode 100644 modules/core/include/dpl/framework_vconf.h create mode 100644 modules/core/include/dpl/generic_event.h create mode 100644 modules/core/include/dpl/lexical_cast.h create mode 100644 modules/core/include/dpl/main.h create mode 100644 modules/core/include/dpl/mutable_task_list.h create mode 100644 modules/core/include/dpl/mutex.h create mode 100644 modules/core/include/dpl/named_base_pipe.h create mode 100644 modules/core/include/dpl/named_input_pipe.h create mode 100644 modules/core/include/dpl/named_output_pipe.h create mode 100644 modules/core/include/dpl/noncopyable.h create mode 100644 modules/core/include/dpl/once.h create mode 100644 modules/core/include/dpl/optional.h create mode 100644 modules/core/include/dpl/optional_typedefs.h create mode 100644 modules/core/include/dpl/platform.h create mode 100644 modules/core/include/dpl/preprocessor.h create mode 100644 modules/core/include/dpl/read_write_mutex.h create mode 100644 modules/core/include/dpl/recursive_mutex.h create mode 100644 modules/core/include/dpl/scope_guard.h create mode 100644 modules/core/include/dpl/scoped_array.h create mode 100644 modules/core/include/dpl/scoped_close.h create mode 100644 modules/core/include/dpl/scoped_dir.h create mode 100644 modules/core/include/dpl/scoped_fclose.h create mode 100644 modules/core/include/dpl/scoped_free.h create mode 100644 modules/core/include/dpl/scoped_gpointer.h create mode 100644 modules/core/include/dpl/scoped_ptr.h create mode 100644 modules/core/include/dpl/scoped_resource.h create mode 100644 modules/core/include/dpl/semaphore.h create mode 100644 modules/core/include/dpl/serialization.h create mode 100644 modules/core/include/dpl/shared_ptr.h create mode 100644 modules/core/include/dpl/single_instance.h create mode 100644 modules/core/include/dpl/singleton.h create mode 100644 modules/core/include/dpl/singleton_impl.h create mode 100644 modules/core/include/dpl/singleton_safe_impl.h create mode 100644 modules/core/include/dpl/sstream.h create mode 100644 modules/core/include/dpl/static_block.h create mode 100644 modules/core/include/dpl/string.h create mode 100644 modules/core/include/dpl/task.h create mode 100644 modules/core/include/dpl/thread.h create mode 100644 modules/core/include/dpl/type_list.h create mode 100644 modules/core/include/dpl/union_cast.h create mode 100644 modules/core/include/dpl/waitable_event.h create mode 100644 modules/core/include/dpl/waitable_handle.h create mode 100644 modules/core/include/dpl/waitable_handle_watch_support.h create mode 100644 modules/core/include/dpl/workaround.h create mode 100644 modules/core/include/dpl/zip_input.h create mode 100644 modules/core/src/DESCRIPTION create mode 100644 modules/core/src/abstract_waitable_input_adapter.cpp create mode 100644 modules/core/src/abstract_waitable_input_output_adapter.cpp create mode 100644 modules/core/src/abstract_waitable_output_adapter.cpp create mode 100644 modules/core/src/address.cpp create mode 100644 modules/core/src/application.cpp create mode 100644 modules/core/src/apply.cpp create mode 100644 modules/core/src/assert.cpp create mode 100644 modules/core/src/atomic.cpp create mode 100644 modules/core/src/binary_queue.cpp create mode 100644 modules/core/src/char_traits.cpp create mode 100644 modules/core/src/colors.cpp create mode 100644 modules/core/src/copy.cpp create mode 100644 modules/core/src/errno_string.cpp create mode 100644 modules/core/src/exception.cpp create mode 100644 modules/core/src/file_input.cpp create mode 100644 modules/core/src/file_output.cpp create mode 100644 modules/core/src/generic_event.cpp create mode 100644 modules/core/src/lexical_cast.cpp create mode 100644 modules/core/src/main.cpp create mode 100644 modules/core/src/mutable_task_list.cpp create mode 100644 modules/core/src/mutex.cpp create mode 100644 modules/core/src/named_base_pipe.cpp create mode 100644 modules/core/src/named_output_pipe.cpp create mode 100644 modules/core/src/noncopyable.cpp create mode 100644 modules/core/src/once.cpp create mode 100644 modules/core/src/read_write_mutex.cpp create mode 100644 modules/core/src/recursive_mutex.cpp create mode 100644 modules/core/src/scoped_dir.cpp create mode 100644 modules/core/src/semaphore.cpp create mode 100644 modules/core/src/serialization.cpp create mode 100644 modules/core/src/single_instance.cpp create mode 100644 modules/core/src/singleton.cpp create mode 100644 modules/core/src/string.cpp create mode 100644 modules/core/src/task.cpp create mode 100644 modules/core/src/thread.cpp create mode 100644 modules/core/src/type_list.cpp create mode 100644 modules/core/src/union_cast.cpp create mode 100644 modules/core/src/waitable_event.cpp create mode 100644 modules/core/src/waitable_handle.cpp create mode 100644 modules/core/src/waitable_handle_watch_support.cpp create mode 100644 modules/core/src/zip_input.cpp create mode 100644 modules/custom_handler_dao/CMakeLists.txt create mode 100644 modules/custom_handler_dao/dao/CustomHandlerDatabase.cpp create mode 100644 modules/custom_handler_dao/dao/custom_handler_dao.cpp create mode 100644 modules/custom_handler_dao/dao/custom_handler_dao_read_only.cpp create mode 100644 modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/CustomHandlerDatabase.h create mode 100644 modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/common_dao_types.h create mode 100644 modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/custom_handler_dao_read_only.h create mode 100644 modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-rw/custom_handler_dao.h create mode 100644 modules/custom_handler_dao/orm/custom_handler_db create mode 100644 modules/custom_handler_dao/orm/custom_handler_db_definitions create mode 100644 modules/custom_handler_dao/orm/custom_handler_db_sql_generator.h create mode 100755 modules/custom_handler_dao/orm/gen_db_md5.sh create mode 100644 modules/custom_handler_dao/orm/orm_generator_custom_handler.h create mode 100644 modules/custom_handler_dao/orm/version_db create mode 100644 modules/db/config.cmake create mode 100644 modules/db/include/dpl/db/naive_synchronization_object.h create mode 100644 modules/db/include/dpl/db/orm.h create mode 100644 modules/db/include/dpl/db/orm_generator.h create mode 100644 modules/db/include/dpl/db/orm_interface.h create mode 100644 modules/db/include/dpl/db/orm_macros.h create mode 100644 modules/db/include/dpl/db/sql_connection.h create mode 100644 modules/db/include/dpl/db/thread_database_support.h create mode 100644 modules/db/src/naive_synchronization_object.cpp create mode 100644 modules/db/src/orm.cpp create mode 100644 modules/db/src/sql_connection.cpp create mode 100644 modules/db/src/thread_database_support.cpp create mode 100644 modules/dbus/config.cmake create mode 100644 modules/dbus/include/dpl/dbus/connection.h create mode 100644 modules/dbus/include/dpl/dbus/dbus_client.h create mode 100644 modules/dbus/include/dpl/dbus/dbus_deserialization.h create mode 100644 modules/dbus/include/dpl/dbus/dbus_interface_dispatcher.h create mode 100644 modules/dbus/include/dpl/dbus/dbus_serialization.h create mode 100644 modules/dbus/include/dpl/dbus/dbus_server_deserialization.h create mode 100644 modules/dbus/include/dpl/dbus/dbus_server_serialization.h create mode 100644 modules/dbus/include/dpl/dbus/dbus_signature.h create mode 100644 modules/dbus/include/dpl/dbus/dispatcher.h create mode 100644 modules/dbus/include/dpl/dbus/exception.h create mode 100644 modules/dbus/include/dpl/dbus/glib_util.h create mode 100644 modules/dbus/include/dpl/dbus/interface.h create mode 100644 modules/dbus/include/dpl/dbus/method_proxy.h create mode 100644 modules/dbus/include/dpl/dbus/object.h create mode 100644 modules/dbus/include/dpl/dbus/object_proxy.h create mode 100644 modules/dbus/include/dpl/dbus/server.h create mode 100644 modules/dbus/src/connection.cpp create mode 100644 modules/dbus/src/dispatcher.cpp create mode 100644 modules/dbus/src/interface.cpp create mode 100644 modules/dbus/src/object.cpp create mode 100644 modules/dbus/src/object_proxy.cpp create mode 100644 modules/dbus/src/server.cpp create mode 100644 modules/event/config.cmake create mode 100644 modules/event/include/dpl/event/abstract_event_call.h create mode 100644 modules/event/include/dpl/event/abstract_event_dispatcher.h create mode 100644 modules/event/include/dpl/event/controller.h create mode 100644 modules/event/include/dpl/event/event_listener.h create mode 100644 modules/event/include/dpl/event/event_support.h create mode 100644 modules/event/include/dpl/event/generic_event_call.h create mode 100644 modules/event/include/dpl/event/inter_context_delegate.h create mode 100644 modules/event/include/dpl/event/main_event_dispatcher.h create mode 100644 modules/event/include/dpl/event/model.h create mode 100644 modules/event/include/dpl/event/model_bind_to_dao.h create mode 100644 modules/event/include/dpl/event/property.h create mode 100644 modules/event/include/dpl/event/thread_event_dispatcher.h create mode 100644 modules/event/src/abstract_event_call.cpp create mode 100644 modules/event/src/abstract_event_dispatcher.cpp create mode 100644 modules/event/src/controller.cpp create mode 100644 modules/event/src/event_listener.cpp create mode 100644 modules/event/src/event_support.cpp create mode 100644 modules/event/src/generic_event_call.cpp create mode 100644 modules/event/src/inter_context_delegate.cpp create mode 100644 modules/event/src/main_event_dispatcher.cpp create mode 100644 modules/event/src/model.cpp create mode 100644 modules/event/src/thread_event_dispatcher.cpp create mode 100644 modules/i18n/CMakeLists.txt create mode 100644 modules/i18n/dao/CMakeLists.txt create mode 100644 modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_dao_read_only.h create mode 100644 modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_database.h create mode 100755 modules/i18n/dao/orm/gen_db_md5.sh create mode 100644 modules/i18n/dao/orm/i18n_db_definitions create mode 100644 modules/i18n/dao/orm/i18n_db_sql_generator.h create mode 100644 modules/i18n/dao/orm/iana_db create mode 100644 modules/i18n/dao/orm/orm_generator_i18n.h create mode 100644 modules/i18n/dao/orm/version_db create mode 100644 modules/i18n/dao/src/i18n_dao_read_only.cpp create mode 100644 modules/i18n/dao/src/i18n_database.cpp create mode 100644 modules/localization/config.cmake create mode 100644 modules/localization/include/LanguageTagsProvider.h create mode 100644 modules/localization/include/dpl/localization/localization_utils.h create mode 100755 modules/localization/include/dpl/localization/w3c_file_localization.h create mode 100644 modules/localization/src/LanguageTagsProvider.cpp create mode 100644 modules/localization/src/w3c_file_localization.cpp create mode 100644 modules/log/config.cmake create mode 100644 modules/log/include/dpl/log/abstract_log_provider.h create mode 100644 modules/log/include/dpl/log/dlog_log_provider.h create mode 100644 modules/log/include/dpl/log/log.h create mode 100644 modules/log/include/dpl/log/old_style_log_provider.h create mode 100644 modules/log/include/dpl/log/secure_log.h create mode 100644 modules/log/src/abstract_log_provider.cpp create mode 100644 modules/log/src/dlog_log_provider.cpp create mode 100644 modules/log/src/log.cpp create mode 100644 modules/log/src/old_style_log_provider.cpp create mode 100644 modules/rpc/config.cmake create mode 100644 modules/rpc/include/dpl/rpc/abstract_rpc_connection.h create mode 100644 modules/rpc/include/dpl/rpc/abstract_rpc_connector.h create mode 100644 modules/rpc/include/dpl/rpc/generic_rpc_connection.h create mode 100644 modules/rpc/include/dpl/rpc/generic_socket_rpc_client.h create mode 100644 modules/rpc/include/dpl/rpc/generic_socket_rpc_connection.h create mode 100644 modules/rpc/include/dpl/rpc/generic_socket_rpc_server.h create mode 100644 modules/rpc/include/dpl/rpc/rpc_function.h create mode 100644 modules/rpc/include/dpl/rpc/unix_socket_rpc_client.h create mode 100644 modules/rpc/include/dpl/rpc/unix_socket_rpc_connection.h create mode 100644 modules/rpc/include/dpl/rpc/unix_socket_rpc_server.h create mode 100644 modules/rpc/src/abstract_rpc_connection.cpp create mode 100644 modules/rpc/src/abstract_rpc_connector.cpp create mode 100644 modules/rpc/src/generic_rpc_connection.cpp create mode 100644 modules/rpc/src/generic_socket_rpc_client.cpp create mode 100644 modules/rpc/src/generic_socket_rpc_connection.cpp create mode 100644 modules/rpc/src/generic_socket_rpc_server.cpp create mode 100644 modules/rpc/src/unix_socket_rpc_client.cpp create mode 100644 modules/rpc/src/unix_socket_rpc_connection.cpp create mode 100644 modules/rpc/src/unix_socket_rpc_server.cpp create mode 100644 modules/security_origin_dao/CMakeLists.txt create mode 100644 modules/security_origin_dao/dao/security_origin_dao.cpp create mode 100755 modules/security_origin_dao/dao/security_origin_dao_types.cpp create mode 100644 modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao.h create mode 100755 modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao_types.h create mode 100644 modules/security_origin_dao/orm/orm_generator_security_origin.h create mode 100644 modules/security_origin_dao/orm/security_origin_db create mode 100644 modules/security_origin_dao/orm/security_origin_db_definitions create mode 100644 modules/security_origin_dao/orm/security_origin_db_sql_generator.h create mode 100644 modules/socket/config.cmake create mode 100644 modules/socket/include/dpl/socket/abstract_socket.h create mode 100644 modules/socket/include/dpl/socket/generic_socket.h create mode 100644 modules/socket/include/dpl/socket/unix_socket.h create mode 100644 modules/socket/include/dpl/socket/waitable_input_output_execution_context_support.h create mode 100644 modules/socket/src/generic_socket.cpp create mode 100644 modules/socket/src/unix_socket.cpp create mode 100644 modules/socket/src/waitable_input_output_execution_context_support.cpp create mode 100644 modules/support/config.cmake create mode 100755 modules/support/wrt_plugin_export.h create mode 100644 modules/test/config.cmake create mode 100644 modules/test/include/dpl/test/abstract_input_parser.h create mode 100644 modules/test/include/dpl/test/abstract_input_reader.h create mode 100644 modules/test/include/dpl/test/abstract_input_tokenizer.h create mode 100644 modules/test/include/dpl/test/process_pipe.h create mode 100644 modules/test/include/dpl/test/test_results_collector.h create mode 100644 modules/test/include/dpl/test/test_runner.h create mode 100644 modules/test/include/dpl/test/test_runner_child.h create mode 100644 modules/test/include/dpl/test/test_runner_multiprocess.h create mode 100644 modules/test/include/dpl/test/value_separated_parser.h create mode 100644 modules/test/include/dpl/test/value_separated_policies.h create mode 100644 modules/test/include/dpl/test/value_separated_reader.h create mode 100644 modules/test/include/dpl/test/value_separated_tokenizer.h create mode 100644 modules/test/include/dpl/test/value_separated_tokens.h create mode 100644 modules/test/src/process_pipe.cpp create mode 100644 modules/test/src/test_results_collector.cpp create mode 100644 modules/test/src/test_runner.cpp create mode 100644 modules/test/src/test_runner_child.cpp create mode 100644 modules/test/src/test_runner_multiprocess.cpp create mode 100644 modules/test/src/value_separated_policies.cpp create mode 100644 modules/test/src/value_separated_tokens.cpp create mode 100644 modules/utils/config.cmake create mode 100644 modules/utils/include/dpl/utils/bash_utils.h create mode 100644 modules/utils/include/dpl/utils/folder_size.h create mode 100644 modules/utils/include/dpl/utils/mime_type_utils.h create mode 100644 modules/utils/include/dpl/utils/path.h create mode 100644 modules/utils/include/dpl/utils/warp_iri.h create mode 100644 modules/utils/include/dpl/utils/widget_version.h create mode 100644 modules/utils/include/dpl/utils/wrt_global_settings.h create mode 100644 modules/utils/include/dpl/utils/wrt_utility.h create mode 100644 modules/utils/src/bash_utils.cpp create mode 100644 modules/utils/src/folder_size.cpp create mode 100644 modules/utils/src/mime_type_utils.cpp create mode 100644 modules/utils/src/path.cpp create mode 100644 modules/utils/src/warp_iri.cpp create mode 100644 modules/utils/src/widget_version.cpp create mode 100644 modules/utils/src/wrt_global_settings.cpp create mode 100644 modules/utils/src/wrt_utility.cpp create mode 100644 modules/widget_dao/CMakeLists.txt create mode 100644 modules/widget_dao/dao/WrtDatabase.cpp create mode 100644 modules/widget_dao/dao/common_dao_types.cpp create mode 100644 modules/widget_dao/dao/config_parser_data.cpp create mode 100644 modules/widget_dao/dao/feature_dao.cpp create mode 100644 modules/widget_dao/dao/feature_dao_read_only.cpp create mode 100644 modules/widget_dao/dao/path_builder.cpp create mode 100644 modules/widget_dao/dao/plugin_dao.cpp create mode 100644 modules/widget_dao/dao/plugin_dao_read_only.cpp create mode 100644 modules/widget_dao/dao/property_dao.cpp create mode 100644 modules/widget_dao/dao/property_dao_read_only.cpp create mode 100644 modules/widget_dao/dao/webruntime_database.cpp create mode 100755 modules/widget_dao/dao/widget_dao.cpp create mode 100755 modules/widget_dao/dao/widget_dao_read_only.cpp create mode 100644 modules/widget_dao/dao/widget_dao_types.cpp create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/WrtDatabase.h create mode 100755 modules/widget_dao/include/dpl/wrt-dao-ro/common_dao_types.h create mode 100755 modules/widget_dao/include/dpl/wrt-dao-ro/config_parser_data.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/feature_dao_read_only.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/feature_model.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/path_builder.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/plugin_dao_read_only.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/property_dao_read_only.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/webruntime_database.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/widget_config.h create mode 100755 modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_read_only.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_types.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-ro/wrt_db_types.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-rw/feature_dao.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-rw/plugin_dao.h create mode 100644 modules/widget_dao/include/dpl/wrt-dao-rw/property_dao.h create mode 100755 modules/widget_dao/include/dpl/wrt-dao-rw/widget_dao.h create mode 100755 modules/widget_dao/orm/gen_db_md5.sh create mode 100644 modules/widget_dao/orm/orm_generator_wrt.h create mode 100644 modules/widget_dao/orm/version_db create mode 100644 modules/widget_dao/orm/wrt_db create mode 100644 modules/widget_dao/orm/wrt_db_definitions create mode 100644 modules/widget_dao/orm/wrt_db_sql_generator.h create mode 100644 modules/widget_interface_dao/CMakeLists.txt create mode 100644 modules/widget_interface_dao/dao/widget_interface_dao.cpp create mode 100644 modules/widget_interface_dao/include/wrt-commons/widget-interface-dao/widget_interface_dao.h create mode 100644 modules/widget_interface_dao/orm/orm_generator_widget_interface.h create mode 100644 modules/widget_interface_dao/orm/widget_interface_db create mode 100644 modules/widget_interface_dao/orm/widget_interface_db_definitions create mode 100644 modules/widget_interface_dao/orm/widget_interface_db_sql_generator.h create mode 100644 packaging/wrt-commons.spec create mode 100644 tests/CMakeLists.txt create mode 100644 tests/CMakeUtils.txt create mode 100644 tests/common/include/glib_interface.h create mode 100644 tests/common/include/loop_control.h create mode 100644 tests/common/src/loop_control.cpp create mode 100644 tests/core/CMakeLists.txt create mode 100644 tests/core/DESCRIPTION create mode 100644 tests/core/data/sample.zip create mode 100644 tests/core/main.cpp create mode 100644 tests/core/test_address.cpp create mode 100644 tests/core/test_binary_queue.cpp create mode 100644 tests/core/test_bind.cpp create mode 100644 tests/core/test_foreach.cpp create mode 100644 tests/core/test_log_unhandled_exception.cpp create mode 100644 tests/core/test_once.cpp create mode 100644 tests/core/test_scope_guard.cpp create mode 100644 tests/core/test_scoped_array.cpp create mode 100644 tests/core/test_scoped_close.cpp create mode 100644 tests/core/test_scoped_dir.cpp create mode 100644 tests/core/test_scoped_fclose.cpp create mode 100644 tests/core/test_scoped_free.cpp create mode 100644 tests/core/test_scoped_ptr.cpp create mode 100644 tests/core/test_semaphore.cpp create mode 100644 tests/core/test_serialization.cpp create mode 100644 tests/core/test_shared_ptr.cpp create mode 100644 tests/core/test_single_instance.cpp create mode 100644 tests/core/test_static_block.cpp create mode 100644 tests/core/test_string.cpp create mode 100644 tests/core/test_thread.cpp create mode 100644 tests/core/test_type_list.cpp create mode 100644 tests/core/test_waitable_handle_watch.cpp create mode 100644 tests/core/test_zip_input.cpp create mode 100644 tests/dao/CMakeLists.txt create mode 100644 tests/dao/README create mode 100644 tests/dao/TestCases_CertificateDAO.cpp create mode 100644 tests/dao/TestCases_CustomHandlerDAO.cpp create mode 100644 tests/dao/TestCases_FeatureDAO.cpp create mode 100644 tests/dao/TestCases_PluginDAO.cpp create mode 100644 tests/dao/TestCases_PropertyDAO.cpp create mode 100644 tests/dao/TestCases_SecurityOriginDAO.cpp create mode 100755 tests/dao/TestCases_WidgetDAO.cpp create mode 100644 tests/dao/TestCases_WidgetInterfaceDAO.cpp create mode 100644 tests/dao/tests_dao.cpp create mode 100755 tests/dao/wrt_dao_tests_prepare_db.sh create mode 100644 tests/db/CMakeLists.txt create mode 100644 tests/db/main.cpp create mode 100644 tests/db/orm/CMakeLists.txt create mode 100644 tests/db/orm/dpl_orm_test_db create mode 100644 tests/db/orm/dpl_orm_test_db_definitions create mode 100644 tests/db/orm/dpl_orm_test_db_sql_generator.h create mode 100644 tests/db/orm/dpl_orm_test_db_sql_generator.h.gch create mode 100644 tests/db/orm/generator_dpl_orm_test.h create mode 100644 tests/db/test_orm.cpp create mode 100644 tests/db/test_sql_connection.cpp create mode 100644 tests/dbus/CMakeLists.txt create mode 100644 tests/dbus/data/org.tizen.DBusTestService.service create mode 100644 tests/dbus/dbus_test.cpp create mode 100644 tests/dbus/dbus_test.h create mode 100644 tests/dbus/main.cpp create mode 100644 tests/dbus/test_cases.cpp create mode 100644 tests/dbus/test_service.cpp create mode 100644 tests/event/CMakeLists.txt create mode 100644 tests/event/main.cpp create mode 100644 tests/event/test_controller.cpp create mode 100644 tests/event/test_event_support.cpp create mode 100644 tests/event/test_ic_delegate.cpp create mode 100644 tests/event/test_property.cpp create mode 100644 tests/files_localization/CMakeLists.txt create mode 100644 tests/files_localization/files/CMakeLists.txt create mode 100644 tests/files_localization/files/icon create mode 100644 tests/files_localization/files/icon2 create mode 100644 tests/files_localization/files/one create mode 100644 tests/files_localization/files/two.html create mode 100644 tests/files_localization/test_localization.cpp create mode 100644 tests/files_localization/test_suite01.cpp create mode 100644 tests/files_localization/wrt_db_localization_prepare.sh create mode 100644 tests/i18n/CMakeLists.txt create mode 100644 tests/i18n/main.cpp create mode 100644 tests/i18n/test_i18n_dao_read_only.cpp create mode 100644 tests/localizationTagsProvider/CMakeLists.txt create mode 100644 tests/localizationTagsProvider/Localization_testcases.cpp create mode 100644 tests/localizationTagsProvider/README create mode 100644 tests/localizationTagsProvider/tests_miscunit.cpp create mode 100644 tests/test/CMakeLists.txt create mode 100644 tests/test/main.cpp create mode 100644 tests/test/runner_child.cpp create mode 100644 tests/test/runner_multiprocess.cpp create mode 100644 tests/test/test_abstract_input_reader.cpp create mode 100644 tests/test/test_process_pipe.cpp create mode 100644 tests/test/test_value_separated_reader.cpp create mode 100644 tests/unused/test_caller.cpp create mode 100644 tests/unused/test_crypto_hash.cpp create mode 100644 tests/unused/test_message_queue.cpp create mode 100644 tests/unused/test_shm.cpp create mode 100644 tests/unused/test_sql_connection.cpp create mode 100644 tests/unused/test_task.cpp create mode 100644 tests/utils/CMakeLists.txt create mode 100644 tests/utils/bash_utils.cpp create mode 100644 tests/utils/main.cpp create mode 100644 tests/utils/path_tests.cpp create mode 100644 tests/utils/widget_version.cpp create mode 100644 tests/utils/wrt_utility.cpp create mode 100644 uncrustify.cfg create mode 100755 uncrustify.sh create mode 100644 wrt-commons create mode 100644 wrt-commons.manifest diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..4c72b9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +*.log +*.a +*.o +*.so +*.so.* +*.sql +*.db +*.db-journal +*.pc + +CMakeCache.txt +CMakeFiles +install_manifest.txt +cmake_install.cmake +Makefile + +documentation.list +modules/widget_dao/database_checksum.h +modules/security_origin_dao/database_checksum_security_origin.h +modules/custom_handler_dao/database_checksum_custom_handler.h +modules/certificate_dao/database_checksum_certificage.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ffc39e1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,203 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# + +# Check minimum CMake version +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +# Project name +PROJECT(dpl) + +STRING(REGEX MATCH "([^.]*)" API_VERSION "${VERSION}") +ADD_DEFINITIONS("-DAPI_VERSION=\"$(API_VERSION)\"") + +# Comment this to disable control of global settings with environment variable +ADD_DEFINITIONS("-DGLOBAL_SETTINGS_CONTROL") + +# Build type +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Release") +ENDIF(NOT CMAKE_BUILD_TYPE) + +# Options +OPTION(DPL_LOG "DPL logs status" OFF) +ADD_DEFINITIONS(-DLOG_TAG="WRT-COMMONS") +IF(DPL_LOG AND NOT CMAKE_BUILD_TYPE MATCHES "profiling") + MESSAGE(STATUS "Logging enabled for DPL") + ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") +ELSE(DPL_LOG AND NOT CMAKE_BUILD_TYPE MATCHES "profiling") + MESSAGE(STATUS "Logging disabled for DPL") +ENDIF(DPL_LOG AND NOT CMAKE_BUILD_TYPE MATCHES "profiling") + +OPTION(WITH_TESTS "Build tests" OFF) +OPTION(WITH_CHILD "Build additional test subdirectory. WITH_TEST must be ON" OFF) + +# Compiler flags +SET(CMAKE_C_FLAGS_PROFILING "-O2") +SET(CMAKE_CXX_FLAGS_PROFILING "-O2 -std=c++0x") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -std=c++0x -g") +SET(CMAKE_C_FLAGS_RELEASE "-Os") +SET(CMAKE_CXX_FLAGS_RELEASE "-Os -std=c++0x -fvisibility-inlines-hidden") +SET(CMAKE_CXX_FLAGS_CCOV "-O0 -std=c++0x -g --coverage") + +ADD_DEFINITIONS("-fPIC") # If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on the m68k, PowerPC and SPARC. (BJ: our ARM too?) + +# CMake settings +MESSAGE(STATUS "========================================") +MESSAGE(STATUS "CMAKE_BINARY_DIR: " ${CMAKE_BINARY_DIR}) +MESSAGE(STATUS "CMAKE_CURRENT_BINARY_DIR: " ${CMAKE_CURRENT_BINARY_DIR}) +MESSAGE(STATUS "CMAKE_SOURCE_DIR: " ${CMAKE_SOURCE_DIR}) +MESSAGE(STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR}) +MESSAGE(STATUS "PROJECT_BINARY_DIR: " ${PROJECT_BINARY_DIR}) +MESSAGE(STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR}) +MESSAGE(STATUS "EXECUTABLE_OUTPUT_PATH: " ${EXECUTABLE_OUTPUT_PATH}) +MESSAGE(STATUS "LIBRARY_OUTPUT_PATH: " ${LIBRARY_OUTPUT_PATH}) +MESSAGE(STATUS "CMAKE_MODULE_PATH: " ${CMAKE_MODULE_PATH}) +MESSAGE(STATUS "CMAKE_COMMAND: " ${CMAKE_COMMAND}) +MESSAGE(STATUS "CMAKE_ROOT: " ${CMAKE_ROOT}) +MESSAGE(STATUS "CMAKE_CURRENT_LIST_FILE: " ${CMAKE_CURRENT_LIST_FILE}) +MESSAGE(STATUS "CMAKE_CURRENT_LIST_LINE: " ${CMAKE_CURRENT_LIST_LINE}) +MESSAGE(STATUS "CMAKE_INCLUDE_PATH: " ${CMAKE_INCLUDE_PATH}) +MESSAGE(STATUS "CMAKE_LIBRARY_PATH: " ${CMAKE_LIBRARY_PATH}) +MESSAGE(STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM}) +MESSAGE(STATUS "CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME}) +MESSAGE(STATUS "CMAKE_SYSTEM_VERSION: " ${CMAKE_SYSTEM_VERSION}) +MESSAGE(STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR}) +MESSAGE(STATUS "UNIX: " ${UNIX}) +MESSAGE(STATUS "WIN32: " ${WIN32}) +MESSAGE(STATUS "APPLE: " ${APPLE}) +MESSAGE(STATUS "MINGW: " ${MINGW}) +MESSAGE(STATUS "CYGWIN: " ${CYGWIN}) +MESSAGE(STATUS "BORLAND: " ${BORLAND}) +MESSAGE(STATUS "MSVC: " ${MSVC}) +MESSAGE(STATUS "MSVC_IDE: " ${MSVC_IDE}) +MESSAGE(STATUS "MSVC60: " ${MSVC60}) +MESSAGE(STATUS "MSVC70: " ${MSVC70}) +MESSAGE(STATUS "MSVC71: " ${MSVC71}) +MESSAGE(STATUS "MSVC80: " ${MSVC80}) +MESSAGE(STATUS "CMAKE_COMPILER_2005: " ${CMAKE_COMPILER_2005}) +MESSAGE(STATUS "CMAKE_SKIP_RULE_DEPENDENCY: " ${CMAKE_SKIP_RULE_DEPENDENCY}) +MESSAGE(STATUS "CMAKE_SKIP_INSTALL_ALL_DEPENDENCY: " ${CMAKE_SKIP_INSTALL_ALL_DEPENDENCY}) +MESSAGE(STATUS "CMAKE_SKIP_RPATH: " ${CMAKE_SKIP_RPATH}) +MESSAGE(STATUS "CMAKE_VERBOSE_MAKEFILE: " ${CMAKE_VERBOSE_MAKEFILE}) +MESSAGE(STATUS "CMAKE_SUPPRESS_REGENERATION: " ${CMAKE_SUPPRESS_REGENERATION}) +MESSAGE(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) +MESSAGE(STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS}) +MESSAGE(STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE}) +MESSAGE(STATUS "BUILD_SHARED_LIBS: " ${BUILD_SHARED_LIBS}) +MESSAGE(STATUS "CMAKE_C_COMPILER: " ${CMAKE_C_COMPILER}) +MESSAGE(STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER}) +MESSAGE(STATUS "CMAKE_COMPILER_IS_GNUCC: " ${CMAKE_COMPILER_IS_GNUCC}) +MESSAGE(STATUS "CMAKE_COMPILER_IS_GNUCXX : " ${CMAKE_COMPILER_IS_GNUCXX}) +MESSAGE(STATUS "CMAKE_AR: " ${CMAKE_AR}) +MESSAGE(STATUS "CMAKE_RANLIB: " ${CMAKE_RANLIB}) +MESSAGE(STATUS "WITH_TESTS: " ${WITH_TESTS}) +MESSAGE(STATUS "WITH_CHILD: " ${WITH_CHILD}) +MESSAGE(STATUS "========================================") + +# Compiler flags +ADD_DEFINITIONS("-fvisibility=default") # mark all exported symbols as visible + +# Warnings mode +#ADD_DEFINITIONS("-Werror") # Make all warnings into errors. + +# Warning flags +ADD_DEFINITIONS("-Wall") # Generate all warnings +ADD_DEFINITIONS("-Wextra") # Generate even more extra warnings +ADD_DEFINITIONS("-pedantic") # Accept only pedantic code +#ADD_DEFINITIONS("-Weffc++") # Accept only effective C++ code +ADD_DEFINITIONS("-Wwrite-strings") # Do not accept writing to contant string memory +ADD_DEFINITIONS("-Winit-self") # Do not accept initializing variable with itself +ADD_DEFINITIONS("-Wcast-align") # Do not accept misaligning with casting +ADD_DEFINITIONS("-Wcast-qual") # Do not accept removing qualifiers with casting +#ADD_DEFINITIONS("-Wold-style-cast") # Do not accept old style casting +ADD_DEFINITIONS("-Wpointer-arith") # Warn about void pointer arthimetic +ADD_DEFINITIONS("-Wstrict-aliasing") # Ensure strict aliasing +ADD_DEFINITIONS("-Wuninitialized") # Do not accept uninitialized variables +ADD_DEFINITIONS("-Wmissing-declarations") # Warn about global and non-accesible functions +ADD_DEFINITIONS("-Woverloaded-virtual") # Warn about incidental overiding non-virtual base methods +ADD_DEFINITIONS("-Wnon-virtual-dtor") # Warn about non-virtual destructor +ADD_DEFINITIONS("-Wctor-dtor-privacy") # Warn about useless and non-constructible classes +#ADD_DEFINITIONS("-Wlong-long") # Do not allow using long long +#ADD_DEFINITIONS("-Wunreachable-code") # Warn about unreachable code +ADD_DEFINITIONS("-Wfloat-equal") # Do not accept comparing floating points with equal operator +ADD_DEFINITIONS("-Wabi") # Warn about possible ABI problems +ADD_DEFINITIONS("-Wswitch-enum") # Check switch enumeration +ADD_DEFINITIONS("-Wformat=2") # Check printf formatting +ADD_DEFINITIONS("-Wundef") # Warn if an undefined identifier is evaluated in an @if directive. +ADD_DEFINITIONS("-Wshadow") # Warn whenever a local variable shadows another local variable, parameter or global variable or whenever a built-in function is shadowed +ADD_DEFINITIONS("-Wconversion") # Warn for implicit conversions that may alter a value +ADD_DEFINITIONS("-Wlogical-op") # Warn about suspicious uses of logical operators in expressions +#ADD_DEFINITIONS("-Waggregate-return") # Warn if any functions that return structures or unions are defined or called. +ADD_DEFINITIONS("-Wmissing-field-initializers") # Warn if a structure's initializer has some fields missing. +ADD_DEFINITIONS("-Wredundant-decls") # Warn if anything is declared more than once in the same scope, even in cases where multiple declaration is valid and changes nothing. +#ADD_DEFINITIONS("-Wmissing-include-dirs") # Warn if a user-supplied include directory does not exist. +ADD_DEFINITIONS("-Wswitch-default") # Warn whenever a switch statement does not have a default case. +ADD_DEFINITIONS("-Wsync-nand") # Warn when __sync_fetch_and_nand and __sync_nand_and_fetch built-in functions are used. These functions changed semantics in GCC 4.4. +ADD_DEFINITIONS("-Wunused") # All the above -Wunused options combined. +ADD_DEFINITIONS("-Wstrict-overflow=5") # Also warn about cases where the compiler reduces the magnitude of a constant involved in a comparison. +#ADD_DEFINITIONS("-Wunsafe-loop-optimizations") # Warn if the loop cannot be optimized because the compiler could not assume anything on the bounds of the loop indices. With -funsafe-loop-optimizations warn if the compiler made such assumptions. +#ADD_DEFINITIONS("-Wmissing-format-attribute") # Warn about function pointers which might be candidates for format attributes. +#ADD_DEFINITIONS("-Wpadded") # Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure. +#ADD_DEFINITIONS("-Winline") # Warn if a function can not be inlined and it was declared as inline. +ADD_DEFINITIONS("-Wdisabled-optimization") # Warn if a requested optimization pass is disabled. +ADD_DEFINITIONS("-std=c++0x") + +# +# Core library files +# +# Define all core library headers and sources. As detail files +# are usually templated and though recompiled in each file, we +# have to compile full source for each target. +# + +# Set names of binaries being created +SET(TARGET_DPL_EFL "lib${PROJECT_NAME}-efl") +SET(TARGET_DPL_DBUS_EFL "lib${PROJECT_NAME}-dbus-efl") +SET(TARGET_DPL_DB_EFL "lib${PROJECT_NAME}-db-efl") +SET(TARGET_DPL_EVENT_EFL "lib${PROJECT_NAME}-event-efl") +SET(TARGET_DPL_SOCKET_EFL "lib${PROJECT_NAME}-socket-efl") +SET(TARGET_DPL_RPC_EFL "lib${PROJECT_NAME}-rpc-efl") +SET(TARGET_DPL_TEST_ENGINE_EFL "lib${PROJECT_NAME}-test-efl") +SET(TARGET_DPL_LOG_EFL "lib${PROJECT_NAME}-log-efl") +SET(TARGET_WRT_DAO_RW_LIB "dpl-wrt-dao-rw") +SET(TARGET_WRT_DAO_RO_LIB "dpl-wrt-dao-ro") +SET(TARGET_CUSTOM_HANDLER_DAO_RW_LIB "wrt-commons-custom-handler-dao-rw") +SET(TARGET_CUSTOM_HANDLER_DAO_RO_LIB "wrt-commons-custom-handler-dao-ro") +SET(TARGET_SECURITY_ORIGIN_DAO_LIB "wrt-commons-security-origin-dao") +SET(TARGET_CERTIFICATE_DAO_LIB "wrt-commons-certificate-dao") +SET(TARGET_DPL_UTILS_EFL "lib${PROJECT_NAME}-utils-efl") +SET(TARGET_I18N_DAO_RO_LIB "wrt-commons-i18n-dao-ro") +SET(TARGET_WIDGET_INTERFACE_DAO_LIB "wrt-commons-widget-interface-dao") + +MACRO(configure_and_install_pkg PKG_FILE) + CONFIGURE_FILE(${PKG_FILE}.in ${PKG_FILE} @ONLY) + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PKG_FILE} DESTINATION lib/pkgconfig) +ENDMACRO(configure_and_install_pkg) + +ADD_SUBDIRECTORY(modules) + +ADD_SUBDIRECTORY(build) +ADD_SUBDIRECTORY(etc) + +IF(WITH_TESTS) + ADD_SUBDIRECTORY(tests) +ENDIF(WITH_TESTS) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..247c97d --- /dev/null +++ b/LICENSE @@ -0,0 +1,203 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..ded3804 --- /dev/null +++ b/NOTICE @@ -0,0 +1 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. \ No newline at end of file diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt new file mode 100644 index 0000000..b94d51f --- /dev/null +++ b/build/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(dbus) +ADD_SUBDIRECTORY(db) +ADD_SUBDIRECTORY(event) +ADD_SUBDIRECTORY(socket) +ADD_SUBDIRECTORY(rpc) +ADD_SUBDIRECTORY(test) +#ADD_SUBDIRECTORY(log) +ADD_SUBDIRECTORY(widget_dao) +ADD_SUBDIRECTORY(security_origin_dao) +ADD_SUBDIRECTORY(custom_handler_dao) +ADD_SUBDIRECTORY(utils) +ADD_SUBDIRECTORY(support) +ADD_SUBDIRECTORY(certificate_dao) +ADD_SUBDIRECTORY(i18n) +ADD_SUBDIRECTORY(widget_interface_dao) diff --git a/build/certificate_dao/CMakeLists.txt b/build/certificate_dao/CMakeLists.txt new file mode 100755 index 0000000..e893640 --- /dev/null +++ b/build/certificate_dao/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Leerang Song (leerang.song@samsung.com) +# @brief +# + +CONFIGURE_AND_INSTALL_PKG(wrt-commons-certificate-dao.pc) + diff --git a/build/certificate_dao/wrt-commons-certificate-dao.pc.in b/build/certificate_dao/wrt-commons-certificate-dao.pc.in new file mode 100644 index 0000000..903dc95 --- /dev/null +++ b/build/certificate_dao/wrt-commons-certificate-dao.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: wrt-commons-certificate-dao +Description: wrt-commons-certificate-dao + +Version: @VERSION@ +Requires: dpl-efl +Libs: -lwrt-commons-certificate-dao -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/build/core/CMakeLists.txt b/build/core/CMakeLists.txt new file mode 100644 index 0000000..cdc17cf --- /dev/null +++ b/build/core/CMakeLists.txt @@ -0,0 +1,80 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL + ecore + appcore-efl + capi-appfw-application + openssl + dlog + vconf + libpcrecpp + icu-uc + minizip + REQUIRED) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_INCLUDE_DIRS}) + +LINK_DIRECTORIES(${SYS_EFL_LIBRARY_DIRS}) + +# Base EFL based DPL library +SET(DPL_EFL_LIBRARY "${PROJECT_NAME}-efl") + +# Build shared library +ADD_LIBRARY(${TARGET_DPL_EFL} SHARED + ${DPL_CORE_SOURCES} + ${DPL_LOG_SOURCES} +) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_EFL} ${SYS_EFL_LIBRARIES} "-lrt") + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_CORE_EFL_DETAIL_HEADERS} + DESTINATION include/dpl-efl/dpl) + +# Install core headers +INSTALL(FILES ${DPL_CORE_HEADERS} + DESTINATION include/dpl-efl/dpl) + +# Install log headers +INSTALL(FILES ${DPL_LOG_HEADERS} + DESTINATION include/dpl-efl/dpl/log) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-efl.pc) diff --git a/build/core/DESCRIPTION b/build/core/DESCRIPTION new file mode 100644 index 0000000..f7f1581 --- /dev/null +++ b/build/core/DESCRIPTION @@ -0,0 +1,2 @@ +!!!options!!! stop +EFL support diff --git a/build/core/dpl-efl.pc.in b/build/core/dpl-efl.pc.in new file mode 100644 index 0000000..6d2a882 --- /dev/null +++ b/build/core/dpl-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-efl +Description: DPL - EFL based +Version: @VERSION@ +Requires: ecore appcore-efl openssl dlog vconf +Libs: -L${libdir} -ldpl-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/custom_handler_dao/CMakeLists.txt b/build/custom_handler_dao/CMakeLists.txt new file mode 100644 index 0000000..cacc560 --- /dev/null +++ b/build/custom_handler_dao/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) +# @brief +# + +CONFIGURE_AND_INSTALL_PKG(wrt-commons-custom-handler-dao-ro.pc) +CONFIGURE_AND_INSTALL_PKG(wrt-commons-custom-handler-dao-rw.pc) diff --git a/build/custom_handler_dao/wrt-commons-custom-handler-dao-ro.pc.in b/build/custom_handler_dao/wrt-commons-custom-handler-dao-ro.pc.in new file mode 100644 index 0000000..7cda187 --- /dev/null +++ b/build/custom_handler_dao/wrt-commons-custom-handler-dao-ro.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: wrt-commons-custom-handler-dao-ro +Description: wrt-commons-custom-handler-dao-ro + +Version: @VERSION@ +Requires: dpl-efl +Libs: -lwrt-commons-custom-handler-dao-ro -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/build/custom_handler_dao/wrt-commons-custom-handler-dao-rw.pc.in b/build/custom_handler_dao/wrt-commons-custom-handler-dao-rw.pc.in new file mode 100644 index 0000000..4cd2737 --- /dev/null +++ b/build/custom_handler_dao/wrt-commons-custom-handler-dao-rw.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: wrt-commons-custom-handler-dao-rw +Description: wrt-commons-custom-handler-dao-rw + +Version: @VERSION@ +Requires: dpl-efl wrt-commons-custom-handler-dao-ro +Libs: -lwrt-commons-custom-handler-dao-rw -lwrt-commons-custom-handler-dao-ro -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/build/db/CMakeLists.txt b/build/db/CMakeLists.txt new file mode 100644 index 0000000..282e55b --- /dev/null +++ b/build/db/CMakeLists.txt @@ -0,0 +1,70 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_DB + sqlite3 + db-util + REQUIRED) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} + ${DPL_DB_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_DB_INCLUDE_DIRS}) + +LINK_DIRECTORIES( + ${SYS_EFL_DB_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_DB_LIBRARY "${PROJECT_NAME}-db-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_DB_EFL} SHARED ${DPL_DB_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_DB_EFL} + ${SYS_EFL_DB_LIBRARIES} + ${TARGET_DPL_EFL} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_DB_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_DB_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_DB_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_DB_HEADERS} + DESTINATION include/dpl-efl/dpl/db) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-db-efl.pc) diff --git a/build/db/dpl-db-efl.pc.in b/build/db/dpl-db-efl.pc.in new file mode 100644 index 0000000..866bb0f --- /dev/null +++ b/build/db/dpl-db-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-db-efl +Description: DPL DB - EFL based +Version: @VERSION@ +Requires: dpl-efl sqlite3 db-util +Libs: -L${libdir} -ldpl-db-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/dbus/CMakeLists.txt b/build/dbus/CMakeLists.txt new file mode 100644 index 0000000..d274572 --- /dev/null +++ b/build/dbus/CMakeLists.txt @@ -0,0 +1,72 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_DBUS + dbus-1 + gio-2.0 + REQUIRED) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} + ${DPL_DBUS_INCLUDE_DIR} + ${DPL_EVENT_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_DBUS_INCLUDE_DIRS}) + +LINK_DIRECTORIES( + ${SYS_EFL_DBUS_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_DBUS_LIBRARY "${PROJECT_NAME}-dbus-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_DBUS_EFL} SHARED ${DPL_DBUS_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_DBUS_EFL} + ${SYS_EFL_DBUS_LIBRARIES} + ${TARGET_DPL_EFL} + ${TARGET_DPL_EVENT_EFL} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_DBUS_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_DBUS_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_DBUS_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_DBUS_HEADERS} + DESTINATION include/dpl-efl/dpl/dbus) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-dbus-efl.pc) diff --git a/build/dbus/dpl-dbus-efl.pc.in b/build/dbus/dpl-dbus-efl.pc.in new file mode 100644 index 0000000..73f2c03 --- /dev/null +++ b/build/dbus/dpl-dbus-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-dbus-efl +Description: DPL DBus - EFL based +Version: @VERSION@ +Requires: dbus-1 dpl-efl dpl-event-efl +Libs: -L${libdir} -ldpl-dbus-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/event/CMakeLists.txt b/build/event/CMakeLists.txt new file mode 100644 index 0000000..46e13f1 --- /dev/null +++ b/build/event/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_EVENT + ecore + appcore-efl + vconf + REQUIRED +) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} + ${DPL_EVENT_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_EVENT_INCLUDE_DIRS}) + +LINK_DIRECTORIES( + ${SYS_EFL_EVENT_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_EVENT_LIBRARY "${PROJECT_NAME}-event-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_EVENT_EFL} SHARED ${DPL_EVENT_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_EVENT_EFL} + ${SYS_EFL_EVENT_LIBRARIES} + ${TARGET_DPL_EFL} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_EVENT_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_EVENT_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_EVENT_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_EVENT_HEADERS} + DESTINATION include/dpl-efl/dpl/event) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-event-efl.pc) diff --git a/build/event/dpl-event-efl.pc.in b/build/event/dpl-event-efl.pc.in new file mode 100644 index 0000000..d4befbe --- /dev/null +++ b/build/event/dpl-event-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-event-efl +Description: DPL Event - EFL based +Version: @VERSION@ +Requires: dpl-efl ecore appcore-efl vconf +Libs: -L${libdir} -ldpl-event-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/i18n/CMakeLists.txt b/build/i18n/CMakeLists.txt new file mode 100644 index 0000000..20ef24c --- /dev/null +++ b/build/i18n/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) +# @brief +# + +CONFIGURE_AND_INSTALL_PKG(wrt-commons-i18n-dao-ro.pc) diff --git a/build/i18n/wrt-commons-i18n-dao-ro.pc.in b/build/i18n/wrt-commons-i18n-dao-ro.pc.in new file mode 100644 index 0000000..270630b --- /dev/null +++ b/build/i18n/wrt-commons-i18n-dao-ro.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: wrt-commons-i18n-dao-ro +Description: wrt-commons-i18n-dao-ro + +Version: @VERSION@ +Requires: dpl-efl +Libs: -lwrt-commons-i18n-dao-ro -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/build/log/CMakeLists.txt b/build/log/CMakeLists.txt new file mode 100644 index 0000000..497f98d --- /dev/null +++ b/build/log/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_LOG + dlog + REQUIRED +) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_LOG_INCLUDE_DIRS}) + +LINK_DIRECTORIES( + ${SYS_EFL_LOG_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_LOG_LIBRARY "${PROJECT_NAME}-log-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_LOG_EFL} SHARED ${DPL_LOG_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_LOG_EFL} + ${SYS_EFL_LOG_LIBRARIES} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_LOG_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_LOG_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_LOG_EFL} + DESTINATION lib) + +INSTALL(FILES ${DPL_LOG_HEADERS} + DESTINATION include/dpl-efl/dpl/log) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-log-efl.pc) diff --git a/build/log/dpl-log-efl.pc.in b/build/log/dpl-log-efl.pc.in new file mode 100644 index 0000000..7f18689 --- /dev/null +++ b/build/log/dpl-log-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-log-efl +Description: DPL Log Engine - EFL based +Version: @VERSION@ +Requires: dpl-efl dlog +Libs: -L${libdir} -ldpl-log-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/rpc/CMakeLists.txt b/build/rpc/CMakeLists.txt new file mode 100644 index 0000000..b585c37 --- /dev/null +++ b/build/rpc/CMakeLists.txt @@ -0,0 +1,75 @@ + +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_RPC + ecore + appcore-efl + REQUIRED +) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} + ${DPL_SOCKET_INCLUDE_DIR} + ${DPL_EVENT_INCLUDE_DIR} + ${DPL_RPC_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_RPC_INCLUDE_DIRS}) + +LINK_DIRECTORIES( + ${SYS_EFL_RPC_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_RPC_LIBRARY "${PROJECT_NAME}-rpc-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_RPC_EFL} SHARED ${DPL_RPC_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_RPC_EFL} + ${SYS_EFL_RPC_LIBRARIES} + ${TARGET_DPL_EFL} + ${TARGET_DPL_EVENT_EFL} + ${TARGET_DPL_SOCKET_EFL} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_RPC_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_RPC_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_RPC_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_RPC_HEADERS} + DESTINATION include/dpl-efl/dpl/rpc) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-rpc-efl.pc) diff --git a/build/rpc/dpl-rpc-efl.pc.in b/build/rpc/dpl-rpc-efl.pc.in new file mode 100644 index 0000000..d857bbe --- /dev/null +++ b/build/rpc/dpl-rpc-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-rpc-efl +Description: DPL RPC - EFL based +Version: @VERSION@ +Requires: dpl-efl dpl-event-efl dpl-socket-efl +Libs: -L${libdir} -ldpl-rpc-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/security_origin_dao/CMakeLists.txt b/build/security_origin_dao/CMakeLists.txt new file mode 100644 index 0000000..7e6d0d3 --- /dev/null +++ b/build/security_origin_dao/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Jihoon Chung (jihoon.chung@samsung.com) +# @brief +# + +CONFIGURE_AND_INSTALL_PKG(wrt-commons-security-origin-dao.pc) + diff --git a/build/security_origin_dao/wrt-commons-security-origin-dao.pc.in b/build/security_origin_dao/wrt-commons-security-origin-dao.pc.in new file mode 100644 index 0000000..2ab81cb --- /dev/null +++ b/build/security_origin_dao/wrt-commons-security-origin-dao.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: wrt-commons-security-origin-dao +Description: wrt-commons-security-origin-dao + +Version: @VERSION@ +Requires: dpl-efl +Libs: -lwrt-commons-security-origin-dao -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/build/socket/CMakeLists.txt b/build/socket/CMakeLists.txt new file mode 100644 index 0000000..b5b6e47 --- /dev/null +++ b/build/socket/CMakeLists.txt @@ -0,0 +1,72 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_SOCKET + ecore + appcore-efl + REQUIRED +) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} + ${DPL_SOCKET_INCLUDE_DIR} + ${DPL_EVENT_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_SOCKET_INCLUDE_DIRS}) + +LINK_DIRECTORIES( + ${SYS_EFL_SOCKET_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_SOCKET_LIBRARY "${PROJECT_NAME}-socket-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_SOCKET_EFL} SHARED ${DPL_SOCKET_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_SOCKET_EFL} + ${SYS_EFL_SOCKET_LIBRARIES} + ${TARGET_DPL_EFL} + ${TARGET_DPL_EVENT_EFL} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_SOCKET_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_SOCKET_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_SOCKET_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_SOCKET_HEADERS} + DESTINATION include/dpl-efl/dpl/socket) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-socket-efl.pc) diff --git a/build/socket/dpl-socket-efl.pc.in b/build/socket/dpl-socket-efl.pc.in new file mode 100644 index 0000000..1e1409a --- /dev/null +++ b/build/socket/dpl-socket-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-socket-efl +Description: DPL Socket - EFL based +Version: @VERSION@ +Requires: dpl-efl dpl-event-efl +Libs: -L${libdir} -ldpl-socket-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/support/CMakeLists.txt b/build/support/CMakeLists.txt new file mode 100644 index 0000000..8a1345e --- /dev/null +++ b/build/support/CMakeLists.txt @@ -0,0 +1,26 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# Install headers +INSTALL(FILES ${DPL_WRT_ENGINE_HEADERS} + DESTINATION include/dpl-efl/wrt-commons) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(wrt-plugins-types.pc) diff --git a/build/support/wrt-plugins-types.pc.in b/build/support/wrt-plugins-types.pc.in new file mode 100644 index 0000000..b35b9b4 --- /dev/null +++ b/build/support/wrt-plugins-types.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: wrt-plugins-types +Description: Header for plugins types +Version: @VERSION@ +Requires: +Libs: +Cflags: -I${includedir}/dpl-efl/wrt-commons diff --git a/build/test/CMakeLists.txt b/build/test/CMakeLists.txt new file mode 100644 index 0000000..6c6c573 --- /dev/null +++ b/build/test/CMakeLists.txt @@ -0,0 +1,70 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_TEST_ENGINE + appcore-efl + libxml-2.0 + REQUIRED) + + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} + ${DPL_TEST_ENGINE_INCLUDE_DIR} + ${DPL_UTILS_INCLUDE_DIR} +) + +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_TEST_ENGINE_INCLUDE_DIRS}) + +LINK_DIRECTORIES( + ${SYS_EFL_TEST_ENGINE_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_TEST_ENGINE_LIBRARY "${PROJECT_NAME}-test-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_TEST_ENGINE_EFL} SHARED ${DPL_TEST_ENGINE_SOURCES}) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_TEST_ENGINE_EFL} + ${TARGET_DPL_EFL} + ${TARGET_DPL_UTILS_EFL} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_TEST_ENGINE_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_TEST_ENGINE_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_TEST_ENGINE_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_TEST_ENGINE_HEADERS} + DESTINATION include/dpl-efl/dpl/test) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-test-efl.pc) diff --git a/build/test/dpl-test-efl.pc.in b/build/test/dpl-test-efl.pc.in new file mode 100644 index 0000000..056ae09 --- /dev/null +++ b/build/test/dpl-test-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-test-efl +Description: DPL Test Engine - EFL based +Version: @VERSION@ +Requires: dpl-efl libxml-2.0 +Libs: -L${libdir} -ldpl-test-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/utils/CMakeLists.txt b/build/utils/CMakeLists.txt new file mode 100644 index 0000000..14bc1aa --- /dev/null +++ b/build/utils/CMakeLists.txt @@ -0,0 +1,84 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Soyoung Kim (sy037.kim@samsung.com) +# @version 1.0 +# @brief +# + +# Check required modules +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SYS_EFL_UTILS + dlog + libiri + appcore-efl + libidn + REQUIRED +) + +# Add core include directories +INCLUDE_DIRECTORIES( + ${DPL_LOG_INCLUDE_DIR} + ${DPL_CORE_INCLUDE_DIR} + ${DPL_DB_INCLUDE_DIR} + ${DPL_UTILS_INCLUDE_DIR} + ${DPL_LOCALIZATION_INCLUDE_DIR} +) +INCLUDE_DIRECTORIES(SYSTEM ${SYS_EFL_UTILS_INCLUDE_DIRS}) + +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/modules/widget_dao/include) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/modules/vcore/src/vcore) + +LINK_DIRECTORIES( + ${SYS_EFL_UTILS_LIBRARY_DIRS} +) + +# Base EFL based DPL library +SET(DPL_EFL_UTILS_LIBRARY "${PROJECT_NAME}-utils-efl") + +# Build shared library + +ADD_LIBRARY(${TARGET_DPL_UTILS_EFL} SHARED + ${DPL_UTILS_SOURCES} + ${DPL_LOCALIZATION_SOURCES} +) + +TARGET_LINK_LIBRARIES(${TARGET_DPL_UTILS_EFL} + ${SYS_EFL_UTILS_LIBRARIES} + ${TARGET_DPL_EFL} + ${TARGET_WRT_DAO_RW_LIB} + ${SYS_EFL_DB_LIBRARIES} +) + +# Target library properties +SET_TARGET_PROPERTIES(${TARGET_DPL_UTILS_EFL} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION} + CLEAN_DIRECT_OUTPUT 1 + OUTPUT_NAME ${DPL_EFL_UTILS_LIBRARY}) + +# Install libraries +INSTALL(TARGETS ${TARGET_DPL_UTILS_EFL} + DESTINATION lib) + +# Install detail headers +INSTALL(FILES ${DPL_UTILS_HEADERS} + DESTINATION include/dpl-efl/dpl/utils) + +INSTALL(FILES ${DPL_LOCALIZATION_HEADERS} + DESTINATION include/dpl-efl/dpl/localization) + +# Install pkgconfig script +CONFIGURE_AND_INSTALL_PKG(dpl-utils-efl.pc) diff --git a/build/utils/dpl-utils-efl.pc.in b/build/utils/dpl-utils-efl.pc.in new file mode 100644 index 0000000..8e1d4c9 --- /dev/null +++ b/build/utils/dpl-utils-efl.pc.in @@ -0,0 +1,11 @@ +prefix=/usr +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: dpl-utils-efl +Description: DPL UTILS - EFL based +Version: @VERSION@ +Requires: dpl-efl +Libs: -L${libdir} -ldpl-utils-efl +Cflags: -I${includedir}/dpl-efl diff --git a/build/widget_dao/CMakeLists.txt b/build/widget_dao/CMakeLists.txt new file mode 100644 index 0000000..f52c106 --- /dev/null +++ b/build/widget_dao/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) +# @brief +# + +CONFIGURE_AND_INSTALL_PKG(dpl-wrt-dao-ro.pc) +CONFIGURE_AND_INSTALL_PKG(dpl-wrt-dao-rw.pc) diff --git a/build/widget_dao/dpl-wrt-dao-ro.pc.in b/build/widget_dao/dpl-wrt-dao-ro.pc.in new file mode 100644 index 0000000..d2d112b --- /dev/null +++ b/build/widget_dao/dpl-wrt-dao-ro.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: dpl-wrt-dao-ro +Description: dpl-wrt-dao-ro + +Version: @VERSION@ +Requires: dpl-efl libxml-2.0 +Libs: -ldpl-wrt-dao-ro -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/build/widget_dao/dpl-wrt-dao-rw.pc.in b/build/widget_dao/dpl-wrt-dao-rw.pc.in new file mode 100644 index 0000000..c71e58d --- /dev/null +++ b/build/widget_dao/dpl-wrt-dao-rw.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: dpl-wrt-dao-rw +Description: dpl-wrt-dao-rw + +Version: @VERSION@ +Requires: dpl-efl dpl-wrt-dao-ro libxml-2.0 +Libs: -ldpl-wrt-dao-rw -ldpl-wrt-dao-ro -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/build/widget_interface_dao/CMakeLists.txt b/build/widget_interface_dao/CMakeLists.txt new file mode 100644 index 0000000..d132545 --- /dev/null +++ b/build/widget_interface_dao/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Jihoon Chung (jihoon.chung@samsung.com) +# @brief +# + +CONFIGURE_AND_INSTALL_PKG(wrt-commons-widget-interface-dao.pc) + diff --git a/build/widget_interface_dao/wrt-commons-widget-interface-dao.pc.in b/build/widget_interface_dao/wrt-commons-widget-interface-dao.pc.in new file mode 100644 index 0000000..348b178 --- /dev/null +++ b/build/widget_interface_dao/wrt-commons-widget-interface-dao.pc.in @@ -0,0 +1,12 @@ +prefix=/usr +exec_prefix=${prefix} + +libdir=${prefix}/lib +includedir=${prefix}/include +Name: wrt-commons-widget-interface-dao +Description: wrt-commons-widget-interface-dao + +Version: @VERSION@ +Requires: dpl-efl +Libs: -lwrt-commons-widget-interface-dao -L${libdir} +Cflags: -I${includedir}/dpl-efl diff --git a/dir-struct.py b/dir-struct.py new file mode 100755 index 0000000..13eb011 --- /dev/null +++ b/dir-struct.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import os +import re + + +def countLines(path): + with open(path) as f: + return len(f.readlines()) + +# RETURNS: ( +# short description (string or None) +# long decsription (array of strings or None) +# options: stop +def parseDescr(lines): + if len(lines) == 0: + return (None, None, False) + linesRest = None + if re.match( r"!!!options!!!", lines[0] ): + optStop = True + linesRest = lines[1:] + else: + optStop = False + linesRest = lines + if len(linesRest) == 0: + return(None,None,optStop) + short = linesRest[0].rstrip() + long = [] + for l in linesRest[1:]: + ll = l.rstrip() + if re.search( r"\S", ll ): + long.append( ll ) + if len(long) == 0: + long = None + + return (short, long, optStop) + +# RETURNS a tree with nodes like: ( +# path (string) +# short description (string or None) +# long decsription (array of strings or None) +# LOC (integer) +# list of subdirs (child nodes like this one) +def parseDir(path): + short = None + long = None + optStop = False + try: + with open( path+'/DESCRIPTION' ) as f: + short, long, optStop = parseDescr( f.readlines() ) + except IOError: + pass + dirs = [] + cntLines = 0 + for fname in os.listdir(path): + if fname != '.git' and os.path.isdir(path+'/'+fname): + subdir = parseDir(path+'/'+fname) + if optStop == False: + dirs.append(subdir) + (dummy0, dummy1, dummy2, subLines, dummy4) = subdir + cntLines += subLines + + if os.path.isfile(path+'/'+fname) \ + and not os.path.islink(path+'/'+fname): + cntLines += countLines(path+'/'+fname) + + return path, short, long, cntLines, dirs + + +### ##### PRINT AS TEXT +### +### def printTextSub(path,indent,withLongDesc): +### short, long, dirs, loc = parseDir(path) +### if short == None: +### p = re.sub(r"^\./", '', path) +### print '%s%s -- ' % (indent, p) +### else: +### p = re.sub(r"^\./", '', path) +### print '%s%s -- %s' % (indent, p, short) +### if withLongDesc: +### if long != None: +### print '' +### for line in long: +### print '%s%s' % (indent+' ',line) +### print '' +### for dir in dirs: +### printTextSub(path+'/'+dir, indent+' ', withLongDesc) +### +### def printText(path,withLongDesc): +### printTextSub(path,'',withLongDesc) +### +### def printTextWoMain(path,withLongDesc): +### short, long, dirs, loc = parseDir(path) +### for dir in dirs: +### printTextSub(path+'/'+dir, '', withLongDesc) +### + +##### PRINT AS a sort of CSV delimited by '|' + +# indent is a number (0..) +def printTabSub(tree,indent): + path, short, long, loc, subdirs = tree + p = re.sub(r"^\./", '', path) + m = re.search(r"/([^/]*$)", p) + if m != None: p = m.groups()[0] + if short == None: + print '%s%s|%d|' % (" "*indent, p, loc) + else: + print '%s%s|%d|%s' % (" "*indent, p, loc, short) + for dir in subdirs: + printTabSub(dir, indent+1) + +def printTab(tree): + printTabSub(tree,0) + +def printTabWoMain(tree): + path, short, long, loc, dirs = tree + for dir in dirs: + printTabSub(dir, 0) + + +##### MAIN + +tree = parseDir('.') +printTabWoMain(tree) + diff --git a/doc/DESCRIPTION b/doc/DESCRIPTION new file mode 100644 index 0000000..c3f01bd --- /dev/null +++ b/doc/DESCRIPTION @@ -0,0 +1 @@ +Documentation diff --git a/doc/doxyfile b/doc/doxyfile new file mode 100644 index 0000000..f058b7a --- /dev/null +++ b/doc/doxyfile @@ -0,0 +1,1600 @@ +# Doxyfile 1.6.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = DPL + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.0 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set +# FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../core ../detail + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = NO + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = YES + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = NO + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = gif + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/doc/dpl_programming_guide.docx b/doc/dpl_programming_guide.docx new file mode 100644 index 0000000000000000000000000000000000000000..f8e11e9c2f155f1e126cfb173f46cd468925e409 GIT binary patch literal 250036 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 z

rh?`@GlwOTtC%F2LQw$xVF40kiG;8ae*~I!&ij%L8j;|ByVXnIzPvc1dXn)%N zX^khKTKq>Jd}HVIfpqW=;B}E=i*#8b`fx%$AFu!j`HqS@swAy^AY(##@%`lYfgq1x zdJEgvFfO9X!*cp&7oObNv0G_93DGN>NUZ(1TYUpjeo|Dm_Y@HbwO{9Btlqe{b!YHS zYyhmxy^M?3O`xV!zxD6}XUpLVo!zXwCI4~R7l z6}*A4hzKAElb!n4E$%a5ehpo!K%qqGr#EhFs=-+dc2JoG%vreS@6_&dBMCA|G+>*x z2Hg;CfID|!^98IipSj>p{UDP-phu|qS42>+?G;P@eou!3wIC$W!fHpp8@QCJxhmw; zDbR3mAwluhm^bW-L2-o0vqWK_k$(03VaO8h3))yVYIV}Wydzb^c62mwl#6Z@qW*6J z-wp}Sydv^(7vf5)yE+P{TZb<(U{$W#Q^7}?ezA0X%F5x_tayPk3hNnY352N~Y{QvUKDiE{0}hYkbP*24dMs>l%BQB+&iY!#YUU7z zBp~Mu4Cg0gCUzN+=$dt^hmo%`EF&VDyBI0#1%uoT_JdN#|`KhhoTWb@nb-N7_2pRv2759~QY7GaBT$dbT z&acsD*cOzCiywF)VR48lz724#oPirzfxg=gZ}f3n1$>%kdZ6mj-Lw{?ZCrqoa*kA8 z9dc=#O|aM4@N2E%0v!TDkEHvUQ^Fh5b&IUoJB}AOq`EpZ^`U4C(7#RS1#;6LMWLHW z(|6e2wOo*KPfRz}>d#p#$kiQDvSw_drxOa` zyLN5}U{0#s&5J1bB@O%XvZe-6nnXr*U>S7TNyB`S#;}`lti&Hn^gr93+2^m8Bpu1V zVuVF_!w%&1C5BzgfVE^;q$(?Mh>TT%V-`|f3dEJ?--RKO3^sy$Kd4gQS;24{YX}CO z4D~Fz(Dt5Y zki9CRd$LEJX8ek|t1LMFEXa_toy2SVC-`D@t^Y@a6$S*n0Cytb*j}9+e+9CkqQ1U9 z_1R5!W^ny0s++b}M+wHqFdbTQ8$Xme0=qF$&-da=s}@tEPX+dtH*@9%9oW<6@Y_<# z0A@7imoTi~fAsskoLPrn1@b*bqM9-H$|^EuMrF3u25SMnob>h9HMzQ_!2{|C9Y`r6 z^de`ss|qcJdczNef~?zO<*@`Ow_tBtqZ0@rDmy$UF`7>Wz&o)frOf^%rRZ7d9P8!w zT0sBCRtxKz#ah1Gy23Nzz18|6vYV0Kq)$zuC;`n|%73q9`UwE$l}H_rP%^oj8$q2# z8fpi6zAwWmj%S;f)WixPp8T^P?+3;d$<=y^SN7Vi8iZCnI1<&@+h7Ofd}AP%g7SXF z=Am0O@<@~Zy@3N=YnQ(9)pG)ES0pig+4xVpupMniD72HyD@HBX;$~{wOet?B?j8Q% z6;stn`0VVo<60z^!Z3mL7U!m?VbbSbxG!PSUK*m|KYGUftMY>lY~v|y(WJ~=#?(l~ zDQS(RN1c@I=Anrn7ki4Bgl>f1Ov4i(_*-youu~7BNXFtY>VVt=6A6+A8@6*``6&h8 z!<+Ujq1Z3DX5Qdt4I(3v*kECC?%i>PLb!96>+Vkfgn^FQK?n$Eaayo4E@z4O(fFnvS zS4w^SSpdLxel3;p7ur(WD>q#H{gGFH0nI_DLU(FA8J^<0pq7k!O2;sJlVegV@DnA78h*IjIKP!L&0V{6$cjL+- zq!6Epi$tz_4>%5cb-4#zaYHnYk!W!2ltlO6=QjG@<;O)f##g^%XwSo20|>Wz&!gjk z=ohu+nS^1``UBqbYiB*T%Df)D2gzjsyY z7U`uU5c?R_4-|6*vvj%4hZSjXEXm1EPH#seOzO>h{)%-aI(j$M|hM)J&866QHm|IRV$!v{%BK*PglK&H3cq`ZgkQU_&m@BFHQ_Ep%0o1O4Few6OuA>z>qe%3;LZ?JQf>gg* zk{q3tR1NnZl3AFx(xMN6xY4wF^%u_+ikfQc_C;(Z8&Ru354N2qd_HeNMch~u;L(ZK zXGnPSoRYBE*B2vl7u?|TC^7|glq$ziP>TRdZX~hb_FVu&#oYvR|M zX+h&_&&$*NHrm)(Xz*Tgm#o1EfE8-_9XFZk+U~XElh8qJE7Eg^uz*SAzupa9cnq(u z5!e!#G@=hljvj$HkG@NETN2cmN=H|;6RC^A5>G}3kM{P&Kde@~F$h2*00RmN*5(WB zPucjMAWuSt$fSR_IsxzU07W6Ng0=^RUTR1~dKd56;3-A;pR+U8Oq|=a!YhYAB#1^0 z=$1m-cnnfSa5N8MRt-Bld&DI%X-#kO6&5f!0RSw!bfRn6hHo{{~U3WD8kYh48C9b%GwjX-{GZl`v-pPa$PJEEn;3{7jkq$*ek4 zlA_PejwogjUs->**l;Sf&4r5yKw(=0U5fnTYs#*{hLtpX%;U4}sL)BPmcN;``_l{hXX1G$Y9)gH z07jDoV*nV|_0msCQ(&P0p7*DPk_?hIBco)z>2bbzZYl>SlD@|)g!Vomkt{5qP3uW-l$GAbJMwj~)gc%+PPnO^ zXCAb*n+R#fofnzMxq>^|oJ^<}F#bW-xF5%()7M+iWE})HBA*RxbKl<8k2!WUA_UL) z5gmiHXrzL&#QRUbVLg?!Lq}LYdXpY!uEH$Fbf+$5p+E!u+$QWt0NRKMcp9k?vKd!k zvOV6jp?`RZfC?W^1X`4BugWw^v5WTT%%T8+gqcE;?UZoC5Kqt@R_)&DOrq^TKVY1q zujdzIWKp*J%?!UXKK-W3x7(m=3cS~UViC`258Whlzy?% zTD7x00ldqBo|}J+8NWFsfLP~odlZ1O>@0&D)eHLGlazZrV)^_hX~IlLlKpe3po=xs zr@mTaFHPBafJIXrvOBF_49?=s4M{kEZ2k+D+QRIfr&E}Ekm zch41u&&eEtixw=9t125w(j*^&q(o}SWOjC<*``B18Yp=9Ig%&!*t$L7#%u>tgq_o!1bCGufPZ^GS2^T{v1(?f`mAVp;lS3mX1NDZv&pcUB%GkG(M`-M}5eJB{SWeo{-dYgRgp9S4qP~7#b znF<6kfm*QMF_?Fy7~fh6Wot~Oc%OifUJ%beIfAt zpRT0fgkeB_z>iB{!}Xw@yLso(Y(f{i;cl_|6+mVU`GAr8Wzx$yW$k9+bWTC=Nai+X z(g2Szk6Rr~*g$^>NKFSZ5_}E(F2>-z*4Juwz6Cs)tM-GD#^FXt6i≤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

fGutGhNXWn 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 z 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

Yx@Tl3P+T`Q5{$o^i3Mx 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/dev/null 2>&1 + fi + pkgId=`echo "$appid" | cut -f1 -d"."` + /usr/bin/sqlite3 $PKGMGR_DB "delete from package_info where package=\"$pkgId\"" + /usr/bin/sqlite3 $PKGMGR_DB "delete from package_app_info where app_id=\"$appid\"" + /bin/rm -rf ${WIDGET_EXEC_PATH}${pkgId} + /bin/rm -rf ${WIDGET_PRELOAD_EXEC_PATH}${pkgId} + widget_desktop_file="${WIDGET_DESKTOP_PATH}${appid}.desktop"; + if [ -f ${widget_desktop_file} ]; then + /bin/rm -f $widget_desktop_file; + fi + widget_smack_rule="${SMACK_RULES_PATH}${pkgId}" + if [ -f ${widget_smack_rule} ]; then + /bin/rm -f $widget_smack_rule; + fi + done +else + echo "${WRT_DB} doesn't exist" +fi + +/usr/bin/wrt_commons_create_clean_db.sh + +#TODO: remove this when switched to wrt-plugins-installer completely +if [ -e ${PLUGINS_INSTALLATION_REQUIRED_PATH} ] && [ -d ${PLUGINS_INSTALLATION_REQUIRED_PATH} ] +then + /bin/touch ${PLUGINS_INSTALLATION_REQUIRED_PATH}${PLUGINS_INSTALLATION_REQUIRED} +fi + +#update plugins +if [ -x /usr/bin/wrt-installer ] +then + /usr/bin/wrt-installer -p +fi diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..82e583f --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# + +# Check minimum CMake version +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +# Project name +PROJECT(dpl-examples) + +# Set common compiler flags +ADD_DEFINITIONS("-Wall -Wextra -ansi -pedantic") + +# Add examples +ADD_SUBDIRECTORY(simple) +ADD_SUBDIRECTORY(rpc) +ADD_SUBDIRECTORY(fake_rpc) +ADD_SUBDIRECTORY(binary_queue) +ADD_SUBDIRECTORY(socket) +ADD_SUBDIRECTORY(tcpsock) +ADD_SUBDIRECTORY(timed_event) +ADD_SUBDIRECTORY(single_instance) +ADD_SUBDIRECTORY(crypto_hash) +ADD_SUBDIRECTORY(metronome) +ADD_SUBDIRECTORY(copy) diff --git a/examples/DESCRIPTION b/examples/DESCRIPTION new file mode 100644 index 0000000..db99a6d --- /dev/null +++ b/examples/DESCRIPTION @@ -0,0 +1,2 @@ +!!!options!!! stop +Example code diff --git a/examples/binary_queue/CMakeLists.txt b/examples/binary_queue/CMakeLists.txt new file mode 100644 index 0000000..5fb9fee --- /dev/null +++ b/examples/binary_queue/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(BINARY_QUEUE_SYS dpl-gtk REQUIRED) + +SET(BINARY_QUEUE_SOURCES + binary_queue.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${BINARY_QUEUE_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${BINARY_QUEUE_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(binary_queue ${BINARY_QUEUE_SOURCES}) +TARGET_LINK_LIBRARIES(binary_queue ${BINARY_QUEUE_SYS_LIBRARIES}) diff --git a/examples/binary_queue/binary_queue.cpp b/examples/binary_queue/binary_queue.cpp new file mode 100644 index 0000000..063b6af --- /dev/null +++ b/examples/binary_queue/binary_queue.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file binary_queue.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of binary queue example + */ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + DPL::BinaryQueue queue; + Assert(queue.Size() == 0); + + for (int i=0; i<10; ++i) + { + int value = 12345; + queue.AppendCopy(&value, sizeof(value)); + queue.AppendUnmanaged(malloc(100), 100); + } + + Assert(queue.Size() == 10 * sizeof(int) + 10 * 100); + + for (size_t i = 0; i < 10 * sizeof(int) + 10 * 100; ++i) + { + char buffer[1]; + queue.Flatten(buffer, 1); + + queue.FlattenConsume(NULL, 0); + queue.Flatten(NULL, 0); + queue.FlattenConsume(buffer, 1); + } + +// UNHANDLED_EXCEPTION_HANDLER_BEGIN +// { +// char a; +// queue.FlattenConsume(&a, sizeof(a)); +// } +// UNHANDLED_EXCEPTION_HANDLER_END + + return 0; +} diff --git a/examples/copy/CMakeLists.txt b/examples/copy/CMakeLists.txt new file mode 100644 index 0000000..ace88df --- /dev/null +++ b/examples/copy/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(COPY_SYS dpl-gtk REQUIRED) + +SET(COPY_SOURCES + copy.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${COPY_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${COPY_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(copy ${COPY_SOURCES}) +TARGET_LINK_LIBRARIES(copy ${COPY_SYS_LIBRARIES}) diff --git a/examples/copy/copy.cpp b/examples/copy/copy.cpp new file mode 100644 index 0000000..5fa9484 --- /dev/null +++ b/examples/copy/copy.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file copy.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of copy example + */ +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + if (argc != 3 && argc != 4) + { + std::cout << "Invalid parameters: copy [input_file] [output_file] [OPTIONAL: number_of_bytes]" << std::endl; + return -1; + } + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + DPL::FileInput input(argv[1]); + DPL::FileOutput output(argv[2]); + + if (argc == 3) + DPL::Copy(&input, &output); + else + DPL::Copy(&input, &output, static_cast(atoi(argv[3]))); + } + UNHANDLED_EXCEPTION_HANDLER_END + + return 0; +} diff --git a/examples/crypto_hash/CMakeLists.txt b/examples/crypto_hash/CMakeLists.txt new file mode 100644 index 0000000..e0b0598 --- /dev/null +++ b/examples/crypto_hash/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(CRYPTO_HASH_SYS dpl-efl REQUIRED) + +SET(CRYPTO_HASH_SOURCES + crypto_hash.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${CRYPTO_HASH_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${CRYPTO_HASH_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(crypto_hash ${CRYPTO_HASH_SOURCES}) +TARGET_LINK_LIBRARIES(crypto_hash ${CRYPTO_HASH_SYS_LIBRARIES}) diff --git a/examples/crypto_hash/crypto_hash.cpp b/examples/crypto_hash/crypto_hash.cpp new file mode 100644 index 0000000..791b971 --- /dev/null +++ b/examples/crypto_hash/crypto_hash.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file crypto_hash.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of crypto hash example + */ +#include +#include +#include +#include + +void help() +{ + std::cout << "Invalid parameters: crypto_hash [hash_function] [message]" << std::endl; + std::cout << "hash_function is one of following: MD2, MD4, MD5, SHA, SHA1, DSS, DSS1, ECDSA, SHA224, SHA256, SHA384, SHA512" << std::endl; +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + { + help(); + return 0; + } + + DPL::Crypto::Hash::Base *crypto; + std::string algorithm = argv[1]; + + if (algorithm == "MD2") + crypto = new DPL::Crypto::Hash::MD2(); + else if (algorithm == "MD4") + crypto = new DPL::Crypto::Hash::MD4(); + else if (algorithm == "MD5") + crypto = new DPL::Crypto::Hash::MD5(); + else if (algorithm == "SHA") + crypto = new DPL::Crypto::Hash::SHA(); + else if (algorithm == "SHA1") + crypto = new DPL::Crypto::Hash::SHA1(); + else if (algorithm == "DSS") + crypto = new DPL::Crypto::Hash::DSS(); + else if (algorithm == "DSS1") + crypto = new DPL::Crypto::Hash::DSS1(); + else if (algorithm == "ECDSA") + crypto = new DPL::Crypto::Hash::ECDSA(); + else if (algorithm == "SHA224") + crypto = new DPL::Crypto::Hash::SHA224(); + else if (algorithm == "SHA256") + crypto = new DPL::Crypto::Hash::SHA256(); + else if (algorithm == "SHA384") + crypto = new DPL::Crypto::Hash::SHA384(); + else if (algorithm == "SHA512") + crypto = new DPL::Crypto::Hash::SHA512(); + else + { + help(); + return 0; + } + + crypto->Append(argv[2]); + crypto->Finish(); + + std::cout << crypto->ToString() << std::endl; + + delete crypto; + + return 0; +} diff --git a/examples/dbus/client-example/CMakeLists.txt b/examples/dbus/client-example/CMakeLists.txt new file mode 100755 index 0000000..48add08 --- /dev/null +++ b/examples/dbus/client-example/CMakeLists.txt @@ -0,0 +1,24 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(client-example) + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(DEPS + dbus-1 + dpl-efl + dpl-dbus-efl + REQUIRED) + +SET(TARGET_NAME "client-example") + +SET(SRCS + client-example.cpp) + +INCLUDE_DIRECTORIES(${DEPS_INCLUDE_DIRS}) + +ADD_DEFINITIONS("-std=c++0x") +ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") + +ADD_EXECUTABLE(${TARGET_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${TARGET_NAME} ${DEPS_LIBRARIES}) + diff --git a/examples/dbus/client-example/client-example.cpp b/examples/dbus/client-example/client-example.cpp new file mode 100644 index 0000000..878febf --- /dev/null +++ b/examples/dbus/client-example/client-example.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file client-example.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Implementation for simple echo service DBus client. + */ +#include +#include +#include + +#include + +int main(int argc, char **argv) +{ + DPL::DBus::Client client("/path/to/object", + "org.tizen.EchoService", + "org.tizen.EchoInterface"); + std::string outstr; + client.Call("echo", "Samsung Rocks! Hello World Test!", &outstr); + std::cout << "Returned: " << outstr << std::endl; + exit(0); +} + diff --git a/examples/dbus/server-example/CMakeLists.txt b/examples/dbus/server-example/CMakeLists.txt new file mode 100755 index 0000000..4562355 --- /dev/null +++ b/examples/dbus/server-example/CMakeLists.txt @@ -0,0 +1,26 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(server-example) + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(DEPS + glib-2.0 + gio-2.0 + dpl-efl + dpl-dbus-efl + REQUIRED) + +SET(TARGET_NAME "server-example") + +SET(SRCS + server-example.cpp) + +INCLUDE_DIRECTORIES(${DEPS_INCLUDE_DIRS}) + +ADD_DEFINITIONS("-std=c++0x") +ADD_DEFINITIONS("-pedantic") +ADD_DEFINITIONS("-Wall") +ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") + +ADD_EXECUTABLE(${TARGET_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${TARGET_NAME} ${DEPS_LIBRARIES}) \ No newline at end of file diff --git a/examples/dbus/server-example/server-example.cpp b/examples/dbus/server-example/server-example.cpp new file mode 100644 index 0000000..84e665d --- /dev/null +++ b/examples/dbus/server-example/server-example.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::string xml = +"" +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +""; + +GMainLoop* g_loop = NULL; + +auto g_interfaces = DPL::DBus::Interface::fromXMLString(xml); + +class DBusDispatcher : public DPL::DBus::Dispatcher +{ +public: + void onMethodCall(GDBusConnection *connection, + const gchar *sender, + const gchar *objectPath, + const gchar *interfaceName, + const gchar *methodName, + GVariant *parameters, + GDBusMethodInvocation *invocation) + { + LogDebug("On method call: " << methodName); + + if (g_strcmp0(methodName, "echo") == 0) + { + const gchar* arg = NULL; + + g_variant_get(parameters, "(&s)", &arg); + LogDebug("Client said: " << arg); + + gchar* response = g_strdup_printf(arg); + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(s)", + response)); + g_free (response); + sleep(5); + } + else if (g_strcmp0(methodName, "quit") == 0) + { + g_main_loop_quit(g_loop); + } + } +}; + +class NewConnectionListener : + public DPL::EventListener +{ +protected: + void OnEventReceived(const DPL::DBus::ServerEvents::NewConnectionEvent& event) + { + m_connection = event.GetArg0(); + + auto quitInterface = g_interfaces.at(1); + quitInterface->setDispatcher(std::make_shared()); + m_quitObject = DBus::Object::create("/object/quit", quitInterface); + + m_connection->registerObject(m_quitObject); + } + +private: + DPL::DBus::ConnectionPtr m_connection; + DPL::DBus::ObjectPtr m_quitObject; +}; + +int main() +{ + g_type_init(); + + // --------------- echo + auto echoConnection = DPL::DBus::Connection::sessionBus(); + + auto echoInterface = g_interfaces.at(0); + echoInterface->setDispatcher(std::make_shared()); + + auto echoObject = DPL::DBus::Object::create("/object/echo", echoInterface); + + echoConnection->registerObject(echoObject); + + echoConnection->registerService("org.tizen.EchoService"); + + // --------------- quit + std::unique_ptr listener(new NewConnectionListener); + auto server = DPL::DBus::Server::create("unix:abstract=someaddr"); + server->AddListener(listener.get()); + server->start(); + + g_loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(g_loop); + g_main_loop_unref(g_loop); + + return 0; +} diff --git a/examples/fake_rpc/CMakeLists.txt b/examples/fake_rpc/CMakeLists.txt new file mode 100644 index 0000000..0778da7 --- /dev/null +++ b/examples/fake_rpc/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Pawel Sikorski (p.sikorski@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(FAKE_RPC_SYS dpl-efl REQUIRED) + +SET(FAKE_RPC_SOURCES + fake_rpc.cpp) + +ADD_DEFINITIONS("-D_DEBUG") +ADD_DEFINITIONS("-DDPL_LOGS_ENABLED") + +INCLUDE_DIRECTORIES(${FAKE_RPC_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${FAKE_RPC_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(fake_rpc ${FAKE_RPC_SOURCES}) +TARGET_LINK_LIBRARIES(fake_rpc ${FAKE_RPC_SYS_LIBRARIES}) diff --git a/examples/fake_rpc/fake_rpc.cpp b/examples/fake_rpc/fake_rpc.cpp new file mode 100644 index 0000000..bab1069 --- /dev/null +++ b/examples/fake_rpc/fake_rpc.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file rpc.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of RPC example + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// FLOW: +// 1st connection - UnixSockets +// 2nd connection - Fake +// client sends data via fake IPC +// server sends back this data via unix IPC. +// client compare sent and received data + +static const char *UNIX_RPC_NAME = "/tmp/unix_socket_rpc"; +static const char *FAKE_RPC_NAME = "/tmp/fake_rpc"; + +typedef DPL::AbstractRPCConnectionEvents::AsyncCallEvent AsyncCallEvent; +typedef DPL::AbstractRPCConnectionEvents::ConnectionClosedEvent + ConnectionClosedEvent; +typedef DPL::AbstractRPCConnectionEvents::ConnectionBrokenEvent + ConnectionBrokenEvent; +typedef DPL::AbstractRPCConnectorEvents::ConnectionEstablishedEvent + ConnectionEstablishedEvent; + +class MyThread + : public DPL::Thread, + private DPL::EventListener, + private DPL::EventListener +{ +private: + DPL::UnixSocketRPCClient m_rpcUnixClient; + DPL::FakeRpcClient m_rpcFakeClient; + int m_connections; + int m_sentData; + int m_receivedData; + + std::unique_ptr m_rpcUnixConnection; + std::unique_ptr m_rpcFakeConnection; + + virtual void OnEventReceived(const AsyncCallEvent &event) + { + LogDebug("CLIENT: AsyncCallEvent received"); + + event.GetArg0().ConsumeArg(m_receivedData); + LogDebug("CLIENT: Result from server: " << m_receivedData); + + if (m_receivedData != m_sentData) + LogError("Wrong data Received!"); + } + + virtual void OnEventReceived(const ConnectionEstablishedEvent &event) + { + if (dynamic_cast(event.GetArg1())){ + ++m_connections; + LogDebug("CLIENT: Acquiring new fake connection"); + m_rpcFakeConnection.reset(event.GetArg1()); + //this is not used on this side +// m_rpcFakeConnection->DPL::EventSupport::AddListener(this); + } + else{ + ++m_connections; + LogDebug("CLIENT: Acquiring new unix connection"); + m_rpcUnixConnection.reset(event.GetArg1()); + m_rpcUnixConnection->DPL::EventSupport::AddListener(this); + } + if(m_connections == 2){ + m_sentData = 1213; + // Emit RPC function call + DPL::RPCFunction proc; + proc.AppendArg(m_sentData); + LogDebug("CLIENT: Calling RPC function"); + m_rpcFakeConnection->AsyncCall(proc); + } + } + +public: + MyThread() : + m_rpcUnixClient(NULL), + m_rpcFakeClient(NULL), + m_connections(0), + m_sentData(0), + m_receivedData(0) + {} + + virtual ~MyThread() + { + // Always quit thread + Quit(); + } + + virtual int ThreadEntry() + { + m_connections = 0; + // Attach RPC listeners + LogDebug("CLIENT: Attaching connection established event"); + m_rpcUnixClient.DPL::EventSupport::AddListener(this); + m_rpcFakeClient.DPL::EventSupport::AddListener(this); + + // Open connection to server + LogDebug("CLIENT: Opening connection to RPC"); + m_rpcUnixClient.Open(UNIX_RPC_NAME); + m_rpcFakeClient.Open(FAKE_RPC_NAME); + + // Start message loop + LogDebug("CLIENT: Starting thread event loop"); + int ret = Exec(); + + if (m_rpcUnixConnection.get()){ + LogDebug("CLIENT: Removing Unix connection"); + m_rpcUnixConnection->DPL::EventSupport::RemoveListener(this); + m_rpcUnixConnection.reset(); + } + + LogDebug("CLIENT: Closing"); + + if (m_rpcFakeConnection.get()){ + LogDebug("CLIENT: Removing Fake connection"); + //this is not used on this side +// m_rpcFakeConnection->DPL::EventSupport::RemoveListener(this); + m_rpcFakeConnection.reset(); + } + + // Detach RPC client listener + LogDebug("CLIENT: Detaching connection established event"); + m_rpcUnixClient.DPL::EventSupport::RemoveListener(this); + m_rpcFakeClient.DPL::EventSupport::RemoveListener(this); + + // Close RPC + LogDebug("CLIENT: Closing RPC client"); + m_rpcUnixClient.CloseAll(); + m_rpcFakeClient.Close();//not needed + + // Done + return ret; + } +}; + +DECLARE_GENERIC_EVENT_0(QuitEvent) +DECLARE_GENERIC_EVENT_0(CloseThreadEvent) + +class MyApplication + : public DPL::Application, + private DPL::Controller::Type>, + private DPL::EventListener, + private DPL::EventListener +{ +private: + DPL::UnixSocketRPCServer m_rpcUnixServer; + DPL::FakeRpcServer m_rpcFakeServer; + + std::unique_ptr m_rpcUnixConnection; + std::unique_ptr m_rpcFakeConnection; + + MyThread m_thread; + + // Quit application event occurred + virtual void OnEventReceived(const QuitEvent &/*event*/){ + // Close RPC now + LogDebug("SERVER: Closing RPC connection..."); + + // Detach RPC connection listeners + if (m_rpcUnixConnection.get()) { + //this is not used on this side +// m_rpcUnixConnection->DPL::EventSupport::RemoveListener(this); + m_rpcUnixConnection.reset(); + } + + if (m_rpcFakeConnection.get()) { + m_rpcFakeConnection->DPL::EventSupport::RemoveListener(this); + m_rpcFakeConnection.reset(); + } + + LogDebug("SERVER: Closing Server"); + m_rpcUnixServer.CloseAll(); + m_rpcFakeServer.CloseAll();//not needed + m_rpcUnixServer.DPL::EventSupport::RemoveListener(this); + m_rpcFakeServer.DPL::EventSupport::RemoveListener(this); + + LogDebug("SERVER: Server closed"); + + Quit(); + } + + virtual void OnEventReceived(const CloseThreadEvent &/*event*/){ + m_thread.Quit(); + } + + virtual void OnEventReceived(const AsyncCallEvent &event) + { + LogDebug("SERVER: AsyncCallEvent received"); + + int value; + event.GetArg0().ConsumeArg(value); + LogDebug("SERVER: Result from client: " << value); + + // send back data to client (via fake) + // Emit RPC function call + DPL::RPCFunction proc; + proc.AppendArg(value); + LogDebug("SERVER: Calling RPC function"); + m_rpcUnixConnection->AsyncCall(proc); + } + + virtual void OnEventReceived(const ConnectionEstablishedEvent &event) + { + // Save connection pointer + if (dynamic_cast(event.GetArg1())){ + LogDebug("SERVER: Acquiring Fake RPC connection"); + m_rpcFakeConnection.reset(event.GetArg1()); + m_rpcFakeConnection->DPL::EventSupport::AddListener(this); + } + else{ + LogDebug("SERVER: Acquiring Unix RPC connection"); + m_rpcUnixConnection.reset(event.GetArg1()); + //this is not used on this side +// m_rpcUnixConnection->DPL::EventSupport::AddListener(this); + } + } + +public: + MyApplication(int argc, char **argv) + : Application(argc, argv, "rpc") + { + // Attach RPC server listeners + LogDebug("SERVER: Attaching connection established event"); + m_rpcUnixServer.DPL::EventSupport::AddListener(this); + m_rpcFakeServer.DPL::EventSupport::AddListener(this); + + // Self touch + LogDebug("SERVER: Touching controller"); + Touch(); + + // Open RPC server + LogDebug("SERVER: Opening server RPC"); + m_rpcUnixServer.Open(UNIX_RPC_NAME); + m_rpcFakeServer.Open(FAKE_RPC_NAME); + + // Run RPC client in thread + LogDebug("SERVER: Starting RPC client thread"); + m_thread.Run(); + + // Quit application automatically in few seconds + LogDebug("SERVER: Sending control timed events"); + DPL::ControllerEventHandler::PostTimedEvent(CloseThreadEvent(), 2); + DPL::ControllerEventHandler::PostTimedEvent(QuitEvent(), 3); + } + + virtual ~MyApplication() + { + // Quit thread + LogDebug("SERVER: Quitting thread"); + } +}; + +int main(int argc, char *argv[]) +{ + LogDebug("Starting"); + MyApplication app(argc, argv); + return app.Exec(); +} diff --git a/examples/metronome/CMakeLists.txt b/examples/metronome/CMakeLists.txt new file mode 100644 index 0000000..b5d1017 --- /dev/null +++ b/examples/metronome/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(METRONOME_SYS dpl-efl REQUIRED) + +SET(METRONOME_CLIENT_SOURCES + metronome_client.cpp) + +SET(METRONOME_SERVER_SOURCES + metronome_server.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${METRONOME_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${METRONOME_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(metronome_client ${METRONOME_CLIENT_SOURCES}) +TARGET_LINK_LIBRARIES(metronome_client ${METRONOME_SYS_LIBRARIES}) + +ADD_EXECUTABLE(metronome_server ${METRONOME_SERVER_SOURCES}) +TARGET_LINK_LIBRARIES(metronome_server ${METRONOME_SYS_LIBRARIES}) diff --git a/examples/metronome/metronome_client.cpp b/examples/metronome/metronome_client.cpp new file mode 100644 index 0000000..1fca0df --- /dev/null +++ b/examples/metronome/metronome_client.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file metronome_client.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of metronome client example + */ +#include +#include +#include +#include +#include + +class MetronomeClientApplication + : public DPL::Application, + private DPL::EventListener, + private DPL::EventListener, + private DPL::EventListener, + private DPL::EventListener +{ +private: + DPL::TcpSocketRPCClient m_rpcClient; + std::unique_ptr m_rpcConnection; + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::AsyncCallEvent &event) + { + (void)event; + + // Heart beat + LogDebug("* Got metronome signal *"); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionClosedEvent &event) + { + (void)event; + + LogDebug("Connection closed"); + + // Must quit + Quit(); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionBrokenEvent &event) + { + (void)event; + + LogDebug("Connection broken"); + + // Must quit + Quit(); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectorEvents::ConnectionEstablishedEvent &event) + { + // Save connection pointer + LogDebug("Connected to metronome server"); + m_rpcConnection.reset(event.GetArg1()); + + // Attach event listeners + m_rpcConnection->DPL::EventSupport::AddListener(this); + m_rpcConnection->DPL::EventSupport::AddListener(this); + m_rpcConnection->DPL::EventSupport::AddListener(this); + } + +public: + MetronomeClientApplication(int argc, char **argv) + : Application(argc, argv, "rpc") + { + // Attach RPC server listeners + m_rpcClient.DPL::EventSupport::AddListener(this); + + // Open RPC server + m_rpcClient.Open("127.0.0.1", 12345); + + // Started + LogDebug("Metronome client started"); + } + + virtual ~MetronomeClientApplication() + { + // Delete all RPC connections + if (m_rpcConnection.get()) + { + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + m_rpcConnection.reset(); + } + + // Close RPC server + m_rpcClient.CloseAll(); + + // Detach RPC server listener + m_rpcClient.DPL::EventSupport::RemoveListener(this); + } +}; + +int main(int argc, char *argv[]) +{ + return MetronomeClientApplication(argc, argv).Exec(); +} diff --git a/examples/metronome/metronome_server.cpp b/examples/metronome/metronome_server.cpp new file mode 100644 index 0000000..cc0ad0a --- /dev/null +++ b/examples/metronome/metronome_server.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file metronome_server.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of metronome server example + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Metronome signal event +DECLARE_GENERIC_EVENT_0(SignalEvent) +DECLARE_GENERIC_EVENT_1(DeleteConnectionEvent, DPL::AbstractRPCConnection *) + +// Heart beat interval +const double HEART_BEAT_INTERVAL = 1.0; // seconds + +class MetronomeServerApplication + : public DPL::Application, + private DPL::Controller::Type>, + private DPL::EventListener, + private DPL::EventListener, + private DPL::EventListener +{ +private: + DPL::TcpSocketRPCServer m_rpcServer; + + typedef std::list ConnectionList; + ConnectionList m_connections; + + // Matronome signal received + virtual void OnEventReceived(const SignalEvent &event) + { + (void)event; + + // Signal all conection about heart beat + DPL::RPCFunction proc; + proc.AppendArg((int)0); + + for (ConnectionList::iterator it = m_connections.begin(); it != m_connections.end(); ++it) + (*it)->AsyncCall(proc); + + // Continue to emot heart beats + DPL::ControllerEventHandler::PostTimedEvent(SignalEvent(), HEART_BEAT_INTERVAL); + } + + virtual void OnEventReceived(const DeleteConnectionEvent &event) + { + delete event.GetArg0(); + } + + void RemoveConnection(DPL::AbstractRPCConnection *connection) + { + // Find connection + ConnectionList::iterator it = std::find(m_connections.begin(), m_connections.end(), connection); + Assert(it != m_connections.end()); + + // Erase connection + m_connections.erase(it); + + // Detach RPC connection listeners + connection->DPL::EventSupport::RemoveListener(this); + connection->DPL::EventSupport::RemoveListener(this); + + // Delete connection + DPL::ControllerEventHandler::PostEvent(DeleteConnectionEvent(connection)); + } + + void AddConnection(DPL::AbstractRPCConnection *connection) + { + // Add connection + m_connections.push_back(connection); + + // Attach event listeners + connection->DPL::EventSupport::AddListener(this); + connection->DPL::EventSupport::AddListener(this); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionClosedEvent &event) + { + (void)event; + + LogDebug("Connection closed"); + + // Remove connection from list + RemoveConnection(static_cast(event.GetSender())); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionBrokenEvent &event) + { + (void)event; + + LogDebug("Connection broken"); + + // Remove connection from list + RemoveConnection(static_cast(event.GetSender())); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectorEvents::ConnectionEstablishedEvent &event) + { + // Save connection pointer + LogDebug("New connection"); + + // Add nre connection to list + AddConnection(event.GetArg1()); + } + +public: + MetronomeServerApplication(int argc, char **argv) + : Application(argc, argv, "rpc") + { + // Attach RPC server listeners + m_rpcServer.DPL::EventSupport::AddListener(this); + + // Inherit calling context + Touch(); + + // Open RPC server + m_rpcServer.Open(12345); + + // Start heart beat + DPL::ControllerEventHandler::PostTimedEvent(SignalEvent(), HEART_BEAT_INTERVAL); + + // Started + LogDebug("Metronome server started"); + } + + virtual ~MetronomeServerApplication() + { + // Delete all RPC connections + while (!m_connections.empty()) + RemoveConnection(m_connections.front()); + + // Close RPC server + m_rpcServer.CloseAll(); + + // Detach RPC server listener + m_rpcServer.DPL::EventSupport::RemoveListener(this); + } +}; + +int main(int argc, char *argv[]) +{ + return MetronomeServerApplication(argc, argv).Exec(); +} diff --git a/examples/rpc/CMakeLists.txt b/examples/rpc/CMakeLists.txt new file mode 100644 index 0000000..d9c7d57 --- /dev/null +++ b/examples/rpc/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(RPC_SYS dpl-efl REQUIRED) + +SET(RPC_SOURCES + rpc.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${RPC_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${RPC_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(rpc ${RPC_SOURCES}) +TARGET_LINK_LIBRARIES(rpc ${RPC_SYS_LIBRARIES}) diff --git a/examples/rpc/rpc.cpp b/examples/rpc/rpc.cpp new file mode 100644 index 0000000..6991edb --- /dev/null +++ b/examples/rpc/rpc.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file rpc.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of RPC example + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *RPC_NAME = "/tmp/unix_socket_rpc"; + +class MyThread + : public DPL::Thread, + private DPL::EventListener, + private DPL::EventListener, + private DPL::EventListener, + private DPL::EventListener +{ +private: + DPL::UnixSocketRPCClient m_rpcClient; + std::unique_ptr m_rpcConnection; + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::AsyncCallEvent &event) + { + (void)event; + + LogDebug("CLIENT: AsyncCallEvent received"); + + int value; + event.GetArg0().ConsumeArg(value); + LogDebug("CLIENT: Result from server: " << value); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionClosedEvent &event) + { + (void)event; + LogDebug("CLIENT: ConnectionClosedEvent received"); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionBrokenEvent &event) + { + (void)event; + LogDebug("CLIENT: ConnectionBrokenEvent received"); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectorEvents::ConnectionEstablishedEvent &event) + { + // Save connection pointer + LogDebug("CLIENT: Acquiring new connection"); + m_rpcConnection.reset(event.GetArg1()); + + // Attach listener to new connection + LogDebug("CLIENT: Attaching connection event listeners"); + m_rpcConnection->DPL::EventSupport::AddListener(this); + m_rpcConnection->DPL::EventSupport::AddListener(this); + m_rpcConnection->DPL::EventSupport::AddListener(this); + + LogDebug("CLIENT: Connection established"); + + // Emit RPC function call + DPL::RPCFunction proc; + proc.AppendArg((int)1111); + LogDebug("CLIENT: Calling RPC function"); + m_rpcConnection->AsyncCall(proc); + } + +public: + virtual ~MyThread() + { + // Always quit thread + Quit(); + } + + virtual int ThreadEntry() + { + // Attach RPC listeners + LogDebug("CLIENT: Attaching connection established event"); + m_rpcClient.DPL::EventSupport::AddListener(this); + + // Open connection to server + LogDebug("CLIENT: Opening connection to RPC"); + m_rpcClient.Open(RPC_NAME); + + // Start message loop + LogDebug("CLIENT: Starting thread event loop"); + int ret = Exec(); + + // Detach RPC listeners + if (m_rpcConnection.get()) + { + LogDebug("CLIENT: Detaching RPC connection events"); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + + LogDebug("CLIENT: Resetting connection"); + m_rpcConnection.reset(); + } + + // Detach RPC client listener + LogDebug("CLIENT: Detaching connection established event"); + m_rpcClient.DPL::EventSupport::RemoveListener(this); + + // Close RPC + LogDebug("CLIENT: Closing RPC client"); + m_rpcClient.CloseAll(); + + // Done + return ret; + } +}; + +DECLARE_GENERIC_EVENT_0(QuitEvent) +DECLARE_GENERIC_EVENT_0(CloseThreadEvent) + +class MyApplication + : public DPL::Application, + private DPL::Controller::Type>, + private DPL::EventListener, + private DPL::EventListener, + private DPL::EventListener, + private DPL::EventListener +{ +private: + DPL::UnixSocketRPCServer m_rpcServer; + std::unique_ptr m_rpcConnection; + + MyThread m_thread; + + // Quit application event occurred + virtual void OnEventReceived(const QuitEvent &event) + { + (void)event; + Quit(); + } + + virtual void OnEventReceived(const CloseThreadEvent &event) + { + (void)event; + m_thread.Quit(); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::AsyncCallEvent &event) + { + (void)event; + + LogDebug("SERVER: AsyncCallEvent received"); + + int value; + event.GetArg0().ConsumeArg(value); + LogDebug("SERVER: Result from client: " << value); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionClosedEvent &event) + { + (void)event; + + LogDebug("SERVER: ConnectionClosedEvent received"); + + // Close RPC now + LogDebug("SERVER: Closing RPC connection on event..."); + + // Detach RPC connection listeners + if (m_rpcConnection.get()) + { + LogDebug("SERVER: Detaching connection events"); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + m_rpcConnection->DPL::EventSupport::RemoveListener(this); + } + LogDebug("SERVER: RPC connection closed"); + + LogDebug("SERVER: Closing RPC on event..."); + m_rpcServer.CloseAll(); + LogDebug("SERVER: RPC closed"); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectionEvents::ConnectionBrokenEvent &event) + { + (void)event; + LogDebug("SERVER: ConnectionBrokenEvent received"); + } + + virtual void OnEventReceived(const DPL::AbstractRPCConnectorEvents::ConnectionEstablishedEvent &event) + { + // Save connection pointer + LogDebug("SERVER: Acquiring RPC connection"); + m_rpcConnection.reset(event.GetArg1()); + + // Attach event listeners + LogDebug("SERVER: Attaching connection listeners"); + m_rpcConnection->DPL::EventSupport::AddListener(this); + m_rpcConnection->DPL::EventSupport::AddListener(this); + m_rpcConnection->DPL::EventSupport::AddListener(this); + + LogDebug("SERVER: Connection established"); + + // Emit RPC function call + DPL::RPCFunction proc; + proc.AppendArg((int)2222); + LogDebug("SERVER: Calling RPC function"); + m_rpcConnection->AsyncCall(proc); + } + +public: + MyApplication(int argc, char **argv) + : Application(argc, argv, "rpc") + { + // Attach RPC server listeners + LogDebug("SERVER: Attaching connection established event"); + m_rpcServer.DPL::EventSupport::AddListener(this); + + // Self touch + LogDebug("SERVER: Touching controller"); + Touch(); + + // Open RPC server + LogDebug("SERVER: Opening server RPC"); + m_rpcServer.Open(RPC_NAME); + + // Run RPC client in thread + LogDebug("SERVER: Starting RPC client thread"); + m_thread.Run(); + + // Quit application automatically in few seconds + LogDebug("SERVER: Sending control timed events"); + DPL::ControllerEventHandler::PostTimedEvent(CloseThreadEvent(), 2); + DPL::ControllerEventHandler::PostTimedEvent(QuitEvent(), 3); + } + + virtual ~MyApplication() + { + // Quit thread + LogDebug("SERVER: Quitting thread"); + m_thread.Quit(); + + // Close RPC server + LogDebug("SERVER: Closing RPC server"); + m_rpcServer.CloseAll(); + + // Detach RPC server listener + m_rpcServer.DPL::EventSupport::RemoveListener(this); + } +}; + +int main(int argc, char *argv[]) +{ + LogDebug("Starting"); + MyApplication app(argc, argv); + return app.Exec(); +} diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt new file mode 100644 index 0000000..42020ec --- /dev/null +++ b/examples/simple/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SIMPLE_SYS dpl-gtk REQUIRED) + +SET(SIMPLE_SOURCES + simple.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${SIMPLE_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${SIMPLE_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(simple ${SIMPLE_SOURCES}) +TARGET_LINK_LIBRARIES(simple ${SIMPLE_SYS_LIBRARIES}) diff --git a/examples/simple/simple.cpp b/examples/simple/simple.cpp new file mode 100644 index 0000000..2ed9fab --- /dev/null +++ b/examples/simple/simple.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file simple.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of simple example + */ +#include +#include + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + LogDebug("Hello world!"); + return 0; +} + diff --git a/examples/single_instance/CMakeLists.txt b/examples/single_instance/CMakeLists.txt new file mode 100644 index 0000000..3c29cc6 --- /dev/null +++ b/examples/single_instance/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(RPC_SYS dpl-efl REQUIRED) + +SET(RPC_SOURCES + single_instance.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${RPC_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${RPC_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(single_instance ${RPC_SOURCES}) +TARGET_LINK_LIBRARIES(single_instance ${RPC_SYS_LIBRARIES}) diff --git a/examples/single_instance/single_instance.cpp b/examples/single_instance/single_instance.cpp new file mode 100644 index 0000000..038594b --- /dev/null +++ b/examples/single_instance/single_instance.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file single_instance.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of single instance example + */ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + std::cout << "Specify instance name!" << std::endl; + return 0; + } + + DPL::SingleInstance singleInstance; + + if (singleInstance.TryLock(argv[1])) + { + std::cout << "Succedded to lock single instance." << std::endl << "Press ENTER to release lock..." << std::endl; + + // Wait for any key + getchar(); + + // Release gathered lock + singleInstance.Release(); + + // Done + return 0; + } + + std::cout << "Cannot retrieve single instance lock." << std::endl + << "Another application has locked single instance." << std::endl + << "Will now exit." << std::endl; + + // Done + return 0; +} diff --git a/examples/socket/CMakeLists.txt b/examples/socket/CMakeLists.txt new file mode 100644 index 0000000..9fe5009 --- /dev/null +++ b/examples/socket/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(SOCKET_SYS dpl-efl REQUIRED) + +SET(SOCKET_SOURCES + socket.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${SOCKET_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${SOCKET_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(socket ${SOCKET_SOURCES}) +TARGET_LINK_LIBRARIES(socket ${SOCKET_SYS_LIBRARIES}) diff --git a/examples/socket/socket.cpp b/examples/socket/socket.cpp new file mode 100644 index 0000000..fc42632 --- /dev/null +++ b/examples/socket/socket.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file socket.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of socket example + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace // anonymous +{ +static const char *SOCKET_NAME = "/tmp/unix_sock"; +} // namespace anonymous + +class MyThread + : public DPL::Thread, + private DPL::EventListener +{ +private: + DPL::UnixSocket m_socket; + + // Socket accept event + virtual void OnEventReceived(const DPL::AbstractSocketEvents::AcceptEvent &event) + { + (void)event; + LogDebug("Accept event occurred"); + + DPL::UnixSocket *client = static_cast(m_socket.Accept()); + + LogDebug("Accepted client remote address: " << client->GetRemoteAddress().ToString()); + LogDebug("Accepted client local address: " << client->GetLocalAddress().ToString()); + + delete client; + } + +public: + virtual ~MyThread() + { + // Quit thread + Quit(); + } + + virtual int ThreadEntry() + { + // Add listeners + m_socket.DPL::EventSupport::AddListener(this); + + // Create server + LogDebug("Starting server..."); + + m_socket.Bind(DPL::Address(SOCKET_NAME)); + m_socket.Listen(5); + + LogDebug("Server started"); + + LogDebug("Server local address: " << m_socket.GetLocalAddress().ToString()); + + int result = Exec(); + + // Remove listeners + m_socket.DPL::EventSupport::RemoveListener(this); + + // Must close socket in same context + m_socket.Close(); + + return result; + } +}; + +DECLARE_GENERIC_EVENT_0(QuitEvent) + +class MyApplication + : public DPL::Application, + public DPL::Controller::Type>, + private DPL::EventListener +{ +private: + MyThread thread; + DPL::UnixSocket sock; + + // Quit application event occurred + virtual void OnEventReceived(const QuitEvent &event) + { + (void)event; + Quit(); + } + + // Socket connected event + virtual void OnEventReceived(const DPL::AbstractSocketEvents::ConnectedEvent &event) + { + (void)event; + LogDebug("Connected event occurred"); + } + +public: + MyApplication(int argc, char **argv) + : Application(argc, argv, "example_socket_application") + { + // Add listeners + sock.DPL::EventSupport::AddListener(this); + + // Touch self controller + Touch(); + + // Start threaded server + LogDebug("Running threaded server"); + + // Run server in thread + thread.Run(); + + LogDebug("Waiting for server to start..."); + sleep(1); + + // Connect to server + sock.Connect(DPL::Address(SOCKET_NAME)); + + // Quit application automatically in few seconds + DPL::ControllerEventHandler::PostTimedEvent(QuitEvent(), 2); + } + + virtual ~MyApplication() + { + // Remove listeners + sock.DPL::EventSupport::RemoveListener(this); + } +}; + +int main(int argc, char *argv[]) +{ + MyApplication app(argc, argv); + return app.Exec(); +} diff --git a/examples/tcpsock/CMakeLists.txt b/examples/tcpsock/CMakeLists.txt new file mode 100644 index 0000000..a6550fc --- /dev/null +++ b/examples/tcpsock/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(TCPSOCK_SYS dpl-efl REQUIRED) + +SET(TCPSOCK_SOURCES + tcpsock.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${TCPSOCK_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${TCPSOCK_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(tcpsock ${TCPSOCK_SOURCES}) +TARGET_LINK_LIBRARIES(tcpsock ${TCPSOCK_SYS_LIBRARIES}) diff --git a/examples/tcpsock/tcpsock.cpp b/examples/tcpsock/tcpsock.cpp new file mode 100644 index 0000000..57141ca --- /dev/null +++ b/examples/tcpsock/tcpsock.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file tcpsock.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of tcpsock example + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class MyApplication + : public DPL::Application, + private DPL::EventListener, + private DPL::EventListener +{ +private: + DPL::TcpSocket m_socket; + + virtual void OnEventReceived(const DPL::AbstractSocketEvents::ConnectedEvent &event) + { + (void)event; + LogDebug("Connected!"); + + // Send request + DPL::BinaryQueue data; + const char *query = "GET /wiki/Main_Page HTTP/1.1\nHost: en.wikipedia.org\n\n"; + data.AppendCopy(query, strlen(query) + 1); + m_socket.Write(data, data.Size()); + } + + virtual void OnEventReceived(const DPL::AbstractSocketEvents::ReadEvent &event) + { + (void)event; + LogDebug("Read!"); + + DPL::BinaryQueueAutoPtr data = m_socket.Read(100); // Bad: DLOG cannot log more than about 450 bytes... + + Assert(data.get() != NULL); + + if (data->Empty()) + { + LogDebug("Connection closed!"); + m_socket.Close(); + + // Done + Quit(); + return; + } + + // Show data + DPL::ScopedArray text(new char[data->Size()]); + data->Flatten(text.Get(), data->Size()); + + LogPedantic("READ: \n--------------------------------------------------------\n" + << std::string(text.Get(), text.Get() + data->Size()) << + "\n--------------------------------------------------------"); + } + +public: + MyApplication(int argc, char **argv) + : Application(argc, argv, "tcpsock") + { + LogDebug("CTOR!"); + + // Add listeners + m_socket.DPL::EventSupport::AddListener(this); + m_socket.DPL::EventSupport::AddListener(this); + + // Connect + m_socket.Open(); + LogDebug("Connecting..."); + m_socket.Connect(DPL::Address("en.wikipedia.org", 80)); + } + + virtual ~MyApplication() + { + LogDebug("DTOR!"); + + // Remove listeners + m_socket.DPL::EventSupport::RemoveListener(this); + m_socket.DPL::EventSupport::RemoveListener(this); + } +}; + +int main(int argc, char *argv[]) +{ + MyApplication app(argc, argv); + return app.Exec(); +} diff --git a/examples/timed_event/CMakeLists.txt b/examples/timed_event/CMakeLists.txt new file mode 100644 index 0000000..cb60fb0 --- /dev/null +++ b/examples/timed_event/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) +# @version 1.0 +# @brief +# +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(RPC_SYS dpl-efl REQUIRED) + +SET(RPC_SOURCES + timed_event.cpp) + +ADD_DEFINITIONS("-D_DEBUG") + +INCLUDE_DIRECTORIES(${RPC_SYS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${RPC_SYS_LIBRARY_DIRS}) + +ADD_EXECUTABLE(timed_event ${RPC_SOURCES}) +TARGET_LINK_LIBRARIES(timed_event ${RPC_SYS_LIBRARIES}) diff --git a/examples/timed_event/timed_event.cpp b/examples/timed_event/timed_event.cpp new file mode 100644 index 0000000..f3d8e80 --- /dev/null +++ b/examples/timed_event/timed_event.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file timed_event.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of timed event example + */ +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GENERIC_EVENT_0(FirstEvent) +DECLARE_GENERIC_EVENT_0(SecondEvent) + +class ControllerInThread + : public DPL::Controller::Type> +{ +protected: + virtual void OnEventReceived(const FirstEvent &event) + { + (void)event; + LogDebug("First event occurred"); + } + + virtual void OnEventReceived(const SecondEvent &event) + { + (void)event; + LogDebug("Second event occurred"); + } +}; + +DECLARE_GENERIC_EVENT_0(QuitEvent) + +class MyApplication + : public DPL::Application, + private DPL::Controller::Type> +{ +private: + DPL::Thread m_thread; + ControllerInThread m_controllerInThread; + + // Quit application event occurred + virtual void OnEventReceived(const QuitEvent &event) + { + (void)event; + Quit(); + } + +public: + MyApplication(int argc, char **argv) + : Application(argc, argv, "timed_event", false) + { + // Touch + Touch(); + m_controllerInThread.Touch(); + + // Run thread + m_thread.Run(); + m_controllerInThread.SwitchToThread(&m_thread); + + // Emit thread timed events + m_controllerInThread.DPL::ControllerEventHandler::PostTimedEvent(SecondEvent(), 3); + m_controllerInThread.DPL::ControllerEventHandler::PostTimedEvent(FirstEvent(), 2); + + // Emit framework timed quit event + DPL::ControllerEventHandler::PostTimedEvent(QuitEvent(), 5); + } + + virtual ~MyApplication() + { + m_controllerInThread.SwitchToThread(NULL); + + // Quit thread + m_thread.Quit(); + } +}; + +int main(int argc, char *argv[]) +{ + MyApplication app(argc, argv); + return app.Exec(); +} diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt new file mode 100644 index 0000000..e3038e1 --- /dev/null +++ b/modules/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +INCLUDE(core/config.cmake) +INCLUDE(dbus/config.cmake) +INCLUDE(db/config.cmake) +INCLUDE(event/config.cmake) +INCLUDE(socket/config.cmake) +INCLUDE(rpc/config.cmake) +INCLUDE(test/config.cmake) +INCLUDE(log/config.cmake) +ADD_SUBDIRECTORY(widget_dao) +ADD_SUBDIRECTORY(widget_interface_dao) +ADD_SUBDIRECTORY(security_origin_dao) +ADD_SUBDIRECTORY(custom_handler_dao) +ADD_SUBDIRECTORY(certificate_dao) +ADD_SUBDIRECTORY(i18n) +INCLUDE(utils/config.cmake) +INCLUDE(localization/config.cmake) +INCLUDE(support/config.cmake) diff --git a/modules/certificate_dao/CMakeLists.txt b/modules/certificate_dao/CMakeLists.txt new file mode 100755 index 0000000..60d076c --- /dev/null +++ b/modules/certificate_dao/CMakeLists.txt @@ -0,0 +1,58 @@ +SET(TARGET_CERTIFICATE_DAO_DB "Sqlite3DbCertificate") + +ADD_CUSTOM_COMMAND( OUTPUT .certificate.db + COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/.certificate.db + COMMAND gcc -Wall -I${PROJECT_SOURCE_DIR}/modules/db/include -I${PROJECT_SOURCE_DIR}/modules/certificate_dao/orm -E ${PROJECT_SOURCE_DIR}/modules/certificate_dao/orm/certificate_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_BINARY_DIR}/certificate_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_BINARY_DIR}/.certificate.db ".read ${CMAKE_CURRENT_BINARY_DIR}/certificate_db.sql" || rm -f ${CMAKE_CURRENT_BINARY_DIR}/.certificate.db + DEPENDS ${PROJECT_SOURCE_DIR}/modules/certificate_dao/orm/certificate_db_sql_generator.h ${PROJECT_SOURCE_DIR}/modules/certificate_dao/orm/certificate_db + ) + +ADD_CUSTOM_COMMAND( OUTPUT .certificate.db-journal + COMMAND touch + ARGS ${CMAKE_CURRENT_BINARY_DIR}/.certificate.db-journal + ) + +ADD_CUSTOM_TARGET(${TARGET_CERTIFICATE_DAO_DB} ALL DEPENDS .certificate.db .certificate.db-journal) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/certificate_db.sql DESTINATION share/wrt-engine/) + +############################################################################### + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(CERTIFICATE_DAO_DEPS + glib-2.0 + dlog + REQUIRED) + +SET(CERTIFICATE_DAO_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/modules/certificate_dao/include + ${PROJECT_SOURCE_DIR}/modules/certificate_dao/orm + ${PROJECT_SOURCE_DIR}/modules/core/include + ${PROJECT_SOURCE_DIR}/modules/db/include + ${PROJECT_SOURCE_DIR}/modules/log/include + ${PROJECT_SOURCE_DIR}/modules/widget_dao/include +) + +SET(CERTIFICATE_DAO_SOURCES + dao/certificate_dao_types.cpp + dao/certificate_dao.cpp + dao/certificate_database.cpp +) + +INCLUDE_DIRECTORIES(SYSTEM ${CERTIFICATE_DAO_DEPS_INCLUDE_DIRS} ) +INCLUDE_DIRECTORIES(${CERTIFICATE_DAO_INCLUDE_DIRS}) + +ADD_LIBRARY(${TARGET_CERTIFICATE_DAO_LIB} SHARED ${CERTIFICATE_DAO_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_CERTIFICATE_DAO_LIB} PROPERTIES SOVERSION ${API_VERSION} VERSION ${VERSION}) +TARGET_LINK_LIBRARIES(${TARGET_CERTIFICATE_DAO_LIB} ${TARGET_DPL_EFL} ${TARGET_DPL_DB_EFL} ${TARGET_WRT_DAP_RO_LIB} ${CERTIFICATE_DAO_DEPS_LIBRARIES}) +ADD_DEPENDENCIES(${TARGET_CERTIFICATE_DAO_LIB} ${TARGET_CERTIFICATE_DAO_DB}) + +INSTALL(TARGETS ${TARGET_CERTIFICATE_DAO_LIB} DESTINATION lib) + +INSTALL(FILES + include/wrt-commons/certificate-dao/certificate_dao_types.h + include/wrt-commons/certificate-dao/certificate_database.h + include/wrt-commons/certificate-dao/certificate_dao.h + DESTINATION include/dpl-efl/wrt-commons/certificate-dao +) + diff --git a/modules/certificate_dao/dao/certificate_dao.cpp b/modules/certificate_dao/dao/certificate_dao.cpp new file mode 100644 index 0000000..0d2138f --- /dev/null +++ b/modules/certificate_dao/dao/certificate_dao.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file certificate_dao.cpp + * @author Leerang Song (leerang.song@samsung.com) + * @version 1.0 + * @brief This file contains the definition of certificate dao class. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* GCC versions 4.7 had changes to the C++ standard. It + * no longer includes to remove namespace pollution. + */ +#include + +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::certificate; + +namespace CertificateDB { +#define SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN Try + +#define SQL_CONNECTION_EXCEPTION_HANDLER_END(message) \ + Catch(DPL::DB::SqlConnection::Exception::Base) { \ + LogError(message); \ + ReThrowMsg(CertificateDAO::Exception::DatabaseError, \ + message); \ + } + +namespace { +DPL::DB::SqlConnection::Flag::Option CERTIFICATE_DB_OPTION = + DPL::DB::SqlConnection::Flag::RW; +DPL::DB::SqlConnection::Flag::Type CERTIFICATE_DB_TYPE = + DPL::DB::SqlConnection::Flag::UseLucene; +const char* const CERTIFICATE_DB_NAME = ".certificate.db"; +const char* const CERTIFICATE_DB_SQL_PATH = + "/usr/share/wrt-engine/certificate_db.sql"; +const char* const CERTIFICATE_DATABASE_JOURNAL_FILENAME = "-journal"; + +const int WEB_APPLICATION_UID = 5000; +const int WEB_APPLICATION_GUID = 5000; + +std::string createDatabasePath(const WrtDB::TizenPkgId &pkgName) +{ + std::stringstream filename; + + filename << WrtDB::WidgetConfig::GetWidgetPersistentStoragePath(pkgName) + << "/" + << CERTIFICATE_DB_NAME; + return filename.str(); +} + +void checkDatabase(std::string databasePath) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + if (databasePath.empty()) { + ThrowMsg(CertificateDAO::Exception::DatabaseError, + "Wrong database Path is passed"); + } + + struct stat buffer; + if (stat(databasePath.c_str(), &buffer) != 0) { + //Create fresh database + LogDebug("Creating database " << databasePath); + + std::fstream file; + file.open(CERTIFICATE_DB_SQL_PATH, std::ios_base::in); + if (!file) { + ThrowMsg(CertificateDAO::Exception::DatabaseError, + "Fail to get database schema from: " << CERTIFICATE_DB_SQL_PATH); + } + + std::stringstream ssBuffer; + ssBuffer << file.rdbuf(); + + file.close(); + + DPL::DB::SqlConnection con(databasePath, + CERTIFICATE_DB_TYPE, + CERTIFICATE_DB_OPTION); + con.ExecCommand(ssBuffer.str().c_str()); + } + + if(chown(databasePath.c_str(), + WEB_APPLICATION_UID, + WEB_APPLICATION_GUID) != 0) + { + ThrowMsg(CertificateDAO::Exception::DatabaseError, + "Fail to change uid/guid"); + } + std::string databaseJournal = + databasePath + CERTIFICATE_DATABASE_JOURNAL_FILENAME; + if(chown(databaseJournal.c_str(), + WEB_APPLICATION_UID, + WEB_APPLICATION_GUID) != 0) + { + ThrowMsg(CertificateDAO::Exception::DatabaseError, + "Fail to change uid/guid"); + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to get database Path") +} +} + +CertificateDAO::CertificateDAO(const WrtDB::TizenPkgId &pkgName) : + m_certificateDBPath(createDatabasePath(pkgName)), + m_certificateDBInterface(m_certificateDBPath, CERTIFICATE_DB_TYPE) +{ + checkDatabase(m_certificateDBPath); + m_certificateDBInterface.AttachToThread(CERTIFICATE_DB_OPTION); +} + +CertificateDAO::~CertificateDAO() +{ + m_certificateDBInterface.DetachFromThread(); +} + +CertificateDataList CertificateDAO::getCertificateDataList(void) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + CertificateDataList list; + CERTIFICATE_DB_SELECT(select, + CertificateInfo, + &m_certificateDBInterface); + typedef std::list RowList; + RowList rowList = select->GetRowList(); + + FOREACH(it, rowList) { + list.push_back( + CertificateDataPtr( + new CertificateData(it->Get_certificate()))); + } + return list; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get data list") +} + +Result CertificateDAO::getResult( + const CertificateData &certificateData) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + CERTIFICATE_DB_SELECT(select, + CertificateInfo, + &m_certificateDBInterface); + select->Where( + Equals(certificateData.certificate)); + CertificateInfo::Select::RowList rows = select->GetRowList(); + + if (rows.empty()) { + return RESULT_UNKNOWN; + } + CertificateInfo::Row row = rows.front(); + return static_cast(row.Get_result()); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END( + "Failed to get result for security certiInfo") +} + +void CertificateDAO::setCertificateData(const CertificateData &certificateData, + const Result result) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&m_certificateDBInterface); + CertificateInfo::Row row; + row.Set_certificate(certificateData.certificate); + row.Set_result(result); + + if (true == hasResult(certificateData)) { + CERTIFICATE_DB_UPDATE(update, + CertificateInfo, + &m_certificateDBInterface); + update->Values(row); + update->Execute(); + } else { + CERTIFICATE_DB_INSERT(insert, + CertificateInfo, + &m_certificateDBInterface); + insert->Values(row); + insert->Execute(); + } + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to set security certiInfo data") +} + +void CertificateDAO::removeCertificateData( + const CertificateData &certificateData) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&m_certificateDBInterface); + + if (true == hasResult(certificateData)) { + CERTIFICATE_DB_DELETE(del, + CertificateInfo, + &m_certificateDBInterface) + del->Where( + Equals(certificateData.certificate)); + del->Execute(); + transaction.Commit(); + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to set certiInfo data") +} + +void CertificateDAO::removeCertificateData(const Result result) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&m_certificateDBInterface); + CERTIFICATE_DB_DELETE(del, + CertificateInfo, + &m_certificateDBInterface) + del->Where(Equals(result)); + del->Execute(); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to remove data by result") +} + +bool CertificateDAO::hasResult(const CertificateData &certificateData) +{ + Result res = getResult(certificateData); + return (res != RESULT_UNKNOWN); +} + +#undef SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN +#undef SQL_CONNECTION_EXCEPTION_HANDLER_END +} // namespace CertificateDB diff --git a/modules/certificate_dao/dao/certificate_dao_types.cpp b/modules/certificate_dao/dao/certificate_dao_types.cpp new file mode 100755 index 0000000..35e8a58 --- /dev/null +++ b/modules/certificate_dao/dao/certificate_dao_types.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file certificate_dao_types.cpp + * @author Leerang Song (leerang.song@samsung.com) + * @version 1.0 + * @brief This file contains the implementation of + * common data types for certificate.db + */ + +#include +#include + +namespace CertificateDB { + +} // namespace CertificateDB diff --git a/modules/certificate_dao/dao/certificate_database.cpp b/modules/certificate_dao/dao/certificate_database.cpp new file mode 100755 index 0000000..4392e0c --- /dev/null +++ b/modules/certificate_dao/dao/certificate_database.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +DPL::Mutex g_certificateDBQueriesMutex; diff --git a/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao.h b/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao.h new file mode 100644 index 0000000..26e981b --- /dev/null +++ b/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file certificate_dao.h + * @author Leerang Song (leerang.song@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of certificate dao + */ +#ifndef _CERTIFICATE_DAO_H_ +#define _CERTIFICATE_DAO_H_ + +#include +#include +#include + +namespace CertificateDB { +class CertificateDAO +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + DECLARE_EXCEPTION_TYPE(Base, DataNotExist) + }; + + explicit CertificateDAO(const WrtDB::TizenPkgId &pkgName); + virtual ~CertificateDAO(); + CertificateDataList getCertificateDataList(); + Result getResult(const CertificateData &certificateData); + void setCertificateData(const CertificateData &certificateData, + const Result result); + void removeCertificateData(const CertificateData &certificateData); + void removeCertificateData(const Result result); + + private: + std::string m_certificateDBPath; + DPL::DB::ThreadDatabaseSupport m_certificateDBInterface; + bool hasResult(const CertificateData &certificateData); +}; + +typedef std::shared_ptr CertificateDAOPtr; +} // namespace CertificateDB + +#endif // _CERTIFICATE_DAO_H_ \ No newline at end of file diff --git a/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao_types.h b/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao_types.h new file mode 100755 index 0000000..f059f4c --- /dev/null +++ b/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_dao_types.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file certificate_dao_types.h + * @author Leerang Song (leerang.song@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of + * common data types for certificate database. + */ +#ifndef _CERTIFICATE_DAO_TYPES_H_ +#define _CERTIFICATE_DAO_TYPES_H_ + +#include +#include +#include + +namespace CertificateDB { + +enum Result +{ + RESULT_UNKNOWN = 0, + RESULT_ALLOW_ONCE, + RESULT_DENY_ONCE, + RESULT_ALLOW_ALWAYS, + RESULT_DENY_ALWAYS +}; + +struct CertificateData +{ + DPL::String certificate; + + CertificateData(const DPL::String& certi) : + certificate(certi) + {} + + bool operator== (const CertificateData& other) const + { + return (certificate == other.certificate); + } + + bool operator!= (const CertificateData& other) const + { + return !(*this == other); + } +}; + +typedef std::shared_ptr CertificateDataPtr; +typedef std::list CertificateDataList; +} // namespace CertificateDB + +#endif // _CERTIFICATE_DAO_TYPES_H_ \ No newline at end of file diff --git a/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_database.h b/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_database.h new file mode 100755 index 0000000..f0ee954 --- /dev/null +++ b/modules/certificate_dao/include/wrt-commons/certificate-dao/certificate_database.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CERTIFICATE_DATABASE_H_ +#define _CERTIFICATE_DATABASE_H_ + +#include +#include + +extern DPL::Mutex g_certificateDBQueriesMutex; + +#define CERTIFICATE_DB_INTERNAL(tlsCommand, InternalType, interface) \ + static DPL::ThreadLocalVariable *tlsCommand##Ptr = NULL; \ + { \ + DPL::Mutex::ScopedLock lock(&g_certificateDBQueriesMutex); \ + if (!tlsCommand##Ptr) { \ + static DPL::ThreadLocalVariable tmp; \ + tlsCommand##Ptr = &tmp; \ + } \ + } \ + DPL::ThreadLocalVariable &tlsCommand = *tlsCommand##Ptr; \ + if (tlsCommand.IsNull()) { tlsCommand = InternalType(interface); } + +#define CERTIFICATE_DB_SELECT(name, type, interface) \ + CERTIFICATE_DB_INTERNAL(name, type::Select, interface) + +#define CERTIFICATE_DB_INSERT(name, type, interface) \ + CERTIFICATE_DB_INTERNAL(name, type::Insert, interface) + +#define CERTIFICATE_DB_UPDATE(name, type, interface) \ + CERTIFICATE_DB_INTERNAL(name, type::Update, interface) + +#define CERTIFICATE_DB_DELETE(name, type, interface) \ + CERTIFICATE_DB_INTERNAL(name, type::Delete, interface) + +#endif // _CERTIFICATE_DATABASE_H_ + diff --git a/modules/certificate_dao/orm/certificate_db b/modules/certificate_dao/orm/certificate_db new file mode 100755 index 0000000..2dbe366 --- /dev/null +++ b/modules/certificate_dao/orm/certificate_db @@ -0,0 +1,9 @@ +SQL(BEGIN TRANSACTION;) + +CREATE_TABLE(CertificateInfo) + COLUMN_NOT_NULL(certificate, TEXT,DEFAULT '') + COLUMN_NOT_NULL(result, INT, DEFAULT 0) + TABLE_CONSTRAINTS(PRIMARY KEY(certificate)) +CREATE_TABLE_END() + +SQL(COMMIT;) diff --git a/modules/certificate_dao/orm/certificate_db_definitions b/modules/certificate_dao/orm/certificate_db_definitions new file mode 100644 index 0000000..6cfdc11 --- /dev/null +++ b/modules/certificate_dao/orm/certificate_db_definitions @@ -0,0 +1,5 @@ +DATABASE_START(certificate) + +#include "certificate_db" + +DATABASE_END() diff --git a/modules/certificate_dao/orm/certificate_db_sql_generator.h b/modules/certificate_dao/orm/certificate_db_sql_generator.h new file mode 100755 index 0000000..07c1816 --- /dev/null +++ b/modules/certificate_dao/orm/certificate_db_sql_generator.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file certificate_db_sql_generator.h + * @author Leerang Song (leerang.song@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL + * input file from database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. +#include + +#include "certificate_db_definitions" diff --git a/modules/certificate_dao/orm/orm_generator_certificate.h b/modules/certificate_dao/orm/orm_generator_certificate.h new file mode 100755 index 0000000..6822708 --- /dev/null +++ b/modules/certificate_dao/orm/orm_generator_certificate.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ORM_GENERATOR_CERTIFICATE_H_ +#define _ORM_GENERATOR_CERTIFICATE_H_ + +#define ORM_GENERATOR_DATABASE_NAME certificate_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif // _ORM_GENERATOR_CERTIFICATE_H_ \ No newline at end of file diff --git a/modules/core/DESCRIPTION b/modules/core/DESCRIPTION new file mode 100644 index 0000000..1369c40 --- /dev/null +++ b/modules/core/DESCRIPTION @@ -0,0 +1 @@ +Main library code diff --git a/modules/core/config.cmake b/modules/core/config.cmake new file mode 100644 index 0000000..13f83d1 --- /dev/null +++ b/modules/core/config.cmake @@ -0,0 +1,153 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# Set DPL core sources +SET(DPL_CORE_SOURCES + ${PROJECT_SOURCE_DIR}/modules/core/src/abstract_waitable_input_adapter.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/abstract_waitable_input_output_adapter.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/abstract_waitable_output_adapter.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/address.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/apply.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/assert.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/atomic.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/binary_queue.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/char_traits.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/colors.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/copy.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/errno_string.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/exception.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/file_input.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/file_output.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/lexical_cast.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/mutable_task_list.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/mutex.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/named_base_pipe.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/named_output_pipe.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/noncopyable.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/once.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/read_write_mutex.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/recursive_mutex.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/scoped_dir.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/serialization.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/single_instance.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/singleton.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/semaphore.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/string.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/task.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/thread.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/type_list.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/union_cast.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/zip_input.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/application.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/main.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/waitable_event.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/waitable_handle.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/waitable_handle_watch_support.cpp + ${PROJECT_SOURCE_DIR}/modules/core/src/generic_event.cpp + PARENT_SCOPE +) + + +# Set DPL core headers +SET(DPL_CORE_HEADERS + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_input.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_input_output.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_output.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_waitable_input_adapter.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_waitable_input.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_waitable_input_output_adapter.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_waitable_input_output.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_waitable_output_adapter.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/abstract_waitable_output.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/address.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/aligned.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/apply.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/assert.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/atomic.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/availability.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/binary_queue.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/bind.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/bool_operator.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/char_traits.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/colors.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/copy.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/enable_shared_from_this.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/errno_string.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/exception.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/file_input.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/file_output.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/foreach.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/generic_event.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/lexical_cast.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/mutable_task_list.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/mutex.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/named_base_pipe.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/named_input_pipe.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/named_output_pipe.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/noncopyable.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/once.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/optional.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/optional_typedefs.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/platform.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/preprocessor.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/read_write_mutex.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/recursive_mutex.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scope_guard.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_resource.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_array.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_close.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_dir.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_fclose.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_free.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_ptr.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/scoped_gpointer.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/serialization.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/semaphore.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/shared_ptr.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/single_instance.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/singleton.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/singleton_impl.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/singleton_safe_impl.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/static_block.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/string.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/sstream.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/task.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/thread.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/type_list.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/union_cast.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/workaround.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/zip_input.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/application.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/framework_appcore.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/framework_efl.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/framework_vconf.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/main.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/waitable_event.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/waitable_handle.h + ${PROJECT_SOURCE_DIR}/modules/core/include/dpl/waitable_handle_watch_support.h + PARENT_SCOPE +) + +SET(DPL_CORE_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/core/include + PARENT_SCOPE +) + diff --git a/modules/core/include/DESCRIPTION b/modules/core/include/DESCRIPTION new file mode 100644 index 0000000..6dfd446 --- /dev/null +++ b/modules/core/include/DESCRIPTION @@ -0,0 +1,2 @@ +!!!options!!! stop +Header files, including template implementations diff --git a/modules/core/include/dpl/abstract_input.h b/modules/core/include/dpl/abstract_input.h new file mode 100644 index 0000000..8c0e16a --- /dev/null +++ b/modules/core/include/dpl/abstract_input.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract input + */ +#ifndef DPL_ABSTRACT_INPUT_H +#define DPL_ABSTRACT_INPUT_H + +#include +#include + +namespace DPL { +class BinaryQueue; +typedef std::auto_ptr BinaryQueueAutoPtr; + +class AbstractInput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, ReadFailed) + }; + + public: + virtual ~AbstractInput() {} + + /** + * Read binary data from input + * If no data is available method returns NULL buffer. + * In case connection was successfuly close, method returns empty buffer + * + * @param[in] size Maximum number of bytes to read from input + * @return Buffer containing read bytes + * @throw ReadFailed + */ + virtual BinaryQueueAutoPtr Read(size_t size) = 0; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_INPUT_H diff --git a/modules/core/include/dpl/abstract_input_output.h b/modules/core/include/dpl/abstract_input_output.h new file mode 100644 index 0000000..153d5c4 --- /dev/null +++ b/modules/core/include/dpl/abstract_input_output.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract output + */ +#ifndef DPL_ABSTRACT_INPUT_OUTPUT_H +#define DPL_ABSTRACT_INPUT_OUTPUT_H + +#include +#include + +namespace DPL { +class AbstractInputOutput : + public AbstractInput, + public AbstractOutput +{ + public: + virtual ~AbstractInputOutput() {} +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_INPUT_OUTPUT_H diff --git a/modules/core/include/dpl/abstract_output.h b/modules/core/include/dpl/abstract_output.h new file mode 100644 index 0000000..56c86fb --- /dev/null +++ b/modules/core/include/dpl/abstract_output.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract output + */ +#ifndef DPL_ABSTRACT_OUTPUT_H +#define DPL_ABSTRACT_OUTPUT_H + +#include +#include + +namespace DPL { +class BinaryQueue; +typedef std::auto_ptr BinaryQueueAutoPtr; + +class AbstractOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, WriteFailed) + }; + + public: + virtual ~AbstractOutput() {} + + /** + * Write binary data to output + * If output is blocked, Write returns zero, if instance is a type of + * WaitableAbstractOutput one can wait for writability then + * + * @param[in] buffer Input buffer with data to be written + * @param[in] bufferSize Maximum number of bytes to write from buffer + * @return Number of bytes success successfuly written or zero if output is + * blocked + * @throw WriteFailed + */ + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize) = 0; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_OUTPUT_H diff --git a/modules/core/include/dpl/abstract_waitable_input.h b/modules/core/include/dpl/abstract_waitable_input.h new file mode 100644 index 0000000..9d957d6 --- /dev/null +++ b/modules/core/include/dpl/abstract_waitable_input.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract waitable input + */ +#ifndef DPL_ABSTRACT_WAITABLE_INPUT_H +#define DPL_ABSTRACT_WAITABLE_INPUT_H + +#include +#include + +namespace DPL { +class AbstractWaitableInput : + public AbstractInput +{ + public: + virtual ~AbstractWaitableInput() {} + + virtual WaitableHandle WaitableReadHandle() const = 0; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_WAITABLE_INPUT_H diff --git a/modules/core/include/dpl/abstract_waitable_input_adapter.h b/modules/core/include/dpl/abstract_waitable_input_adapter.h new file mode 100644 index 0000000..43efaee --- /dev/null +++ b/modules/core/include/dpl/abstract_waitable_input_adapter.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract waitable input + */ +#ifndef DPL_ABSTRACT_WAITABLE_INPUT_ADAPTER_H +#define DPL_ABSTRACT_WAITABLE_INPUT_ADAPTER_H + +#include +#include +#include + +namespace DPL { +class AbstractWaitableInputAdapter : + public AbstractWaitableInput +{ + private: + AbstractInput *m_input; + WaitableEvent m_waitableEvent; + + public: + explicit AbstractWaitableInputAdapter(AbstractInput *input); + + virtual BinaryQueueAutoPtr Read(size_t size); + + virtual WaitableHandle WaitableReadHandle() const; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_WAITABLE_INPUT_ADAPTER_H diff --git a/modules/core/include/dpl/abstract_waitable_input_output.h b/modules/core/include/dpl/abstract_waitable_input_output.h new file mode 100644 index 0000000..e858f51 --- /dev/null +++ b/modules/core/include/dpl/abstract_waitable_input_output.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_input_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract waitable input output + */ +#ifndef DPL_ABSTRACT_WAITABLE_INPUT_OUTPUT_H +#define DPL_ABSTRACT_WAITABLE_INPUT_OUTPUT_H + +#include +#include + +namespace DPL { +class AbstractWaitableInputOutput : + public AbstractWaitableInput, + public AbstractWaitableOutput +{ + public: + virtual ~AbstractWaitableInputOutput() {} +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_WAITABLE_INPUT_OUTPUT_H diff --git a/modules/core/include/dpl/abstract_waitable_input_output_adapter.h b/modules/core/include/dpl/abstract_waitable_input_output_adapter.h new file mode 100644 index 0000000..a0322d0 --- /dev/null +++ b/modules/core/include/dpl/abstract_waitable_input_output_adapter.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_input_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract waitable input output + */ +#ifndef DPL_ABSTRACT_WAITABLE_INPUT_OUTPUT_ADAPTER_H +#define DPL_ABSTRACT_WAITABLE_INPUT_OUTPUT_ADAPTER_H + +#include +#include +#include + +namespace DPL { +class AbstractWaitableInputOutputAdapter : + public AbstractWaitableInputAdapter, + public AbstractWaitableOutputAdapter +{ + public: + explicit AbstractWaitableInputOutputAdapter( + AbstractInputOutput *inputOutput); +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_WAITABLE_INPUT_OUTPUT_ADAPTER_H diff --git a/modules/core/include/dpl/abstract_waitable_output.h b/modules/core/include/dpl/abstract_waitable_output.h new file mode 100644 index 0000000..abcc3f8 --- /dev/null +++ b/modules/core/include/dpl/abstract_waitable_output.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract waitable output + */ +#ifndef DPL_ABSTRACT_WAITABLE_OUTPUT_H +#define DPL_ABSTRACT_WAITABLE_OUTPUT_H + +#include +#include + +namespace DPL { +class AbstractWaitableOutput : + public AbstractOutput +{ + public: + virtual ~AbstractWaitableOutput() {} + + virtual WaitableHandle WaitableWriteHandle() const = 0; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_WAITABLE_OUTPUT_H diff --git a/modules/core/include/dpl/abstract_waitable_output_adapter.h b/modules/core/include/dpl/abstract_waitable_output_adapter.h new file mode 100644 index 0000000..9e40bc4 --- /dev/null +++ b/modules/core/include/dpl/abstract_waitable_output_adapter.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract waitable output + */ +#ifndef DPL_ABSTRACT_WAITABLE_OUTPUT_ADAPTER_H +#define DPL_ABSTRACT_WAITABLE_OUTPUT_ADAPTER_H + +#include +#include +#include + +namespace DPL { +class AbstractWaitableOutputAdapter : + public AbstractWaitableOutput +{ + private: + AbstractOutput *m_output; + WaitableEvent m_waitableEvent; + + public: + explicit AbstractWaitableOutputAdapter(AbstractOutput *output); + + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize); + + virtual WaitableHandle WaitableWriteHandle() const; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_WAITABLE_OUTPUT_ADAPTER_H diff --git a/modules/core/include/dpl/address.h b/modules/core/include/dpl/address.h new file mode 100644 index 0000000..05893f9 --- /dev/null +++ b/modules/core/include/dpl/address.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file address.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of address + */ +#ifndef DPL_ADDRESS_H +#define DPL_ADDRESS_H + +#include +#include + +namespace DPL { +class Address +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InvalidAddress) + }; + + private: + std::string m_address; + unsigned short m_port; + + public: + Address(); + Address(const std::string &address); + Address(const std::string &address, unsigned short port); + + virtual ~Address(); + + std::string GetAddress() const; + unsigned short GetPort() const; + + std::string ToString() const; + + bool operator<(const Address &addr) const; +}; +} // namespace DPL + +#endif // DPL_ADDRESS_H diff --git a/modules/core/include/dpl/aligned.h b/modules/core/include/dpl/aligned.h new file mode 100644 index 0000000..4400545 --- /dev/null +++ b/modules/core/include/dpl/aligned.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file aligned.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of aligned attribute from + * gcc + */ +#ifndef DPL_ALIGNED_H +#define DPL_ALIGNED_H + +#define DPL_ALIGNED(n) __attribute__((aligned(n))) + +#endif // DPL_ALIGNED_H diff --git a/modules/core/include/dpl/application.h b/modules/core/include/dpl/application.h new file mode 100644 index 0000000..188d7ac --- /dev/null +++ b/modules/core/include/dpl/application.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file application.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC application support + */ +#ifndef DPL_APPLICATION_H +#define DPL_APPLICATION_H + +#include +#include +#include +#include +#include + +namespace DPL { +class Application +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, TooManyInstances) + DECLARE_EXCEPTION_TYPE(Base, FrameworkError) + }; + + protected: + int m_argc; + char **m_argv; + std::string m_applicationName; + + bool m_mainWindowVisible; + + static bool app_create(void *data); + static void app_terminate(void *data); + static void app_pause(void *data); + static void app_resume(void *data); + static void app_control(app_control_h app_control, void *data); + + virtual void OnCreate(); + virtual void OnStart(); + virtual void OnStop(); + virtual void OnResume(); + virtual void OnPause(); + virtual void OnRelaunch(); + virtual void OnReset(bundle *b); + virtual void OnTerminate(); + virtual void OnLowMemory(); + virtual void OnLowBattery(); + virtual void OnLanguageChanged(); + + public: + Application(int argc, + char **argv, + const std::string &applicationName, + bool showMainWindow = true); + virtual ~Application(); + + /** + * @brief Execute application and start message processing + */ + virtual int Exec(); + + /* + * @brief Sends quit message to application message loop + */ + virtual void Quit(); +}; + +class ApplicationExt : public Application +{ + public: + ApplicationExt(int argc, + char **argv, + const std::string &applicationName, + bool showMainWindow = true); + virtual ~ApplicationExt(); + + /** + * @brief Execute application and start message processing + */ + virtual int Exec(); + + /* + * @brief Sends quit message to application message loop + */ + virtual void Quit(); + + private: + static DPL::Atomic m_useCount; +}; +} // namespace DPL + +#endif // DPL_APPLICATION_H diff --git a/modules/core/include/dpl/apply.h b/modules/core/include/dpl/apply.h new file mode 100644 index 0000000..fc1be53 --- /dev/null +++ b/modules/core/include/dpl/apply.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file apply.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief Implementation file for Apply functionality. + */ +#ifndef DPL_APPLY_H_ +#define DPL_APPLY_H_ + +#ifndef __GXX_EXPERIMENTAL_CXX0X__ // C++11 compatibility check +# include +#else + +#include +#include + +namespace DPL { +enum class ExtraArgsInsertPolicy +{ + /** + * Extra arguments will be add at the end of the argument list + * passed to operation call. + */ + Append, + + /** + * Extra arguments will be add at the begining of the argument list + * passed to operation call. + */ + Prepend +}; + +template +struct _ApplyDispatchByPolicy; + +template +Result Apply(Operation op, + const std::tuple& t, + ArgsE && ... extra) +{ + return _ApplyDispatchByPolicy:: + template Apply(op, t, std::forward(extra) ...); +} + +template +struct _ApplyTuple +{ + template + static Result Apply(Operation op, + const std::tuple& t1, + const std::tuple& t2, + Args && ... args) + { + return _ApplyTuple:: + template Apply(op, + t1, + t2, + std::get(t1), + std::forward(args) ...); + } +}; + +template +struct _ApplyTuple<0, M> +{ + template + static Result Apply(Operation op, + const std::tuple& t1, + const std::tuple& t2, + Args && ... args) + { + return _ApplyTuple<0, M - 1>:: + template Apply(op, + t1, + t2, + std::get(t2), + std::forward(args) ...); + } +}; + +template<> +struct _ApplyTuple<0, 0> +{ + template + static Result Apply(Operation op, + const std::tuple&, + const std::tuple&, + Args && ... args) + { + return op(std::forward(args) ...); + } +}; + +template +struct _ApplyArgs +{ + template + static Result Apply(Operation op, + const std::tuple& t, + Args && ... args) + { + return _ApplyArgs:: + template Apply(op, + t, + std::get(t), + std::forward(args) ...); + } +}; + +template<> +struct _ApplyArgs<0> +{ + template + static Result Apply(Operation op, + const std::tuple&, + Args && ... args) + { + return op(std::forward(args) ...); + } +}; + +template<> +struct _ApplyDispatchByPolicy +{ + template + static Result Apply(Operation op, + const std::tuple& t, + ArgsE && ... extra) + { + return _ApplyArgs:: + template Apply(op, + t, + std::forward(extra) ...); + } +}; + +template<> +struct _ApplyDispatchByPolicy +{ + template + static Result Apply(Operation op, + const std::tuple& t, + ArgsE && ... extra) + { + return _ApplyTuple:: + template Apply(op, + t, + std::make_tuple(std::forward( + extra) ...)); + } +}; +} // namespace DPL + +#endif // __GXX_EXPERIMENTAL_CXX0X__ + +#endif // DPL_APPLY_H_ diff --git a/modules/core/include/dpl/assert.h b/modules/core/include/dpl/assert.h new file mode 100644 index 0000000..abdb481 --- /dev/null +++ b/modules/core/include/dpl/assert.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#ifndef DPL_ASSERT_H +#define DPL_ASSERT_H + +namespace DPL { +// Assertion handler procedure +// Do not call directly +// Always use Assert macro +void AssertProc(const char *condition, + const char *file, + int line, + const char *function) __attribute__ ((__noreturn__)); +} // namespace DPL + +#define Assert(Condition) do { if (!(Condition)) { DPL::AssertProc(#Condition, \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + } } while (0) + +#define AssertMsg(Condition, Msg) \ + do { \ + if (!(Condition)) { \ + DPL::AssertProc( \ + (std::string(std::string(#Condition)+" ") + Msg).c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) + +#endif // DPL_ASSERT_H diff --git a/modules/core/include/dpl/atomic.h b/modules/core/include/dpl/atomic.h new file mode 100644 index 0000000..50c4a1a --- /dev/null +++ b/modules/core/include/dpl/atomic.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file atomic.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of atomic + */ +#ifndef DPL_ATOMIC_H +#define DPL_ATOMIC_H + +#pragma GCC system_header +#include + +namespace DPL { +class Atomic +{ + public: + typedef gint ValueType; + + private: + volatile ValueType m_value; + + public: + Atomic(ValueType value = static_cast(0)); + + ValueType ExchangeAndAdd(ValueType value); + bool CompareAndExchange(ValueType oldValue, ValueType newValue); + bool operator--(); + void operator++(); + + operator ValueType() const; +}; +} // namespace DPL + +#endif // DPL_ATOMIC_H diff --git a/modules/core/include/dpl/availability.h b/modules/core/include/dpl/availability.h new file mode 100644 index 0000000..0813892 --- /dev/null +++ b/modules/core/include/dpl/availability.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file availability.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + */ +#ifndef DPL_AVAILABILITY_H +#define DPL_AVAILABILITY_H + +#define DPL_DEPRECATED __attribute__((deprecated)) +#define DPL_DEPRECATED_WITH_MESSAGE(msg) __attribute__((deprecated(msg))) + +#define DPL_UNUSED __attribute__((unused)) +#define DPL_UNUSED_PARAM(variable) (void)variable + +#endif // DPL_AVAILABILITY_H diff --git a/modules/core/include/dpl/binary_queue.h b/modules/core/include/dpl/binary_queue.h new file mode 100644 index 0000000..f4fa278 --- /dev/null +++ b/modules/core/include/dpl/binary_queue.h @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file binary_queue.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of binary queue + */ +#ifndef DPL_BINARY_QUEUE_H +#define DPL_BINARY_QUEUE_H + +#include +#include +#include +#include +#include + +namespace DPL { +/** + * Binary stream implemented as constant size bucket list + * + * @todo Add optimized implementation for FlattenConsume + */ +class BinaryQueue : + public AbstractInputOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OutOfData) + }; + + typedef void (*BufferDeleter)(const void *buffer, size_t bufferSize, + void *userParam); + static void BufferDeleterFree(const void *buffer, + size_t bufferSize, + void *userParam); + + class BucketVisitor + { + public: + /** + * Destructor + */ + virtual ~BucketVisitor(); + + /** + * Visit bucket + * + * @return none + * @param[in] buffer Constant pointer to bucket data buffer + * @param[in] bufferSize Number of bytes in bucket + */ + virtual void OnVisitBucket(const void *buffer, size_t bufferSize) = 0; + }; + + private: + struct Bucket : + private Noncopyable + { + const void *buffer; + const void *ptr; + size_t size; + size_t left; + + BufferDeleter deleter; + void *param; + + Bucket(const void *buffer, + size_t bufferSize, + BufferDeleter deleter, + void *userParam); + virtual ~Bucket(); + }; + + typedef std::list BucketList; + BucketList m_buckets; + size_t m_size; + + static void DeleteBucket(Bucket *bucket); + + class BucketVisitorCall + { + private: + BucketVisitor *m_visitor; + + public: + BucketVisitorCall(BucketVisitor *visitor); + virtual ~BucketVisitorCall(); + + void operator()(Bucket *bucket) const; + }; + + public: + /** + * Construct empty binary queue + */ + BinaryQueue(); + + /** + * Construct binary queue via bare copy of other binary queue + * + * @param[in] other Other binary queue to copy from + * @warning One cannot assume that bucket structure is preserved during copy + */ + BinaryQueue(const BinaryQueue &other); + + /** + * Destructor + */ + virtual ~BinaryQueue(); + + /** + * Construct binary queue via bare copy of other binary queue + * + * @param[in] other Other binary queue to copy from + * @warning One cannot assume that bucket structure is preserved during copy + */ + const BinaryQueue &operator=(const BinaryQueue &other); + + /** + * Append copy of @a bufferSize bytes from memory pointed by @a buffer + * to the end of binary queue. Uses default deleter based on free. + * + * @return none + * @param[in] buffer Pointer to buffer to copy data from + * @param[in] bufferSize Number of bytes to copy + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @see BinaryQueue::BufferDeleterFree + */ + void AppendCopy(const void *buffer, size_t bufferSize); + + /** + * Append @a bufferSize bytes from memory pointed by @a buffer + * to the end of binary queue. Uses custom provided deleter. + * Responsibility for deleting provided buffer is transfered to BinaryQueue. + * + * @return none + * @param[in] buffer Pointer to data buffer + * @param[in] bufferSize Number of bytes available in buffer + * @param[in] deleter Pointer to deleter procedure used to free provided + * buffer + * @param[in] userParam User parameter passed to deleter routine + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendUnmanaged( + const void *buffer, + size_t bufferSize, + BufferDeleter deleter = + &BinaryQueue::BufferDeleterFree, + void *userParam = NULL); + + /** + * Append copy of other binary queue to the end of this binary queue + * + * @return none + * @param[in] other Constant reference to other binary queue to copy data + * from + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @warning One cannot assume that bucket structure is preserved during copy + */ + void AppendCopyFrom(const BinaryQueue &other); + + /** + * Move bytes from other binary queue to the end of this binary queue. + * This also removes all bytes from other binary queue. + * This method is designed to be as fast as possible (only pointer swaps) + * and is suggested over making copies of binary queues. + * Bucket structure is preserved after operation. + * + * @return none + * @param[in] other Reference to other binary queue to move data from + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendMoveFrom(BinaryQueue &other); + + /** + * Append copy of binary queue to the end of other binary queue + * + * @return none + * @param[in] other Constant reference to other binary queue to copy data to + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @warning One cannot assume that bucket structure is preserved during copy + */ + void AppendCopyTo(BinaryQueue &other) const; + + /** + * Move bytes from binary queue to the end of other binary queue. + * This also removes all bytes from binary queue. + * This method is designed to be as fast as possible (only pointer swaps) + * and is suggested over making copies of binary queues. + * Bucket structure is preserved after operation. + * + * @return none + * @param[in] other Reference to other binary queue to move data to + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendMoveTo(BinaryQueue &other); + + /** + * Retrieve total size of all data contained in binary queue + * + * @return Number of bytes in binary queue + */ + size_t Size() const; + + /** + * Remove all data from binary queue + * + * @return none + */ + void Clear(); + + /** + * Check if binary queue is empty + * + * @return true if binary queue is empty, false otherwise + */ + bool Empty() const; + + /** + * Remove @a size bytes from beginning of binary queue + * + * @return none + * @param[in] size Number of bytes to remove + * @exception BinaryQueue::Exception::OutOfData Number of bytes is larger + * than available bytes in binary queue + */ + void Consume(size_t size); + + /** + * Retrieve @a bufferSize bytes from beginning of binary queue and copy them + * to user supplied buffer + * + * @return none + * @param[in] buffer Pointer to user buffer to receive bytes + * @param[in] bufferSize Size of user buffer pointed by @a buffer + * @exception BinaryQueue::Exception::OutOfData Number of bytes to flatten + * is larger than available bytes in binary queue + */ + void Flatten(void *buffer, size_t bufferSize) const; + + /** + * Retrieve @a bufferSize bytes from beginning of binary queue, copy them + * to user supplied buffer, and remove from binary queue + * + * @return none + * @param[in] buffer Pointer to user buffer to receive bytes + * @param[in] bufferSize Size of user buffer pointed by @a buffer + * @exception BinaryQueue::Exception::OutOfData Number of bytes to flatten + * is larger than available bytes in binary queue + */ + void FlattenConsume(void *buffer, size_t bufferSize); + + /** + * Visit each buffer with data using visitor object + * + * @return none + * @param[in] visitor Pointer to bucket visitor + * @see BinaryQueue::BucketVisitor + */ + void VisitBuckets(BucketVisitor *visitor) const; + + /** + * IAbstractInput interface + */ + virtual BinaryQueueAutoPtr Read(size_t size); + + /** + * IAbstractOutput interface + */ + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize); +}; + +/** + * Binary queue auto pointer + */ +typedef std::auto_ptr BinaryQueueAutoPtr; +} // namespace DPL + +#endif // DPL_BINARY_QUEUE_H diff --git a/modules/core/include/dpl/bind.h b/modules/core/include/dpl/bind.h new file mode 100644 index 0000000..190319b --- /dev/null +++ b/modules/core/include/dpl/bind.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file bind.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the header file of bind + */ + +/* + * Remarks: + * - Current implementation supports binding member functions (methods) only. + * - Currently up to 8 std::placeholders are supported. + * - Bound delegates are of type std::function<...>. This implies that + * passing arguments at bind-time is not supported (arguments MAY ONLY be + * passed at call-time). + * + * Usage: + * - For usage see tests/core/test_bind.cpp. In general, usage comes down to: + * std::function delegate = + * DPL::Bind(&ObjectType::MethodName, &object); + */ + +#ifndef DPL_BIND_H_ +#define DPL_BIND_H_ + +#include + +#include +#include +#include + +namespace DPL { +namespace detail { +template +struct PlaceholdersBindHelper; + +#define DPL_PLACEHOLDERS_LIST_(z, n, t) ,BOOST_PP_CAT(std::placeholders::_, \ + BOOST_PP_ADD(n, 1)) +#define DPL_PLACEHOLDERS_(count) BOOST_PP_REPEAT(count, \ + DPL_PLACEHOLDERS_LIST_, \ + count) +#define DPL_PLACEHOLDERS_BIND_HELPER_(count) \ +template<> \ +struct PlaceholdersBindHelper \ +{ \ + template \ + static std::function \ + bind(Result(Type::*method)(Args...), Type* object) { \ + return std::bind(method, object DPL_PLACEHOLDERS_(count)); \ + } \ +} + +DPL_PLACEHOLDERS_BIND_HELPER_(0); +DPL_PLACEHOLDERS_BIND_HELPER_(1); +DPL_PLACEHOLDERS_BIND_HELPER_(2); +DPL_PLACEHOLDERS_BIND_HELPER_(3); +DPL_PLACEHOLDERS_BIND_HELPER_(4); +DPL_PLACEHOLDERS_BIND_HELPER_(5); +DPL_PLACEHOLDERS_BIND_HELPER_(6); +DPL_PLACEHOLDERS_BIND_HELPER_(7); +DPL_PLACEHOLDERS_BIND_HELPER_(8); +} + +template +std::function Bind(Result(Type::*method)(Args...), + Type* object) +{ + return detail::PlaceholdersBindHelper::bind(method, + object); +} +} + +#endif // DPL_BIND_H_ diff --git a/modules/core/include/dpl/bool_operator.h b/modules/core/include/dpl/bool_operator.h new file mode 100644 index 0000000..a432df3 --- /dev/null +++ b/modules/core/include/dpl/bool_operator.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file bool_operator.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of bool operator + * + * This module is deprecated, please use standard C++11 feature: explicit conversion operator + * + * example: + * explicit operator bool() {}; + */ +#ifndef DPL_BOOL_OPERATOR_H +#define DPL_BOOL_OPERATOR_H + +#include + +#define DPL_IMPLEMENT_BOOL_OPERATOR(Type, ThisType, CheckPtr, ClassPtr) \ + typedef Type *ThisType::*UnknownBoolType; \ + \ + operator UnknownBoolType() const \ + { \ + return (CheckPtr == NULL) ? NULL : &ThisType::ClassPtr; \ + } DPL_DEPRECATED_WITH_MESSAGE("use standard C++11 feature: explicit conversion operator"); \ + \ + bool operator !() const \ + { \ + return CheckPtr == NULL; \ + } DPL_DEPRECATED_WITH_MESSAGE("use standard C++11 feature: explicit conversion operator"); \ + +#endif // DPL_BOOL_OPERATOR_H diff --git a/modules/core/include/dpl/char_traits.h b/modules/core/include/dpl/char_traits.h new file mode 100644 index 0000000..eb2988f --- /dev/null +++ b/modules/core/include/dpl/char_traits.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file char_traits.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief Char traits are used to create basic_string extended with + * additional features + * Current char traits could be extended in feature to boost + * performance + */ +#ifndef DPL_CHAR_TRAITS +#define DPL_CHAR_TRAITS + +#include +#include +#include +#include +#include + +namespace DPL { +typedef std::char_traits CharTraits; +} // namespace DPL + +#endif // DPL_CHAR_TRAITS diff --git a/modules/core/include/dpl/colors.h b/modules/core/include/dpl/colors.h new file mode 100644 index 0000000..c7cfd53 --- /dev/null +++ b/modules/core/include/dpl/colors.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file colors.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Some constants with definition of colors for Console + * and html output + */ + +#ifndef DPL_COLORS_H +#define DPL_COLORS_H + +namespace DPL { +namespace Colors { +namespace Text { +extern const char* BOLD_GREEN_BEGIN; +extern const char* BOLD_GREEN_END; +extern const char* PURPLE_BEGIN; +extern const char* PURPLE_END; +extern const char* RED_BEGIN; +extern const char* RED_END; +extern const char* GREEN_BEGIN; +extern const char* GREEN_END; +extern const char* CYAN_BEGIN; +extern const char* CYAN_END; +extern const char* BOLD_RED_BEGIN; +extern const char* BOLD_RED_END; +extern const char* BOLD_YELLOW_BEGIN; +extern const char* BOLD_YELLOW_END; +extern const char* BOLD_GOLD_BEGIN; +extern const char* BOLD_GOLD_END; +extern const char* BOLD_WHITE_BEGIN; +extern const char* BOLD_WHITE_END; +} //namespace Text + +namespace Html { +extern const char* BOLD_GREEN_BEGIN; +extern const char* BOLD_GREEN_END; +extern const char* PURPLE_BEGIN; +extern const char* PURPLE_END; +extern const char* RED_BEGIN; +extern const char* RED_END; +extern const char* GREEN_BEGIN; +extern const char* GREEN_END; +extern const char* CYAN_BEGIN; +extern const char* CYAN_END; +extern const char* BOLD_RED_BEGIN; +extern const char* BOLD_RED_END; +extern const char* BOLD_YELLOW_BEGIN; +extern const char* BOLD_YELLOW_END; +extern const char* BOLD_GOLD_BEGIN; +extern const char* BOLD_GOLD_END; +extern const char* BOLD_WHITE_BEGIN; +extern const char* BOLD_WHITE_END; +} //namespace Html +} //namespace Colors +} //namespace DPL + +#endif /* DPL_COLORS_H */ diff --git a/modules/core/include/dpl/copy.h b/modules/core/include/dpl/copy.h new file mode 100644 index 0000000..e796a61 --- /dev/null +++ b/modules/core/include/dpl/copy.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file copy.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of copy + */ +#ifndef DPL_COPY_H +#define DPL_COPY_H + +#include +#include +#include + +namespace DPL { +/** + * Copy failed exception + */ +DECLARE_EXCEPTION_TYPE(Exception, CopyFailed) + +/** + * Copy all bytes abstract waitable input to abstract waitable output + * + * @param[in] input Abstract waitable input to copy from + * @param[in] output Abstract waitable output to copy to + * @throw CopyFailed An error occurred while copying. Look into exception trace + * for details. + */ +void Copy(AbstractWaitableInput *input, AbstractWaitableOutput *output); + +/** + * Copy exactly totalBytes bytes abstract waitable input to abstract waitable + * output + * + * @param[in] input Abstract waitable input to copy from + * @param[in] output Abstract waitable output to copy to + * @throw CopyFailed An error occurred while copying. Look into exception trace + * for details. + */ +void Copy(AbstractWaitableInput *input, + AbstractWaitableOutput *output, + size_t totalBytes); +} // namespace DPL + +#endif // DPL_COPY_H diff --git a/modules/core/include/dpl/enable_shared_from_this.h b/modules/core/include/dpl/enable_shared_from_this.h new file mode 100644 index 0000000..0a0fb3a --- /dev/null +++ b/modules/core/include/dpl/enable_shared_from_this.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file enable_shared_from_this.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of shared pointer RAII + */ +#ifndef DPL_ENABLE_SHARED_FROM_THIS_H +#define DPL_ENABLE_SHARED_FROM_THIS_H + +#include +#include +#include + +namespace DPL { +template +class EnableSharedFromThis : private Noncopyable +{ + private: + // A weak pointer to shared counter + SharedCounter *m_counter; + Class *m_ptr; + + public: + DPL::SharedPtr SharedFromThis() + { + Assert(m_counter != NULL && "Pointer is not shared!"); + return SharedPtr(m_counter, m_ptr); + } + + DPL::SharedPtr SharedFromThis() const + { + Assert(m_counter != NULL && "Pointer is not shared!"); + return SharedPtr(m_counter, m_ptr); + } + + // For internal SharedPtr usage only. Do not call directly. + void _Internal_AcceptSharedPtr(SharedCounter *counter, Class *ptr) + { + m_counter = counter; + m_ptr = ptr; + } + + EnableSharedFromThis() : + m_counter(NULL), + m_ptr(NULL) + {} + + virtual ~EnableSharedFromThis() + {} +}; +} // namespace DPL + +#endif // DPL_ENABLE_SHARED_FROM_THIS_H diff --git a/modules/core/include/dpl/errno_string.h b/modules/core/include/dpl/errno_string.h new file mode 100644 index 0000000..446dbc9 --- /dev/null +++ b/modules/core/include/dpl/errno_string.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file errno_string.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of errno string + */ +#ifndef DPL_ERRNO_STRING_H +#define DPL_ERRNO_STRING_H + +#include +#include +#include + +namespace DPL { +DECLARE_EXCEPTION_TYPE(DPL::Exception, InvalidErrnoValue) + +std::string GetErrnoString(int error = errno); +} // namespace DPL + +#endif // DPL_ERRNO_STRING_H diff --git a/modules/core/include/dpl/exception.h b/modules/core/include/dpl/exception.h new file mode 100644 index 0000000..cdbdc53 --- /dev/null +++ b/modules/core/include/dpl/exception.h @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for base exception + */ +#ifndef DPL_EXCEPTION_H +#define DPL_EXCEPTION_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +void LogUnhandledException(const std::string &str); +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function); +} + +namespace DPL { +class Exception +{ + private: + static unsigned int m_exceptionCount; + static Exception* m_lastException; + static void (*m_terminateHandler)(); + + static void AddRef(Exception* exception) + { + if (!m_exceptionCount) { + m_terminateHandler = std::set_terminate(&TerminateHandler); + } + + ++m_exceptionCount; + m_lastException = exception; + } + + static void UnRef(Exception* e) + { + if (m_lastException == e) { + m_lastException = NULL; + } + + --m_exceptionCount; + + if (!m_exceptionCount) { + std::set_terminate(m_terminateHandler); + m_terminateHandler = NULL; + } + } + + static void TerminateHandler() + { + if (m_lastException != NULL) { + DisplayKnownException(*m_lastException); + abort(); + } else { + DisplayUnknownException(); + abort(); + } + } + + Exception *m_reason; + std::string m_path; + std::string m_function; + int m_line; + + protected: + std::string m_message; + std::string m_className; + + public: + static std::string KnownExceptionToString(const Exception &e) + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled DPL exception occurred ===\033[m\n\n"; + message << "\033[1;33mException trace:\033[m\n\n"; + message << e.DumpToString(); + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static std::string UnknownExceptionToString() + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled non-DPL exception occurred ===\033[m\n\n"; + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static void DisplayKnownException(const Exception& e) + { + LogUnhandledException(KnownExceptionToString(e).c_str()); + } + + static void DisplayUnknownException() + { + LogUnhandledException(UnknownExceptionToString().c_str()); + } + + Exception(const Exception &other) + { + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + } + + const Exception &operator =(const Exception &other) + { + if (this == &other) { + return *this; + } + + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + + return *this; + } + + Exception(const char *path, + const char *function, + int line, + const std::string &message) : + m_reason(NULL), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + Exception(const char *path, + const char *function, + int line, + const Exception &reason, + const std::string &message) : + m_reason(new Exception(reason)), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + virtual ~Exception() throw() + { + if (m_reason != NULL) { + delete m_reason; + m_reason = NULL; + } + + UnRef(this); + } + + void Dump() const + { + // Show reason first + if (m_reason != NULL) { + m_reason->Dump(); + } + + // Afterward, dump exception + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + printf("\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "" : m_message.c_str()); + } + + std::string DumpToString() const + { + std::string ret; + if (m_reason != NULL) { + ret = m_reason->DumpToString(); + } + + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + char buf[1024]; + snprintf(buf, + sizeof(buf), + "\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, + m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "" : m_message.c_str()); + + buf[sizeof(buf) - 1] = '\n'; + ret += buf; + + return ret; + } + + Exception *GetReason() const + { + return m_reason; + } + + std::string GetPath() const + { + return m_path; + } + + std::string GetFunction() const + { + return m_function; + } + + int GetLine() const + { + return m_line; + } + + std::string GetMessage() const + { + return m_message; + } + + std::string GetClassName() const + { + return m_className; + } +}; +} // namespace DPL + +#define Try try + +#define Throw(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__) + +#define ThrowMsg(ClassName, Message) \ + do \ + { \ + std::ostringstream dplLoggingStream; \ + dplLoggingStream << Message; \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, dplLoggingStream.str()); \ + } while (0) + +#define ReThrow(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception) + +#define ReThrowMsg(ClassName, Message) \ + throw ClassName(__FILE__, \ + __FUNCTION__, \ + __LINE__, \ + _rethrown_exception, \ + Message) + +#define Catch(ClassName) \ + catch (const ClassName &_rethrown_exception) + +#define DECLARE_EXCEPTION_TYPE(BaseClass, Class) \ + class Class : \ + public BaseClass \ + { \ + public: \ + Class(const char *path, \ + const char *function, \ + int line, \ + const std::string & message = std::string()) : \ + BaseClass(path, function, line, message) \ + { \ + BaseClass::m_className = #Class; \ + } \ + \ + Class(const char *path, \ + const char *function, \ + int line, \ + const DPL::Exception & reason, \ + const std::string & message = std::string()) : \ + BaseClass(path, function, line, reason, message) \ + { \ + BaseClass::m_className = #Class; \ + } \ + }; + +#define UNHANDLED_EXCEPTION_HANDLER_BEGIN try + +#define UNHANDLED_EXCEPTION_HANDLER_END \ + catch (const DPL::Exception &exception) \ + { \ + std::ostringstream msg; \ + msg << DPL::Exception::KnownExceptionToString(exception); \ + DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + catch (std::exception& e) \ + { \ + std::ostringstream msg; \ + msg << e.what(); \ + msg << "\n"; \ + msg << DPL::Exception::UnknownExceptionToString(); \ + DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + catch (...) \ + { \ + std::ostringstream msg; \ + msg << DPL::Exception::UnknownExceptionToString(); \ + DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } + +namespace DPL { +namespace CommonException { +/** + * Internal exception definitions + * + * These should normally not happen. + * Usually, exception trace with internal error includes + * important messages. + */ +DECLARE_EXCEPTION_TYPE(Exception, InternalError) ///< Unexpected error from + // underlying libraries or + // kernel +} +} + +#endif // DPL_EXCEPTION_H diff --git a/modules/core/include/dpl/file_input.h b/modules/core/include/dpl/file_input.h new file mode 100644 index 0000000..3adcf21 --- /dev/null +++ b/modules/core/include/dpl/file_input.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file file_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of file input + */ +#ifndef DPL_FILE_INPUT_H +#define DPL_FILE_INPUT_H + +#include +#include +#include + +namespace DPL { +class FileInput : + private Noncopyable, + public AbstractWaitableInput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) + }; + + protected: + int m_fd; + + public: + FileInput(); + FileInput(const std::string &fileName); + virtual ~FileInput(); + + void Open(const std::string &fileName); + void Close(); + + // AbstractInput + virtual BinaryQueueAutoPtr Read(size_t size); + + // AbstractWaitableInput + virtual WaitableHandle WaitableReadHandle() const; +}; +} // namespace DPL + +#endif // DPL_FILE_INPUT_H diff --git a/modules/core/include/dpl/file_output.h b/modules/core/include/dpl/file_output.h new file mode 100644 index 0000000..90be8cd --- /dev/null +++ b/modules/core/include/dpl/file_output.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file file_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of file output + */ +#ifndef DPL_FILE_OUTPUT_H +#define DPL_FILE_OUTPUT_H + +#include +#include +#include + +namespace DPL { +class FileOutput : + private Noncopyable, + public AbstractWaitableOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) + }; + + protected: + int m_fd; + + public: + FileOutput(); + FileOutput(const std::string &fileName); + virtual ~FileOutput(); + + void Open(const std::string &fileName); + void Close(); + + // AbstractOutput + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize); + + // AbstracWaitableOutput + virtual WaitableHandle WaitableWriteHandle() const; +}; +} // namespace DPL + +#endif // DPL_FILE_OUTPUT_H diff --git a/modules/core/include/dpl/foreach.h b/modules/core/include/dpl/foreach.h new file mode 100644 index 0000000..bbe477a --- /dev/null +++ b/modules/core/include/dpl/foreach.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file foreach.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of foreach macro for stl + * containers + */ +#ifndef DPL_FOREACH_H +#define DPL_FOREACH_H + +#include + +namespace DPL { +namespace Private { +/* + * Used to detect type of valid reference to value object. + */ +template +T& ValueReference(T& t) +{ + return(t); +} + +template +const T& ValueReference(const T& t) +{ + return(t); +} +} //Private +} //DPL + +#define DPL_FOREACH_IMPL(temporaryName, iterator, container) \ + __typeof__ (DPL::Private::ValueReference((container))) & \ + temporaryName = (container); \ + for (__typeof__ (temporaryName.begin())iterator = \ + temporaryName.begin(); \ + (iterator) != temporaryName.end(); ++iterator) + +#define FOREACH(iterator, container) \ + DPL_FOREACH_IMPL( \ + DPL_MACRO_CONCAT(foreachContainerReference, __COUNTER__), \ + iterator, \ + container) + +#endif // DPL_FOREACH_H diff --git a/modules/core/include/dpl/framework_appcore.h b/modules/core/include/dpl/framework_appcore.h new file mode 100644 index 0000000..d076ddc --- /dev/null +++ b/modules/core/include/dpl/framework_appcore.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file framework_appcore.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the forward header file for APPCORE framework + */ +#pragma GCC system_header +#include diff --git a/modules/core/include/dpl/framework_efl.h b/modules/core/include/dpl/framework_efl.h new file mode 100644 index 0000000..6246587 --- /dev/null +++ b/modules/core/include/dpl/framework_efl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file framework_efl.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the forward header file for EFL framework + */ +#pragma GCC system_header +#include +#include +#include diff --git a/modules/core/include/dpl/framework_vconf.h b/modules/core/include/dpl/framework_vconf.h new file mode 100644 index 0000000..8de9b31 --- /dev/null +++ b/modules/core/include/dpl/framework_vconf.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file framework_vconf.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the forward header file for VCONF + */ +#pragma GCC system_header +#include +#include diff --git a/modules/core/include/dpl/generic_event.h b/modules/core/include/dpl/generic_event.h new file mode 100644 index 0000000..b20d913 --- /dev/null +++ b/modules/core/include/dpl/generic_event.h @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_event.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC generic event + */ +#ifndef DPL_GENERIC_EVENT_H +#define DPL_GENERIC_EVENT_H + +namespace DPL { +class EventSender +{ + public: + explicit EventSender(void *sender) : + m_sender(sender) + {} + + void* GetSender() const + { + return m_sender; + } + + private: + void *m_sender; +}; + +class GenericEvent +{ + protected: + void *m_sender; + + public: + explicit GenericEvent(const EventSender &sender) : + m_sender(sender.GetSender()) + {} + + virtual ~GenericEvent() + {} + + void *GetSender() const + { + return m_sender; + } +}; + +class GenericEvent0 : + public GenericEvent +{ + public: + explicit GenericEvent0(const EventSender &sender) : + GenericEvent(sender) + {} + + virtual ~GenericEvent0() + {} +}; + +template +class GenericEvent1 : + public GenericEvent0 +{ + public: + typedef Arg0Type Arg0; + + protected: + Arg0 m_arg0; + + public: + explicit GenericEvent1(const EventSender &sender) : + GenericEvent0(sender) + {} + + GenericEvent1(Arg0 arg0, const EventSender &sender) : + GenericEvent0(sender), + m_arg0(arg0) + {} + + virtual ~GenericEvent1() + {} + + Arg0 GetArg0() const + { + return m_arg0; + } +}; + +template +class GenericEvent2 : + public GenericEvent1 +{ + public: + typedef Arg0Type Arg0; + typedef Arg1Type Arg1; + + protected: + Arg1 m_arg1; + + public: + explicit GenericEvent2(const EventSender &sender) : + GenericEvent1(sender) + {} + + GenericEvent2(Arg0 arg0, Arg1 arg1, const EventSender &sender) : + GenericEvent1(arg0, sender), + m_arg1(arg1) + {} + + virtual ~GenericEvent2() + {} + + Arg1 GetArg1() const + { + return m_arg1; + } +}; + +template +class GenericEvent3 : + public GenericEvent2 +{ + public: + typedef Arg0Type Arg0; + typedef Arg1Type Arg1; + typedef Arg2Type Arg2; + + protected: + Arg2 m_arg2; + + public: + explicit GenericEvent3(const EventSender &sender) : + GenericEvent2(sender) + {} + + GenericEvent3(Arg0 arg0, Arg1 arg1, Arg2 arg2, const EventSender &sender) : + GenericEvent2(arg0, arg1, sender), + m_arg2(arg2) + {} + + virtual ~GenericEvent3() + {} + + Arg2 GetArg2() const + { + return m_arg2; + } +}; + +template +class GenericEvent4 : + public GenericEvent3 +{ + public: + typedef Arg0Type Arg0; + typedef Arg1Type Arg1; + typedef Arg2Type Arg2; + typedef Arg3Type Arg3; + + protected: + Arg3 m_arg3; + + public: + explicit GenericEvent4(const EventSender &sender) : + GenericEvent3(sender) + {} + + GenericEvent4(Arg0 arg0, + Arg1 arg1, + Arg2 arg2, + Arg3 arg3, + const EventSender &sender) : + GenericEvent3(arg0, arg1, arg2, sender), + m_arg3(arg3) + {} + + virtual ~GenericEvent4() + {} + + Arg3 GetArg3() const + { + return m_arg3; + } +}; + +template +class GenericEvent5 : + public GenericEvent4 +{ + public: + typedef Arg0Type Arg0; + typedef Arg1Type Arg1; + typedef Arg2Type Arg2; + typedef Arg3Type Arg3; + typedef Arg4Type Arg4; + + protected: + Arg4 m_arg4; + + public: + explicit GenericEvent5(const EventSender &sender) : + GenericEvent4(sender) + {} + + GenericEvent5(Arg0 arg0, + Arg1 arg1, + Arg2 arg2, + Arg3 arg3, + Arg4 arg4, + const EventSender &sender) : + GenericEvent4(arg0, arg1, arg2, + arg3, sender), + m_arg4(arg4) + {} + + virtual ~GenericEvent5() + {} + + Arg4 GetArg4() const + { + return m_arg4; + } +}; + +template +class GenericEvent6 : + public GenericEvent5 +{ + public: + typedef Arg0Type Arg0; + typedef Arg1Type Arg1; + typedef Arg2Type Arg2; + typedef Arg3Type Arg3; + typedef Arg4Type Arg4; + typedef Arg5Type Arg5; + + protected: + Arg5 m_arg5; + + public: + explicit GenericEvent6(const EventSender &sender) : + GenericEvent5(sender) + {} + + GenericEvent6(Arg0 arg0, + Arg1 arg1, + Arg2 arg2, + Arg3 arg3, + Arg4 arg4, + Arg5 arg5, + const EventSender &sender) : + GenericEvent5(arg0, + arg1, + arg2, + arg3, + arg4, + sender), + m_arg5(arg5) + {} + + virtual ~GenericEvent6() + {} + + Arg5 GetArg5() const + { + return m_arg5; + } +}; + +template +class GenericEvent7 : + public GenericEvent6 +{ + public: + typedef Arg0Type Arg0; + typedef Arg1Type Arg1; + typedef Arg2Type Arg2; + typedef Arg3Type Arg3; + typedef Arg4Type Arg4; + typedef Arg5Type Arg5; + typedef Arg6Type Arg6; + + protected: + Arg6 m_arg6; + + public: + explicit GenericEvent7(const EventSender &sender) : + GenericEvent6(sender) + {} + + GenericEvent7(Arg0 arg0, + Arg1 arg1, + Arg2 arg2, + Arg3 arg3, + Arg4 arg4, + Arg5 arg5, + Arg6 arg6, + const EventSender &sender) : + GenericEvent6(arg0, arg1, arg2, arg3, arg4, arg5, sender), + m_arg6(arg6) + {} + + virtual ~GenericEvent7() + {} + + Arg6 GetArg6() const + { + return m_arg6; + } +}; + +template +class GenericEvent8 : + public GenericEvent7 +{ + public: + typedef Arg0Type Arg0; + typedef Arg1Type Arg1; + typedef Arg2Type Arg2; + typedef Arg3Type Arg3; + typedef Arg4Type Arg4; + typedef Arg5Type Arg5; + typedef Arg6Type Arg6; + typedef Arg7Type Arg7; + + protected: + Arg7 m_arg7; + + public: + explicit GenericEvent8(const EventSender &sender) : + GenericEvent7(sender) + {} + + GenericEvent8(Arg0 arg0, + Arg1 arg1, + Arg2 arg2, + Arg3 arg3, + Arg4 arg4, + Arg5 arg5, + Arg6 arg6, + Arg7 arg7, + const EventSender &sender) : + GenericEvent7(arg0, arg1, arg2, arg3, arg4, arg5, + arg6, sender), + m_arg7(arg7) + {} + + virtual ~GenericEvent8() + {} + + Arg7 GetArg7() const + { + return m_arg7; + } +}; +} // namespace DPL + +#define DECLARE_GENERIC_EVENT_0(ClassName) \ + class ClassName : \ + public DPL::GenericEvent0 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent0(sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_1(ClassName, Arg0Type) \ + class ClassName : \ + public DPL::GenericEvent1 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent1(sender) \ + { \ + } \ + \ + explicit ClassName(Arg0Type arg0, \ + const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent1(arg0, sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_2(ClassName, Arg0Type, Arg1Type) \ + class ClassName : \ + public DPL::GenericEvent2 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent2(sender) \ + { \ + } \ + \ + ClassName(Arg0Type arg0, Arg1Type arg1, \ + const DPL::EventSender & sender = DPL::EventSender(NULL)) : \ + DPL::GenericEvent2(arg0, arg1, sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_3(ClassName, Arg0Type, Arg1Type, Arg2Type) \ + class ClassName : \ + public DPL::GenericEvent3 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent3(sender) \ + { \ + } \ + \ + ClassName(Arg0Type arg0, Arg1Type arg1, Arg2Type arg2, \ + const DPL::EventSender & sender = DPL::EventSender(NULL)) : \ + DPL::GenericEvent3(arg0, \ + arg1, \ + arg2, \ + sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_4(ClassName, \ + Arg0Type, \ + Arg1Type, \ + Arg2Type, \ + Arg3Type) \ + class ClassName : \ + public DPL::GenericEvent4 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent4(sender) \ + { \ + } \ + \ + ClassName(Arg0Type arg0, Arg1Type arg1, Arg2Type arg2, Arg3Type arg3, \ + const DPL::EventSender & sender = DPL::EventSender(NULL)) : \ + DPL::GenericEvent4(arg0, \ + arg1, \ + arg2, \ + arg3, \ + sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_5(ClassName, \ + Arg0Type, \ + Arg1Type, \ + Arg2Type, \ + Arg3Type, \ + Arg4Type) \ + class ClassName : \ + public DPL::GenericEvent5 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent5( \ + sender) \ + { \ + } \ + \ + ClassName(Arg0Type arg0, \ + Arg1Type arg1, \ + Arg2Type arg2, \ + Arg3Type arg3, \ + Arg4Type arg4, \ + const DPL::EventSender & sender = DPL::EventSender(NULL)) : \ + DPL::GenericEvent5( \ + arg0, \ + arg1, \ + arg2, \ + arg3, \ + arg4, \ + sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_6(ClassName, \ + Arg0Type, \ + Arg1Type, \ + Arg2Type, \ + Arg3Type, \ + Arg4Type, \ + Arg5Type) \ + class ClassName : \ + public DPL::GenericEvent6 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent6(sender) \ + { \ + } \ + \ + ClassName(Arg0Type arg0, \ + Arg1Type arg1, \ + Arg2Type arg2, \ + Arg3Type arg3, \ + Arg4Type arg4, \ + Arg5Type arg5, \ + const DPL::EventSender & sender = DPL::EventSender(NULL)) : \ + DPL::GenericEvent6(arg0, \ + arg1, \ + arg2, \ + arg3, \ + arg4, \ + arg5, \ + sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_7(ClassName, \ + Arg0Type, \ + Arg1Type, \ + Arg2Type, \ + Arg3Type, \ + Arg4Type, \ + Arg5Type, \ + Arg6Type) \ + class ClassName : \ + public DPL::GenericEvent7 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent7(sender) \ + { \ + } \ + \ + ClassName(Arg0Type arg0, \ + Arg1Type arg1, \ + Arg2Type arg2, \ + Arg3Type arg3, \ + Arg4Type arg4, \ + Arg5Type arg5, \ + Arg6Type arg6, \ + const DPL::EventSender & sender = DPL::EventSender(NULL)) : \ + DPL::GenericEvent7(arg0, \ + arg1, \ + arg2, \ + arg3, \ + arg4, \ + arg5, \ + arg6, \ + sender) \ + { \ + } \ + }; + +#define DECLARE_GENERIC_EVENT_8(ClassName, \ + Arg0Type, \ + Arg1Type, \ + Arg2Type, \ + Arg3Type, \ + Arg4Type, \ + Arg5Type, \ + Arg6Type, \ + Arg7Type) \ + class ClassName : \ + public DPL::GenericEvent8 \ + { \ + public: \ + explicit ClassName(const DPL::EventSender & sender = \ + DPL::EventSender(NULL)) : \ + DPL::GenericEvent8(sender) \ + { \ + } \ + \ + ClassName(Arg0Type arg0, \ + Arg1Type arg1, \ + Arg2Type arg2, \ + Arg3Type arg3, \ + Arg4Type arg4, \ + Arg5Type arg5, \ + Arg6Type arg6, \ + Arg7Type arg7, \ + const DPL::EventSender & sender = DPL::EventSender(NULL)) : \ + DPL::GenericEvent8(arg0, \ + arg1, \ + arg2, \ + arg3, \ + arg4, \ + arg5, \ + arg6, \ + arg7, \ + sender) \ + { \ + } \ + }; + +#endif // DPL_GENERIC_EVENT_H diff --git a/modules/core/include/dpl/lexical_cast.h b/modules/core/include/dpl/lexical_cast.h new file mode 100644 index 0000000..1b54026 --- /dev/null +++ b/modules/core/include/dpl/lexical_cast.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file lexical_cast.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for lexical cast + */ +#ifndef DPL_LEXICAL_CAST_H +#define DPL_LEXICAL_CAST_H + +#include + +namespace DPL { +template +TargetType lexical_cast(const SourceType &data) +{ + TargetType result; + + std::ostringstream out; + out << data; + + std::istringstream in(out.str()); + in >> result; + + return result; +} +} // namespace DPL + +#endif // DPL_LEXICAL_CAST_H diff --git a/modules/core/include/dpl/main.h b/modules/core/include/dpl/main.h new file mode 100644 index 0000000..cb088cf --- /dev/null +++ b/modules/core/include/dpl/main.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main for EFL + */ +#ifndef DPL_MAIN_H +#define DPL_MAIN_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +class Main : + public WaitableHandleWatchSupport +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + }; + + protected: + Ecore_Fd_Handler *m_invokerHandler; + + static Eina_Bool StaticDispatchInvoker(void *data, + Ecore_Fd_Handler *fd_handler); + static Eina_Bool StaticDispatchReadWatcher(void *data, + Ecore_Fd_Handler *fd_handler); + static Eina_Bool StaticDispatchWriteWatcher(void *data, + Ecore_Fd_Handler *fd_handler); + + typedef std::list EcoreFdHandlerList; + + EcoreFdHandlerList m_readWatchersList; + EcoreFdHandlerList m_writeWatchersList; + + void DispatchInvoker(); + void DispatchReadWatcher(WaitableHandle waitableHandle); + void DispatchWriteWatcher(WaitableHandle waitableHandle); + + void ReloadWatchList(); + + // WaitableHandleWatchSupport + virtual Thread *GetInvokerThread(); + virtual void HandleDirectInvoker(); + +#ifdef DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND + // GLIB loop intergration workaround + typedef int (*EcoreSelectType)(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout); + EcoreSelectType m_oldEcoreSelect; + + static int EcoreSelectInterceptor(int nfds, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout); +#endif // DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND + + public: + explicit Main(); + virtual ~Main(); +}; + +/** + * Main singleton + */ +typedef Singleton

MainSingleton; +} // namespace DPL + +#endif // DPL_MAIN_H diff --git a/modules/core/include/dpl/mutable_task_list.h b/modules/core/include/dpl/mutable_task_list.h new file mode 100644 index 0000000..9facbd3 --- /dev/null +++ b/modules/core/include/dpl/mutable_task_list.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file mutable_task_list.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief Header file for task list + */ +#ifndef DPL_MUTABLE_TASK_LIST_H +#define DPL_MUTABLE_TASK_LIST_H + +#include +#include + +namespace DPL { +class MutableTaskList : + public Task +{ + private: + typedef std::list Tasks; + + Tasks m_tasks; + Tasks::iterator m_currentTask; + + bool m_running; + + protected: + void AddTask(Task *task); + + public: + MutableTaskList(); + virtual ~MutableTaskList(); + + bool NextStep(); + bool Abort(); + size_t GetStepCount() const; +}; +} // namespace DPL + +#endif // DPL_MUTABLE_TASK_LIST_H diff --git a/modules/core/include/dpl/mutex.h b/modules/core/include/dpl/mutex.h new file mode 100644 index 0000000..315a92c --- /dev/null +++ b/modules/core/include/dpl/mutex.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file mutex.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of mutex + */ +#ifndef DPL_MUTEX_H +#define DPL_MUTEX_H + +#include +#include +#include + +namespace DPL { +class Mutex : + private Noncopyable +{ + public: + class ScopedLock : + private Noncopyable + { + private: + Mutex *m_mutex; + + public: + explicit ScopedLock(Mutex *mutex); + ~ScopedLock(); + }; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, LockFailed) + DECLARE_EXCEPTION_TYPE(Base, UnlockFailed) + }; + + private: + mutable pthread_mutex_t m_mutex; + + void Lock() const; + void Unlock() const; + + public: + Mutex(); + ~Mutex(); +}; +} // namespace DPL + +#endif // DPL_MUTEX_H diff --git a/modules/core/include/dpl/named_base_pipe.h b/modules/core/include/dpl/named_base_pipe.h new file mode 100644 index 0000000..45714ef --- /dev/null +++ b/modules/core/include/dpl/named_base_pipe.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file named_base_pipe.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of named base pipe + */ +#ifndef DPL_NAMED_BASE_PIPE_H +#define DPL_NAMED_BASE_PIPE_H + +#include + +namespace DPL { +class NamedBasePipe +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, AlreadyExist) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, DestroyFailed) + }; + + public: + virtual ~NamedBasePipe(); + + static void Create(const std::string &fileName); + static void Destroy(const std::string &fileName); +}; +} // namespace DPL + +#endif // DPL_NAMED_BASE_PIPE_H diff --git a/modules/core/include/dpl/named_input_pipe.h b/modules/core/include/dpl/named_input_pipe.h new file mode 100644 index 0000000..cf7b4b7 --- /dev/null +++ b/modules/core/include/dpl/named_input_pipe.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file named_input_pipe.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of named input pipe + */ +#ifndef DPL_NAMED_PIPE_H +#define DPL_NAMED_PIPE_H + +#include +#include +#include + +namespace DPL { +class NamedInputPipe : + public NamedBasePipe, + public FileInput +{}; +} // namespace DPL + +#endif // DPL_NAMED_PIPE_H diff --git a/modules/core/include/dpl/named_output_pipe.h b/modules/core/include/dpl/named_output_pipe.h new file mode 100644 index 0000000..573d1d2 --- /dev/null +++ b/modules/core/include/dpl/named_output_pipe.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file named_output_pipe.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of named output pipe + */ +#ifndef DPL_NAMED_OUTPUT_PIPE_H +#define DPL_NAMED_OUTPUT_PIPE_H + +#include +#include +#include +#include + +namespace DPL { +class NamedOutputPipe : + private Noncopyable, + public NamedBasePipe, + public AbstractWaitableOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) + }; + + protected: + int m_fifo; + + public: + NamedOutputPipe(); + virtual ~NamedOutputPipe(); + + void Open(const std::string &fileName); + void Close(); + + // AbstractOutput + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize); + + // AbstracWaitableOutput + virtual WaitableHandle WaitableWriteHandle() const; +}; +} // namespace DPL + +#endif // DPL_NAMED_OUTPUT_PIPE_H diff --git a/modules/core/include/dpl/noncopyable.h b/modules/core/include/dpl/noncopyable.h new file mode 100644 index 0000000..98d57dd --- /dev/null +++ b/modules/core/include/dpl/noncopyable.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#ifndef DPL_NONCOPYABLE_H +#define DPL_NONCOPYABLE_H + +namespace DPL { +class Noncopyable +{ + private: + Noncopyable(const Noncopyable &); + const Noncopyable &operator=(const Noncopyable &); + + public: + Noncopyable(); + virtual ~Noncopyable(); +}; +} // namespace DPL + +#endif // DPL_NONCOPYABLE_H diff --git a/modules/core/include/dpl/once.h b/modules/core/include/dpl/once.h new file mode 100644 index 0000000..ab3710f --- /dev/null +++ b/modules/core/include/dpl/once.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file once.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of once + */ +#ifndef DPL_ONCE_H +#define DPL_ONCE_H + +#include +#include +#include +#include + +namespace DPL { +class Once : + private Noncopyable +{ + public: + typedef std::function Delegate; + + void Call(Delegate delegate); + + private: + Atomic m_atomic; + Mutex m_mutex; +}; +} // namespace DPL + +#endif // DPL_ONCE_H diff --git a/modules/core/include/dpl/optional.h b/modules/core/include/dpl/optional.h new file mode 100644 index 0000000..d1ec5f3 --- /dev/null +++ b/modules/core/include/dpl/optional.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file optional_value.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + */ + +#ifndef DPL_OPTIONAL_H +#define DPL_OPTIONAL_H + +#include +#include + +namespace DPL { +template +class Optional +{ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, NullReference) + }; + + public: + Optional() : + m_null(true), + m_value() + {} + + Optional(const Type& t) : + m_null(false), + m_value(t) + {} + + bool IsNull() const + { + return m_null; + } + + Type& operator*() + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return m_value; + } + + const Type& operator*() const + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return m_value; + } + + const Type* operator->() const + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return &m_value; + } + + Type* operator->() + { + if (m_null) { + Throw(typename Exception::NullReference); + } + return &m_value; + } + + bool operator!() const + { + return m_null; + } + + Optional& operator=(const Type& other) + { + m_null = false; + m_value = other; + return *this; + } + + bool operator==(const Optional& aSecond) const + { + return LogicalOperator(*this, aSecond, + std::equal_to(), std::equal_to()); + } + + bool operator==(const Type& aSecond) const + { + return Optional(aSecond) == *this; + } + + bool operator!=(const Optional& aSecond) const + { + return !(*this == aSecond); + } + + bool operator<(const Optional& aSecond) const + { + return LogicalOperator(*this, aSecond, + std::less(), std::less()); + } + + bool operator>(const Optional& aSecond) const + { + return LogicalOperator(*this, aSecond, + std::greater(), std::greater()); + } + + bool operator<=(const Optional& aSecond) const + { + return *this == aSecond || *this < aSecond; + } + + bool operator>=(const Optional& aSecond) const + { + return *this == aSecond || *this > aSecond; + } + + static Optional Null; + + private: + bool m_null; + Type m_value; + + template + static bool LogicalOperator(const Optional& aFirst, + const Optional& aSecond, + taComparator aComparator, + taNullComparator aNullComparator) + { + if (aFirst.m_null == aSecond.m_null) { + if (aFirst.m_null) { + return taEquality; + } else { + return aComparator(aFirst.m_value, aSecond.m_value); + } + } else { + return aNullComparator(aFirst.m_null, aSecond.m_null); + } + } +} DPL_DEPRECATED_WITH_MESSAGE("Use boost::optional instead"); + +template +Optional Optional::Null = Optional(); +} //namespace DPL + +template +std::ostream& operator<<(std::ostream& aStream, + const DPL::Optional& aOptional) +{ + if (aOptional.IsNull()) { + return aStream << "null optional"; + } else { + return aStream << *aOptional; + } +} + +#endif // DPL_OPTIONAL_VALUE_H diff --git a/modules/core/include/dpl/optional_typedefs.h b/modules/core/include/dpl/optional_typedefs.h new file mode 100644 index 0000000..8b56b4c --- /dev/null +++ b/modules/core/include/dpl/optional_typedefs.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DPL_OPTIONAL_TYPEDEFS_H +#define DPL_OPTIONAL_TYPEDEFS_H + +#include +#include +#include + +namespace DPL { +typedef Optional OptionalString; +typedef Optional OptionalInt; +typedef Optional OptionalUInt; +typedef Optional OptionalBool; +typedef Optional OptionalFloat; +typedef Optional OptionalStdString; +} //namespace DPL + +#endif /* DPL_OPTIONAL_TYPEDEFS_H */ + diff --git a/modules/core/include/dpl/platform.h b/modules/core/include/dpl/platform.h new file mode 100644 index 0000000..d910f5c --- /dev/null +++ b/modules/core/include/dpl/platform.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file platform.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + */ +#ifndef DPL_PLATFORM_H +#define DPL_PLATFORM_H + +// Use Features definition +// Use a particular optional platform service or third-party library +// +// Description : +// +// Author : () - +// #define USE__ (0 or 1) +#define USE(FEATURE) (defined (USE_##FEATURE) && USE_##FEATURE) + +// Description : Application side patch to use manual rotation feature in webkit +// Author : Jihoon Chung(jihoon.chung@samsung.com) - 10.26.2013 +#define USE_WEBKIT_MANUAL_ROTATION 1 + +// Description : Temporary patch about enable/disable webapp specific settings, especially for web-provider. +// Author : Jihoon Chung(jihoon.chung@samsung.com) - 11.09.2013 +#define USE_WEB_PROVIDER_EXCEPTION_IN_EWK_CONTEXT 1 + +// Description : Enhanced "progress bar" user experience. +// Show "progress bar" in "load,started" webkit callback to show earlier. +// Confirmed by webkit loader team. +// Author : Jihoon Chung(jihoon.chung@samsung.com) - 11.21.2013 +#define USE_WEBKIT_SHOW_PROGRESS_BAR_EARLIER 1 + +// Description : Webkit version-up +// Author : Jihoon Chung(jihoon.chung@samsung.com) - 01.14.2013 +#define USE_WEBKIT_UPVERSION 0 + +// Description : Support web-provider +// Livebox for webapp is valid in the platform depends on home screen. +// Author : Jihoon Chung(jihoon.chung@samsung.com) - 05.23.2014 +#define USE_WEB_PROVIDER 1 + +// Enable Features definition +// Turn on a specific feature of WRT +// +// Description : +// +// Author : () - +// #define ENABLE_ (0 or 1) +#define ENABLE(FEATURE) (defined (ENABLE_##FEATURE) && ENABLE_##FEATURE) + +// Description : Support onbeforeunload event +// Author : Jihoon Chung(jihoon.chung@samsung.com) - 11.15.2013 +#define ENABLE_JAVASCRIPT_ONBEFOREUNLOAD_EVENT 0 + +// Description : Support app scheme(app://) +// App scheme(app://) supports special scheme to packaged resources. +// Main reason of requirement is that enhance cross origin security and deprecate file scheme(file://). +// Author : Tomasz Iwanek(t.iwanek@samsung.com) - 11.16.2013 +#define ENABLE_APP_SCHEME 0 + +// Description : Custom user agent support by tizen widget setting +// Author : Tae-Jeong Lee (taejeong.lee@samsung.com) - 11.26.2013 +#define ENABLE_CUSTOM_USER_AGENT_SUPPORT 0 + +// Description : Support CORS(Cross-origin resource sharing) whitelisting +// Allow to use resource by trust origin. Basically, trust domain includes own app scheme(app://). +// Author : Tomasz Iwanek(t.iwanek@samsung.com) - 01.02.2014 +#define ENABLE_CORS_WHITELISTING 0 + +// Description : Support CSP(Content security policy) +// Author : Tomasz Iwanek(t.iwanek@samsung.com) - 01.03.2014 +#define ENABLE_CONTENT_SECURITY_POLICY 1 + +// Description : Enabling background decryption for encrypted resources +// Author : Tomasz Iwanek(t.iwanek@samsung.com) - 16.12.2013 +#define ENABLE_BACKGROUND_THREAD_DECRYPTION 0 + +// Description : Support allow-navigation +// Origin based navigation control of main resource. +// Author : Jihoon Chung (jihoon.chung@samsung.com) - 01.08.2014 +#define ENABLE_ALLOW_NAVIGATION 1 + +// Description : Restrict Max Length of Config Element Attributes +// Wrt Installer restricts value of Element attributes' length to Maximum Length if defined. +// Author : Sankeerth V S (sankeerth.vs@samsung.com) - 03.09.2014 +#define ENABLE_ELEMENT_ATTR_MAX_LENGTH 1 + +// Description : Add Ellipsis at the end if element or attribute length exceeds the max allowed length +// as Wrt Installer restricts value of Element attributes' length to Maximum Length if defined. +// Author : Sankeerth V S (sankeerth.vs@samsung.com) / Lalit Arora (lalit.arora@samsung.com) - 01.11.2014 +#define ENABLE_ADD_ELLIPSIS 0 + +#endif // DPL_PLATFORM_H diff --git a/modules/core/include/dpl/preprocessor.h b/modules/core/include/dpl/preprocessor.h new file mode 100644 index 0000000..6fca34c --- /dev/null +++ b/modules/core/include/dpl/preprocessor.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file preprocessor.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file contains some usefull macros. + */ + +#ifndef DPL_PREPROCESSOR_H +#define DPL_PREPROCESSOR_H + +#define DPL_MACRO_CONCAT_IMPL(x, y) x##y +#define DPL_MACRO_CONCAT(x, y) DPL_MACRO_CONCAT_IMPL(x, y) + +#ifdef __COUNTER__ +#define DPL_ANONYMOUS_VARIABLE(name) DPL_MACRO_CONCAT(name, __COUNTER__) +#else +#define DPL_ANONYMOUS_VARIABLE(name) DPL_MACRO_CONCAT(name, __LINE__) +#endif + +#endif //DPL_PREPROCESSOR_H diff --git a/modules/core/include/dpl/read_write_mutex.h b/modules/core/include/dpl/read_write_mutex.h new file mode 100644 index 0000000..75d9f06 --- /dev/null +++ b/modules/core/include/dpl/read_write_mutex.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file read_write_mutex.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of read write mutex + */ +#ifndef DPL_READ_WRITE_MUTEX_H +#define DPL_READ_WRITE_MUTEX_H + +#include +#include +#include + +namespace DPL { +class ReadWriteMutex : + private Noncopyable +{ + public: + class ScopedReadLock : + private Noncopyable + { + private: + ReadWriteMutex *m_mutex; + + public: + ScopedReadLock(ReadWriteMutex *mutex); + virtual ~ScopedReadLock(); + }; + + class ScopedWriteLock : + private Noncopyable + { + private: + ReadWriteMutex *m_mutex; + + public: + ScopedWriteLock(ReadWriteMutex *mutex); + virtual ~ScopedWriteLock(); + }; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, DestroyFailed) + DECLARE_EXCEPTION_TYPE(Base, ReadLockFailed) + DECLARE_EXCEPTION_TYPE(Base, WriteLockFailed) + DECLARE_EXCEPTION_TYPE(Base, UnlockFailed) + }; + + private: + mutable pthread_rwlock_t m_rwlock; + + void ReadLock() const; + void WriteLock() const; + void Unlock() const; + + public: + explicit ReadWriteMutex(); + virtual ~ReadWriteMutex(); +}; +} // namespace DPL + +#endif // DPL_READ_WRITE_MUTEX_H diff --git a/modules/core/include/dpl/recursive_mutex.h b/modules/core/include/dpl/recursive_mutex.h new file mode 100644 index 0000000..e4744cc --- /dev/null +++ b/modules/core/include/dpl/recursive_mutex.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file recursive_mutex.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of recursive mutex + */ +#ifndef DPL_RECURSIVE_MUTEX_H +#define DPL_RECURSIVE_MUTEX_H + +#include +#include +#include + +namespace DPL { +class RecursiveMutex : + private Noncopyable +{ + public: + class ScopedLock : + private Noncopyable + { + private: + RecursiveMutex *m_mutex; + + public: + ScopedLock(RecursiveMutex *mutex); + virtual ~ScopedLock(); + }; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, DestroyFailed) + DECLARE_EXCEPTION_TYPE(Base, LockFailed) + DECLARE_EXCEPTION_TYPE(Base, UnlockFailed) + }; + + private: + mutable pthread_mutex_t m_mutex; + + void Lock() const; + void Unlock() const; + + public: + explicit RecursiveMutex(); + virtual ~RecursiveMutex(); +}; +} // namespace DPL + +#endif // DPL_RECURSIVE_MUTEX_H diff --git a/modules/core/include/dpl/scope_guard.h b/modules/core/include/dpl/scope_guard.h new file mode 100644 index 0000000..21a7b0c --- /dev/null +++ b/modules/core/include/dpl/scope_guard.h @@ -0,0 +1,111 @@ +/* + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scope_guard.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scope guard RAII + */ +#ifndef DPL_SCOPE_GUARD_H_ +#define DPL_SCOPE_GUARD_H_ + +#include +#include +#include +#include +#include + +namespace DPL { +template +class ScopeGuard +{ + public: + explicit ScopeGuard(const FunctionType& function) + : m_function{function}, + m_released{false} + {} + + explicit ScopeGuard(FunctionType&& function) + : m_function{std::move(function)}, + m_released{false} + {} + + ScopeGuard(ScopeGuard&& other) + : m_function{std::move(other.m_function)}, + m_released{other.m_released} + { + other.Release(); + } + + ScopeGuard(const ScopeGuard&) = delete; + + ~ScopeGuard() + { + if (!m_released) + { + Execute(); + } + } + + ScopeGuard& operator=(const ScopeGuard&) = delete; + + void Release() + { + m_released = true; + } + + void* operator new(size_t) = delete; + + private: + // FIXME change to noexcept when available + void Execute() throw() + { + m_function(); + } + + FunctionType m_function; + bool m_released; +}; + +template +inline ScopeGuard::type> +MakeScopeGuard(FunctionType&& function) +{ + return ScopeGuard::type>( + std::forward(function)); +} + +namespace detail { +enum class ScopeGuardOnExit {}; + +template +inline ScopeGuard::type> +operator+(detail::ScopeGuardOnExit, FunctionType&& function) +{ + return ScopeGuard::type>( + std::forward(function)); +} +} +} + +// FIXME provide support for compilers not supporting variadic macros; +// instead of using variadic macros (for compatibility) we could +// capture all by '&' (only referenced variables would be captured) +#define DPL_SCOPE_EXIT(...) \ + auto DPL_ANONYMOUS_VARIABLE(DPL_SCOPE_EXIT_STATE) \ + = ::DPL::detail::ScopeGuardOnExit() + [__VA_ARGS__]() + +#endif // DPL_SCOPE_GUARD_H_ diff --git a/modules/core/include/dpl/scoped_array.h b/modules/core/include/dpl/scoped_array.h new file mode 100644 index 0000000..1be91bd --- /dev/null +++ b/modules/core/include/dpl/scoped_array.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_ptr.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped array RAII + * + * This module is deprecated, please use standard C++11 feature: std::unique_ptr + */ +#ifndef DPL_SCOPED_ARRAY_H +#define DPL_SCOPED_ARRAY_H + +#include + +#include +#include +#include + +namespace DPL { +template +struct ScopedArrayPolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + delete[] ptr; + } +}; + +template +class ScopedArray : public ScopedResource > +{ + typedef ScopedArrayPolicy Policy; + typedef ScopedResource BaseType; + + public: + explicit ScopedArray(Class *ptr = Policy::NullValue()) : BaseType(ptr) { } + + Class &operator [](std::ptrdiff_t k) const + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL array!"); + Assert(k >= 0 && "Negative array index"); + + return this->m_value[k]; + } +} DPL_DEPRECATED_WITH_MESSAGE("use standard C++11 feature: std::unique_ptr"); +} // namespace DPL + +#endif // DPL_SCOPED_PTR_H diff --git a/modules/core/include/dpl/scoped_close.h b/modules/core/include/dpl/scoped_close.h new file mode 100644 index 0000000..45477af --- /dev/null +++ b/modules/core/include/dpl/scoped_close.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_close.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped close RAII + */ +#ifndef DPL_SCOPED_CLOSE_H +#define DPL_SCOPED_CLOSE_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +struct ScopedClosePolicy +{ + typedef int Type; + static Type NullValue() + { + return -1; + } + static void Destroy(Type handle) + { + if (handle != -1) { + if (TEMP_FAILURE_RETRY(::fsync(handle)) == -1) { + std::string errString = GetErrnoString(); + LogPedantic("Failed to fsync scoped close error: " + << errString); + } + + if (::close(handle) == -1) { + std::string errString = GetErrnoString(); + LogPedantic("Failed to scoped close error: " + << errString); + } + } + } +}; + +class ScopedClose : public ScopedResource +{ + typedef ScopedClosePolicy Policy; + typedef ScopedResource BaseType; + typedef ScopedClosePolicy::Type Type; + + public: + explicit ScopedClose(Type handle = Policy::NullValue()) : + BaseType(handle) + { } +}; +} // namespace DPL + +#endif // DPL_SCOPED_CLOSE_H diff --git a/modules/core/include/dpl/scoped_dir.h b/modules/core/include/dpl/scoped_dir.h new file mode 100644 index 0000000..b10b4cc --- /dev/null +++ b/modules/core/include/dpl/scoped_dir.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_dir.h + * @author Iwanek Tomasz (t.iwanek@smasung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped directory existence + */ + +#ifndef DPL_SCOPED_DIR_H +#define DPL_SCOPED_DIR_H + +#include +#include +#include +#include + +namespace DPL { + +struct ScopedDirPolicy +{ + typedef std::string Type; + static Type NullValue(); + static void Destroy(Type ptr); +}; + +class ScopedDir : public ScopedResource +{ + typedef ScopedDirPolicy Policy; + typedef ScopedResource BaseType; + + public: + explicit ScopedDir(const std::string & str = Policy::NullValue(), mode_t mode = S_IRWXU|S_IRGRP|S_IXGRP); +}; +} // namespace DPL + +#endif // DPL_SCOPED_DIR_H diff --git a/modules/core/include/dpl/scoped_fclose.h b/modules/core/include/dpl/scoped_fclose.h new file mode 100644 index 0000000..b029803 --- /dev/null +++ b/modules/core/include/dpl/scoped_fclose.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_fclose.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped fclose RAII + */ +#ifndef DPL_SCOPED_FCLOSE_H +#define DPL_SCOPED_FCLOSE_H + +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +struct ScopedFClosePolicy +{ + typedef FILE* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type file) + { + if (file != NULL) { + // Try to flush first + if (TEMP_FAILURE_RETRY(fflush(file)) != 0) { + std::string errString = GetErrnoString(); + LogPedantic("Failed to fflush scoped fclose error: " + << errString); + } + + // fclose cannot be retried, try to close once + if (fclose(file) != 0) { + std::string errString = GetErrnoString(); + LogPedantic("Failed scoped fclose error: " << errString); + } + } + } +}; + +class ScopedFClose : public ScopedResource +{ + typedef ScopedFClosePolicy Policy; + typedef ScopedResource BaseType; + + public: + explicit ScopedFClose(FILE* argFileStream = Policy::NullValue()) : + BaseType(argFileStream) + {} +}; +} // namespace DPL + +#endif // DPL_SCOPED_FCLOSE_H diff --git a/modules/core/include/dpl/scoped_free.h b/modules/core/include/dpl/scoped_free.h new file mode 100644 index 0000000..7bebe39 --- /dev/null +++ b/modules/core/include/dpl/scoped_free.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_free.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped free RAII + */ + +#ifndef DPL_SCOPED_FREE_H +#define DPL_SCOPED_FREE_H + +#include +#include + +#include + +namespace DPL { +template +struct ScopedFreePolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + free(ptr); + } +}; + +template +class ScopedFree : public ScopedResource > +{ + typedef ScopedFreePolicy Policy; + typedef ScopedResource BaseType; + + public: + explicit ScopedFree(Memory *ptr = Policy::NullValue()) : BaseType(ptr) { } +}; +} // namespace DPL + +#endif // DPL_SCOPED_FREE_H diff --git a/modules/core/include/dpl/scoped_gpointer.h b/modules/core/include/dpl/scoped_gpointer.h new file mode 100644 index 0000000..6ccfd9e --- /dev/null +++ b/modules/core/include/dpl/scoped_gpointer.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_gpointer.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped_gpointer + * + * This module is deprecated and may be removed in future. + */ + +#ifndef DPL_SCOPED_GPOINTER_H +#define DPL_SCOPED_GPOINTER_H + +#include +#include +#include +#include +#include + +namespace DPL { +struct ScopedGPointerPolicy +{ + typedef gpointer Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type pointer) + { + if (pointer != NULL) { + g_object_unref(pointer); + } + } +}; + +template +class ScopedGPointer : public DPL::ScopedResource +{ + typedef ScopedGPointerPolicy Policy; + typedef DPL::ScopedResource BaseType; + + public: + explicit ScopedGPointer(typename Policy::Type pointer = + Policy::NullValue()) : + BaseType(pointer) + {} + + Class *operator->() const throw() + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL pointer!"); + return static_cast(this->m_value); + } + + Class & operator *() const throw() + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL pointer!"); + return *static_cast(this->m_value); + } +} DPL_DEPRECATED; +} // namespace DPL + +#endif // DPL_SCOPED_GPOINTER_H diff --git a/modules/core/include/dpl/scoped_ptr.h b/modules/core/include/dpl/scoped_ptr.h new file mode 100644 index 0000000..0a2d01d --- /dev/null +++ b/modules/core/include/dpl/scoped_ptr.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file scoped_ptr.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped pointer RAII + * + * This module is deprecated, please use standard C++11 feature: std::unique_ptr + */ +#ifndef DPL_SCOPED_PTR_H +#define DPL_SCOPED_PTR_H + +#include + +#include +#include +#include + +namespace DPL { +template +struct ScopedPtrPolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + delete ptr; + } +}; + +template > +class ScopedPtr : public ScopedResource +{ + typedef ClassPolicy Policy; + typedef ScopedResource BaseType; + + public: + explicit ScopedPtr(Class *ptr = Policy::NullValue()) : BaseType(ptr) { } + + Class *operator->() const throw() + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL pointer!"); + return this->m_value; + } + + Class &operator *() const throw() + { + Assert(this->m_value != Policy::NullValue() && + "Dereference of scoped NULL pointer!"); + return *this->m_value; + } +} DPL_DEPRECATED_WITH_MESSAGE("use standard C++11 feature: std::unique_ptr"); +} // namespace DPL + +#endif // DPL_SCOPED_PTR_H diff --git a/modules/core/include/dpl/scoped_resource.h b/modules/core/include/dpl/scoped_resource.h new file mode 100644 index 0000000..63287da --- /dev/null +++ b/modules/core/include/dpl/scoped_resource.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file scoped_resource.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped resource pattern + */ +#ifndef DPL_SCOPED_RESOURCE_H +#define DPL_SCOPED_RESOURCE_H + +#include + +namespace DPL { +template +class ScopedResource : + private Noncopyable +{ + public: + typedef typename ClassPolicy::Type ValueType; + typedef ScopedResource ThisType; + + protected: + ValueType m_value; + + public: + explicit ScopedResource(ValueType value) : m_value(value) { } + + ~ScopedResource() + { + ClassPolicy::Destroy(m_value); + } + + ValueType Get() const + { + return m_value; + } + + void Reset(ValueType value = ClassPolicy::NullValue()) + { + ClassPolicy::Destroy(m_value); + m_value = value; + } + + ValueType Release() + { + ValueType value = m_value; + m_value = ClassPolicy::NullValue(); + return value; + } + typedef ValueType ThisType::*UnknownBoolType; + + operator UnknownBoolType() const + { + return m_value == ClassPolicy::NullValue() ? + 0 : //0 is valid here because it converts to false + &ThisType::m_value; //it converts to true + } + + bool operator !() const + { + return m_value == ClassPolicy::NullValue(); + } +}; +} // namespace DPL + +#endif // DPL_SCOPED_RESOURCE_H diff --git a/modules/core/include/dpl/semaphore.h b/modules/core/include/dpl/semaphore.h new file mode 100644 index 0000000..0505621 --- /dev/null +++ b/modules/core/include/dpl/semaphore.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file semaphore.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of semaphore + */ +#ifndef DPL_SEMAPHORE_H +#define DPL_SEMAPHORE_H + +#include +#include +#include +#include + +namespace DPL { +class Semaphore : + private Noncopyable +{ + public: + class ScopedLock : + private Noncopyable + { + private: + Semaphore *m_semaphore; + + public: + explicit ScopedLock(Semaphore *semaphore); + ~ScopedLock(); + }; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, LockFailed) + DECLARE_EXCEPTION_TYPE(Base, UnlockFailed) + DECLARE_EXCEPTION_TYPE(Base, RemoveFailed) + }; + + private: + enum Type + { + Type_Unnamed, + Type_Named + }; + + Type m_type; + + mutable union + { + struct + { + sem_t handle; + } unnamed; + + struct + { + sem_t *handle; + char *name; + bool unlinkOnDestroy; + } named; + } m_semaphore; + + sem_t *InternalGet() const; + void InternalDestroy(); + + public: + /** + * decrement the semaphore counter + */ + void Lock() const; + + /** + * increment the semaphore counter + */ + void Unlock() const; + + /** + * Remove a named semaphore + * + * @param fileName Name of the semaphore + */ + static void Remove(const std::string &fileName); + + /** + * Open an unnamed semaphore + * + * @param maxLockCount Maximum number of threads allowed to enter semaphore + */ + explicit Semaphore(size_t maxLockCount); + + /** + * Open a named semaphore + * + * @param fileName Semaphore filename + * @param allowCreate Should non-existing semaphore be created + * @param maxLockCount Maximum number of threads allowed to enter semaphore + * @param permissions Semaphore file permissions + * @param unlinkOnDestroy Should semaphore file be deleted on destruction + */ + explicit Semaphore(const std::string &fileName, + bool allowCreate = true, + bool exclusiveCreate = false, + size_t maxLockCount = 1, + int permissions = 0600, + bool unlinkOnDestroy = false); + + /** + * Destroy a semaphore + */ + ~Semaphore(); +}; +} // namespace DPL + +#endif // DPL_SEMAPHORE_H diff --git a/modules/core/include/dpl/serialization.h b/modules/core/include/dpl/serialization.h new file mode 100644 index 0000000..d72c488 --- /dev/null +++ b/modules/core/include/dpl/serialization.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file serialization.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Interfaces and templates used for data serialization. + */ +#ifndef SERIALIZATION_H +#define SERIALIZATION_H + +#include +#include +#include +#include + +namespace DPL { +// Abstract data stream buffer +class IStream +{ + public: + virtual void Read(size_t num, void * bytes) = 0; + virtual void Write(size_t num, const void * bytes) = 0; + virtual ~IStream(){} +}; + +// Serializable interface +class ISerializable +{ + public: + /* ISerializable(){}; + * ISerializable(IStream&){}; */ + virtual void Serialize(IStream &) const = 0; + virtual ~ISerializable(){} +}; + +struct Serialization { + // serialization + // normal functions + + // ISerializable objects + static void Serialize(IStream& stream, const ISerializable& object) + { + object.Serialize(stream); + } + static void Serialize(IStream& stream, const ISerializable* const object) + { + object->Serialize(stream); + } + + // unsigned int + static void Serialize(IStream& stream, const unsigned value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const unsigned* const value) + { + stream.Write(sizeof(*value), value); + } + + // int + static void Serialize(IStream& stream, const int value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const int* const value) + { + stream.Write(sizeof(*value), value); + } + + // bool + static void Serialize(IStream& stream, const bool value) + { + stream.Write(sizeof(value), &value); + } + static void Serialize(IStream& stream, const bool* const value) + { + stream.Write(sizeof(*value), value); + } + + // std::string + static void Serialize(IStream& stream, const std::string& str) + { + int length = str.size(); + stream.Write(sizeof(length), &length); + stream.Write(length, str.c_str()); + } + static void Serialize(IStream& stream, const std::string* const str) + { + int length = str->size(); + stream.Write(sizeof(length), &length); + stream.Write(length, str->c_str()); + } + + // STL templates + + // std::list + template + static void Serialize(IStream& stream, const std::list& list) + { + int length = list.size(); + stream.Write(sizeof(length), &length); + for (typename std::list::const_iterator list_iter = list.begin(); + list_iter != list.end(); list_iter++) + { + Serialize(stream, *list_iter); + } + } + template + static void Serialize(IStream& stream, const std::list* const list) + { + Serialize(stream, *list); + } + + // std::vector + template + static void Serialize(IStream& stream, const std::vector& vec) + { + int length = vec.size(); + stream.Write(sizeof(length), &length); + for (typename std::vector::const_iterator vec_iter = vec.begin(); + vec_iter != vec.end(); vec_iter++) + { + Serialize(stream, *vec_iter); + } + } + template + static void Serialize(IStream& stream, const std::vector* const vec) + { + Serialize(stream, *vec); + } + + // std::pair + template + static void Serialize(IStream& stream, const std::pair& p) + { + Serialize(stream, p.first); + Serialize(stream, p.second); + } + template + static void Serialize(IStream& stream, const std::pair* const p) + { + Serialize(stream, *p); + } + + // std::map + template + static void Serialize(IStream& stream, const std::map& map) + { + int length = map.size(); + stream.Write(sizeof(length), &length); + typename std::map::const_iterator it; + for (it = map.begin(); it != map.end(); ++it) { + Serialize(stream, (*it).first); + Serialize(stream, (*it).second); + } + } + template + static void Serialize(IStream& stream, const std::map* const map) + { + Serialize(stream, *map); + } +}; // struct Serialization + +struct Deserialization { + // deserialization + // normal functions + + // ISerializable objects + // T instead of ISerializable is needed to call proper constructor + template + static void Deserialize(IStream& stream, T& object) + { + object = T(stream); + } + template + static void Deserialize(IStream& stream, T*& object) + { + object = new T(stream); + } + + // unsigned int + static void Deserialize(IStream& stream, unsigned& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, unsigned*& value) + { + value = new unsigned; + stream.Read(sizeof(*value), value); + } + + // int + static void Deserialize(IStream& stream, int& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, int*& value) + { + value = new int; + stream.Read(sizeof(*value), value); + } + + // bool + static void Deserialize(IStream& stream, bool& value) + { + stream.Read(sizeof(value), &value); + } + static void Deserialize(IStream& stream, bool*& value) + { + value = new bool; + stream.Read(sizeof(*value), value); + } + + // std::string + static void Deserialize(IStream& stream, std::string& str) + { + int length; + stream.Read(sizeof(length), &length); + char * buf = new char[length + 1]; + stream.Read(length, buf); + buf[length] = 0; + str = std::string(buf); + delete[] buf; + } + static void Deserialize(IStream& stream, std::string*& str) + { + int length; + stream.Read(sizeof(length), &length); + char * buf = new char[length + 1]; + stream.Read(length, buf); + buf[length] = 0; + str = new std::string(buf); + delete[] buf; + } + + // STL templates + + // std::list + template + static void Deserialize(IStream& stream, std::list& list) + { + int length; + stream.Read(sizeof(length), &length); + for (int i = 0; i < length; ++i) { + T obj; + Deserialize(stream, obj); + list.push_back(obj); + } + } + template + static void Deserialize(IStream& stream, std::list*& list) + { + list = new std::list; + Deserialize(stream, *list); + } + + // std::vector + template + static void Deserialize(IStream& stream, std::vector& vec) + { + int length; + stream.Read(sizeof(length), &length); + for (int i = 0; i < length; ++i) { + T obj; + Deserialize(stream, obj); + vec.push_back(obj); + } + } + template + static void Deserialize(IStream& stream, std::vector*& vec) + { + vec = new std::vector; + Deserialize(stream, *vec); + } + + // std::pair + template + static void Deserialize(IStream& stream, std::pair& p) + { + Deserialize(stream, p.first); + Deserialize(stream, p.second); + } + template + static void Deserialize(IStream& stream, std::pair*& p) + { + p = new std::pair; + Deserialize(stream, *p); + } + + // std::map + template + static void Deserialize(IStream& stream, std::map& map) + { + int length; + stream.Read(sizeof(length), &length); + for (int i = 0; i < length; ++i) { + K key; + T obj; + Deserialize(stream, key); + Deserialize(stream, obj); + map[key] = obj; + } + } + template + static void Deserialize(IStream& stream, std::map*& map) + { + map = new std::map; + Deserialize(stream, *map); + } +}; // struct Deserialization +} // namespace DPL + +#endif // SERIALIZATION_H diff --git a/modules/core/include/dpl/shared_ptr.h b/modules/core/include/dpl/shared_ptr.h new file mode 100644 index 0000000..27f8b60 --- /dev/null +++ b/modules/core/include/dpl/shared_ptr.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file shared_ptr.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of shared pointer RAII + * + * This module is deprecated, please use standard C++11 feature: std::shared_ptr + */ +#ifndef DPL_SHARED_PTR_H +#define DPL_SHARED_PTR_H + +#include + +#include +#include +#include +#include +#include + +namespace DPL { +struct StaticPointerCastTag {}; +struct ConstPointerCastTag {}; +struct DynamicPointerCastTag {}; + +struct SharedCounter +{ + SharedCounter() : + ref(1) + {} + + Atomic ref; +}; + +template +class EnableSharedFromThis; + +template +inline void _Internal_AcceptSharedPtr(SharedCounter *counter, + Other *other, + EnableSharedFromThis *otherBase) +{ + otherBase->_Internal_AcceptSharedPtr(counter, other); +} + +struct AnyPointer +{ + template + AnyPointer(Other *) + {} +}; + +inline void _Internal_AcceptSharedPtr(SharedCounter *, AnyPointer, AnyPointer) +{} + +template +class SharedPtr +{ + public: + typedef Class ValueType; + typedef SharedPtr ThisType; + + private: + SharedCounter *m_counter; + Class *m_ptr; + + void AttachCounter(const SharedCounter *counter) + { + // Attention: R-Value const cast + m_counter = const_cast(counter); + + if (m_counter != NULL) { + ++m_counter->ref; + } + } + + void DetachCounter() + { + if (m_counter) { + if (!--m_counter->ref) { + delete m_ptr; + delete m_counter; + } + + m_counter = NULL; + m_ptr = NULL; + } + } + + public: + SharedPtr() : + m_counter(NULL), + m_ptr(NULL) + {} + + explicit SharedPtr(Class *ptr) : + m_counter(NULL), + m_ptr(ptr) + { + if (m_ptr != NULL) { + m_counter = new SharedCounter(); + _Internal_AcceptSharedPtr(m_counter, m_ptr, m_ptr); + } + } + + SharedPtr(const SharedPtr &other) : + m_counter(NULL), + m_ptr(other.m_ptr) + { + AttachCounter(other.m_counter); + } + + SharedPtr(SharedCounter *counter, Class *ptr) : + m_counter(NULL), + m_ptr(ptr) + { + AttachCounter(counter); + } + + template + friend class SharedPtr; + + template + SharedPtr(const SharedPtr &other, const StaticPointerCastTag &) : + m_counter(NULL), + m_ptr(NULL) + { + m_ptr = static_cast(other.m_ptr); + AttachCounter(other.m_counter); + } + + template + SharedPtr(const SharedPtr &other, const ConstPointerCastTag &) : + m_counter(NULL), + m_ptr(NULL) + { + m_ptr = const_cast(other.m_ptr); + AttachCounter(other.m_counter); + } + + template + SharedPtr(const SharedPtr &other, const DynamicPointerCastTag &) : + m_counter(NULL), + m_ptr(NULL) + { + Class *ptr = dynamic_cast(other.Get()); + + if (ptr == NULL) { + return; + } + + m_ptr = ptr; + AttachCounter(other.m_counter); + } + + virtual ~SharedPtr() + { + DetachCounter(); + } + + Class *Get() const + { + return m_counter == NULL ? NULL : m_ptr; + } + + Class *operator->() const + { + Assert(m_counter != NULL && "Dereference of shared NULL pointer!"); + return m_ptr; + } + + Class &operator *() const + { + Assert(m_counter != NULL && "Dereference of shared NULL pointer!"); + return *m_ptr; + } + + void Reset(Class *ptr = NULL) + { + DetachCounter(); + + if (ptr != NULL) { + m_ptr = ptr; + m_counter = new SharedCounter(); + _Internal_AcceptSharedPtr(m_counter, m_ptr, m_ptr); + } + } + + SharedPtr &operator=(const SharedPtr &other) + { + if (this != &other) { + DetachCounter(); + m_ptr = other.m_ptr; + AttachCounter(other.m_counter); + } + + return *this; + } + + Atomic::ValueType GetUseCount() const + { + if (m_counter == NULL) { + return Atomic::ValueType(0); + } + + return m_counter->ref; + } + + DPL_IMPLEMENT_BOOL_OPERATOR(ValueType, ThisType, m_counter, m_ptr) +} DPL_DEPRECATED_WITH_MESSAGE("use standard C++11 feature: std::shared_ptr"); + +template +SharedPtr StaticPointerCast(const SharedPtr &ptr) +{ + return SharedPtr(ptr, StaticPointerCastTag()); +} + +template +SharedPtr ConstPointerCast(const SharedPtr &ptr) +{ + return SharedPtr(ptr, ConstPointerCastTag()); +} + +template +SharedPtr DynamicPointerCast(const SharedPtr &ptr) +{ + return SharedPtr(ptr, DynamicPointerCastTag()); +} + +template +inline bool operator ==(const SharedPtr &first, + const SharedPtr &second) +{ + return first.Get() == second.Get(); +} + +template +inline bool operator !=(const SharedPtr &first, + const SharedPtr &second) +{ + return first.Get() != second.Get(); +} + +template +inline bool operator <(const SharedPtr &first, + const SharedPtr &second) +{ + return first.Get() < second.Get(); +} +template +inline bool operator >(const SharedPtr &first, + const SharedPtr &second) +{ + return first.Get() > second.Get(); +} + +template +inline bool operator <=(const SharedPtr &first, + const SharedPtr &second) +{ + return first.Get() <= second.Get(); +} + +template +inline bool operator >=(const SharedPtr &first, + const SharedPtr &second) +{ + return first.Get() >= second.Get(); +} +} // namespace DPL + +#endif // DPL_SHARED_PTR_H diff --git a/modules/core/include/dpl/single_instance.h b/modules/core/include/dpl/single_instance.h new file mode 100644 index 0000000..afcaf52 --- /dev/null +++ b/modules/core/include/dpl/single_instance.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file single_instance.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of single instance + */ +#ifndef DPL_SINGLE_INSTANCE_H +#define DPL_SINGLE_INSTANCE_H + +#include +#include +#include + +namespace DPL { +class SingleInstance : + private Noncopyable +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, LockError) + DECLARE_EXCEPTION_TYPE(Base, ReleaseError) + }; + + private: + bool m_locked; + int m_fdLock; + + public: + SingleInstance(); + virtual ~SingleInstance(); + + bool TryLock(const std::string &lockName); + void Release(); +}; +} // namespace DPL + +#endif // DPL_SINGLE_INSTANCE_H diff --git a/modules/core/include/dpl/singleton.h b/modules/core/include/dpl/singleton.h new file mode 100644 index 0000000..530f5c1 --- /dev/null +++ b/modules/core/include/dpl/singleton.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_H +#define DPL_SINGLETON_H + +#include +#include +#include + +namespace DPL { +template +class Singleton : + private Class +{ + // + // Note: + // + // To remove posibility of instantiating directly Class, + // make Class' default constructor protected + // + + private: + Singleton() + {} + + typedef Optional OptionalThreadPtr; + + static Singleton &InternalInstance(); + + public: + virtual ~Singleton() + {} + + static Class &Instance(); +}; +} // namespace DPL + +#endif // DPL_SINGLETON_H diff --git a/modules/core/include/dpl/singleton_impl.h b/modules/core/include/dpl/singleton_impl.h new file mode 100644 index 0000000..12dbf32 --- /dev/null +++ b/modules/core/include/dpl/singleton_impl.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton_impl.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_IMPL_H +#define DPL_SINGLETON_IMPL_H + +/* + * WARNING! + * + * If some singleton's implementation uses another singletons implementation, + * those templates make the second singleton a dubleton. Be warned. Try to use + * singleton_safe_impl.h if possible. + */ + +namespace DPL { +template +Singleton& Singleton::InternalInstance() +{ + static Singleton instance; + return instance; +} + +template +Class &Singleton::Instance() +{ + Singleton& instance = Singleton::InternalInstance(); + return instance; +} +} // namespace DPL + +#define IMPLEMENT_SINGLETON(Type) \ + template DPL::Singleton&DPL::Singleton::InternalInstance(); \ + template Type & DPL::Singleton::Instance(); \ + +#endif // DPL_SINGLETON_IMPL_H diff --git a/modules/core/include/dpl/singleton_safe_impl.h b/modules/core/include/dpl/singleton_safe_impl.h new file mode 100644 index 0000000..c8923b7 --- /dev/null +++ b/modules/core/include/dpl/singleton_safe_impl.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton_safe_impl.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_SAFE_IMPL_H +#define DPL_SINGLETON_SAFE_IMPL_H + +#define IMPLEMENT_SAFE_SINGLETON(Class) \ + namespace DPL { \ + template<> \ + Singleton&Singleton::InternalInstance() \ + { \ + static Singleton instance; \ + return instance; \ + } \ + \ + template<> \ + Class & Singleton::Instance() \ + { \ + Singleton& instance = Singleton::InternalInstance(); \ + return instance; \ + } \ + \ + template Singleton&Singleton::InternalInstance(); \ + template Class & Singleton::Instance(); \ + } // namespace DPL + +#endif // DPL_SINGLETON_SAFE_IMPL_H diff --git a/modules/core/include/dpl/sstream.h b/modules/core/include/dpl/sstream.h new file mode 100644 index 0000000..aba4e0f --- /dev/null +++ b/modules/core/include/dpl/sstream.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file sstream.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief String stream typedefs + */ +#ifndef DPL_CORE_INCLUDE_SSTREAM_H_ +#define DPL_CORE_INCLUDE_SSTREAM_H_ + +#include +#include + +namespace DPL { +// @brief DPL IStringStream +typedef std::basic_istringstream IStringStream; + +// @brief DPL OStringStream +typedef std::basic_ostringstream OStringStream; +} //namespace DPL + +#endif // DPL_CORE_INCLUDE_SSTREAM_H_ diff --git a/modules/core/include/dpl/static_block.h b/modules/core/include/dpl/static_block.h new file mode 100644 index 0000000..62fae46 --- /dev/null +++ b/modules/core/include/dpl/static_block.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file static_block.h + * @author Iwanek Tomasz (t.iwanek@samsung.com) + * @version 1.0 + */ +#ifndef STATIC_BLOCK_H +#define STATIC_BLOCK_H + +#include + +//NOTE: order of static initialization of blocks is not specified + +// to be used only outside class of function scopes +#define STATIC_BLOCK_IMPL( UNIQUE ) \ + static void DPL_MACRO_CONCAT( _staticBlock , UNIQUE() ); \ + static int DPL_MACRO_CONCAT( _staticBlockInitAssurence , UNIQUE ) = []() -> int \ + { \ + (void) DPL_MACRO_CONCAT( _staticBlockInitAssurence , UNIQUE ); \ + DPL_MACRO_CONCAT( _staticBlock , UNIQUE() ); \ + return 0; \ + }(); \ + void DPL_MACRO_CONCAT( _staticBlock , UNIQUE() ) \ + +#define STATIC_BLOCK \ + STATIC_BLOCK_IMPL( __COUNTER__ ) \ + +//for class implementation +#define STATIC_BLOCK_CLASS( classname, methodname ) STATIC_BLOCK { classname::methodname(); } + +#endif // STATIC_BLOCK_H diff --git a/modules/core/include/dpl/string.h b/modules/core/include/dpl/string.h new file mode 100644 index 0000000..e4dc923 --- /dev/null +++ b/modules/core/include/dpl/string.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file string.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + */ +#ifndef DPL_STRING +#define DPL_STRING + +#include +#include +#include +#include +#include + +namespace DPL { +// @brief DPL string +typedef std::basic_string String; + +// @brief String exception class +class StringException +{ + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + + // @brief Invalid init for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF8ToUTF32) + + // @brief Invalid taStdContainerinit for UTF32 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvInitErrorUTF32ToUTF8) + + // @brief Invalid conversion for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF8ToUTF32) + + // @brief Invalid conversion for UTF8 to UTF32 converter + DECLARE_EXCEPTION_TYPE(Base, IconvConvertErrorUTF32ToUTF8) + + // @brief Invalid ASCII character detected in FromASCII + DECLARE_EXCEPTION_TYPE(Base, InvalidASCIICharacter) + + // @brief Invalid ASCII character detected in FromASCII + DECLARE_EXCEPTION_TYPE(Base, ICUInvalidCharacterFound) +}; + +//!\brief convert ASCII string to DPL::String +String FromASCIIString(const std::string& aString); + +//!\brief convert UTF32 string to DPL::String +String FromUTF32String(const std::wstring& aString); + +//@brief Returns String object created from UTF8 string +//@param[in] aString input UTF-8 string +String FromUTF8String(const std::string& aString); + +//@brief Returns String content as std::string +std::string ToUTF8String(const String& aString); + +//@brief Compare two unicode strings +int StringCompare(const String &left, + const String &right, + bool caseInsensitive = false); + +//@brief Splits the string into substrings. +//@param[in] str Input string +//@param[in] delimiters array or string containing a sequence of substring +// delimiters. Can be also a single delimiter character. +//@param[in] it InserterIterator that is used to save the generated substrings. +template +void Tokenize(const StringType& str, + const Delimiters& delimiters, + InserterIterator it, + bool ignoreEmpty = false) +{ + typename StringType::size_type nextSearchStart = 0; + typename StringType::size_type pos; + typename StringType::size_type length; + + while (true) { + pos = str.find_first_of(delimiters, nextSearchStart); + length = + ((pos == StringType::npos) ? str.length() : pos) - nextSearchStart; + + if (!ignoreEmpty || length > 0) { + *it = str.substr(nextSearchStart, length); + it++; + } + + if (pos == StringType::npos) { + return; + } + + nextSearchStart = pos + 1; + } +} + +namespace Utils { + +template class ConcatFunc : public std::binary_function +{ +public: + explicit ConcatFunc(const T & val) : m_delim(val) {} + T operator()(const T & arg1, const T & arg2) const + { + return arg1 + m_delim + arg2; + } +private: + T m_delim; +}; + +} + +template +typename ForwardIterator::value_type Join(ForwardIterator begin, ForwardIterator end, typename ForwardIterator::value_type delim) +{ + typedef typename ForwardIterator::value_type value; + if(begin == end) return value(); + Utils::ConcatFunc func(delim); + ForwardIterator init = begin; + return std::accumulate(++begin, end, *init, func); +} + +template void TrimLeft(StringType & obj, typename StringType::const_pointer separators) +{ + obj.erase(0, obj.find_first_not_of(separators)); +} + +template void TrimRight(StringType & obj, typename StringType::const_pointer separators) +{ + obj.erase(obj.find_last_not_of(separators)+1); +} + +template void Trim(StringType & obj, typename StringType::const_pointer separators) +{ + TrimLeft(obj, separators); + TrimRight(obj, separators); +} + + +} //namespace DPL + +std::ostream& operator<<(std::ostream& aStream, const DPL::String& aString); + +#endif // DPL_STRING diff --git a/modules/core/include/dpl/task.h b/modules/core/include/dpl/task.h new file mode 100644 index 0000000..fa5f3a3 --- /dev/null +++ b/modules/core/include/dpl/task.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file task.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Radoslaw Wicik (r.wicik@samsung.com) + * @version 1.0 + * @brief Header file for abstaract task definition + */ +#ifndef DPL_TASK_H +#define DPL_TASK_H + +#include +#include +#include +#include +#include + +namespace DPL { + +class Task : + private Noncopyable +{ + public: + virtual ~Task() {} + + virtual bool NextStep() = 0; + virtual bool Abort() = 0; + virtual size_t GetStepCount() const = 0; +}; + +template +class TaskDecl : + public Task +{ + protected: + typedef void (Impl::*Step)(); + + private: + typedef std::list StepList; + + StepList m_steps; + StepList m_abortSteps; + typename StepList::iterator m_currentStep; + typename StepList::iterator m_nextStep; + bool m_switched; + + Impl *m_impl; + bool m_running; + + protected: + void AddStep(Step step) + { + Assert(!m_running && "AddStep is not allowed after calling NextStep!"); + Assert(m_steps.end() == std::find(m_steps.begin(), + m_steps.end(), + step) && + "The same step started twice is not supported"); + m_steps.push_back(step); + m_nextStep = m_steps.begin(); + } + + void AddAbortStep(Step step) + { + Assert( + !m_running && "AddAbortStep is not allowed after calling NextStep!"); + Assert(m_abortSteps.end() == + std::find(m_abortSteps.begin(), + m_abortSteps.end(), + step) && + "The same step started twice is not supported"); + m_abortSteps.push_front(step); + } + + void SwitchToStep(Step step) + { + /// @TODO There can be problem here if user sets the same method two + // times in task list. + typename StepList::iterator i = std::find(m_steps.begin(), + m_steps.end(), step); + Assert(i != m_steps.end()); + m_nextStep = i; + m_switched = true; + } + + Step GetCurrentStep() const + { + if (m_currentStep == m_steps.end()) { + return NULL; + } + + return *m_currentStep; + } + + public: + TaskDecl(Impl *impl) : + m_switched(false), + m_impl(impl), + m_running(false) + { + Assert(this == m_impl); + m_currentStep = m_steps.end(); + m_nextStep = m_steps.end(); + } + + bool NextStep() + { + m_running = true; + + Assert( + m_nextStep != m_steps.end() && + "Step list is empty or all steps done"); + + m_switched = false; + + Step call = *m_nextStep; + (*m_impl.*call)(); + + m_currentStep = m_nextStep; + + if (m_switched) { + return true; + } else { + return ++m_nextStep != m_steps.end(); + } + } + + bool Abort() + { + m_running = true; + + m_steps.clear(); + + if (m_abortSteps.empty()) { + return false; + } + + FOREACH(it, m_abortSteps) + m_steps.push_back(*it); + + m_nextStep = m_steps.begin(); + + m_abortSteps.clear(); + + return true; + } + + size_t GetStepCount() const + { + return static_cast(m_steps.size()); + } +}; +} // namespace DPL + +#endif // DPL_TASK_H diff --git a/modules/core/include/dpl/thread.h b/modules/core/include/dpl/thread.h new file mode 100644 index 0000000..c41de3f --- /dev/null +++ b/modules/core/include/dpl/thread.h @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of thread + */ +#ifndef DPL_THREAD_H +#define DPL_THREAD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +class Thread : + private Noncopyable, + public WaitableHandleWatchSupport +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, DestroyFailed) + DECLARE_EXCEPTION_TYPE(Base, RunFailed) + DECLARE_EXCEPTION_TYPE(Base, QuitFailed) + DECLARE_EXCEPTION_TYPE(Base, UnmanagedThread) + }; + + typedef void (*EventDeleteProc)(void *event, void *userParam); + typedef void (*EventDispatchProc)(void *event, void *userParam); + + protected: + /** + * Main thread entry + * The method is intended to be overloaded with custom code. + * Default implementation just executes Exec method to process + * all thread exents + */ + virtual int ThreadEntry(); + + /** + * Start processing of thread events + */ + int Exec(); + + private: + struct InternalEvent + { + void *event; + void *userParam; + EventDispatchProc eventDispatchProc; + EventDeleteProc eventDeleteProc; + + InternalEvent(void *eventArg, + void *userParamArg, + EventDispatchProc eventDispatchProcArg, + EventDeleteProc eventDeleteProcArg) : + event(eventArg), + userParam(userParamArg), + eventDispatchProc(eventDispatchProcArg), + eventDeleteProc(eventDeleteProcArg) + {} + }; + + struct InternalTimedEvent : + InternalEvent + { + unsigned long dueTimeMiliseconds; + unsigned long registerTimeMiliseconds; + + InternalTimedEvent(void *eventArg, + void *userParamArg, + unsigned long dueTimeMilisecondsArg, + unsigned long registerTimeMilisecondsArg, + EventDispatchProc eventDispatchProcArg, + EventDeleteProc eventDeleteProcArg) : + InternalEvent(eventArg, + userParamArg, + eventDispatchProcArg, + eventDeleteProcArg), + dueTimeMiliseconds(dueTimeMilisecondsArg), + registerTimeMiliseconds(registerTimeMilisecondsArg) + {} + + bool operator<(const InternalTimedEvent &other) + { + return registerTimeMiliseconds + dueTimeMiliseconds > + other.registerTimeMiliseconds + other.dueTimeMiliseconds; + } + }; + + // Internal event list + typedef std::list InternalEventList; + + // Internal timed event list + typedef std::vector InternalTimedEventVector; + + // State managment + pthread_t m_thread; + volatile bool m_abandon; + volatile bool m_running; + Mutex m_stateMutex; + WaitableEvent m_quitEvent; + + // Event processing + Mutex m_eventMutex; + InternalEventList m_eventList; + WaitableEvent m_eventInvoker; + + // Timed events processing + Mutex m_timedEventMutex; + InternalTimedEventVector m_timedEventVector; + WaitableEvent m_timedEventInvoker; + + // WaitableHandleWatchSupport + virtual Thread *GetInvokerThread(); + virtual void HandleDirectInvoker(); + bool m_directInvoke; + + // Internals + unsigned long GetCurrentTimeMiliseconds() const; + void ProcessEvents(); + void ProcessTimedEvents(); + + static void *StaticThreadEntry(void *param); + + public: + explicit Thread(); + virtual ~Thread(); + + /** + * Run thread. Does nothing if thread is already running + */ + void Run(); + + /** + * Send quit message to thread and wait for its end + * Does nothing is thread is not running + */ + void Quit(); + + /** + * Checks if current thread is main one + * Returns true if it is main program thread, false otherwise + */ + static bool IsMainThread(); + + /** + * Current thread retrieval + * Returns DPL thread handle or NULL if it is main program thread + */ + static Thread *GetCurrentThread(); + + /** + * Low-level event push, usually used only by EventSupport + */ + void PushEvent(void *event, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam); + + /** + * Low-level timed event push, usually used only by EventSupport + */ + void PushTimedEvent(void *event, + double dueTimeSeconds, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam); + + /** + * Sleep for a number of seconds + */ + static void Sleep(uint64_t seconds); + + /** + * Sleep for a number of miliseconds + */ + static void MiliSleep(uint64_t miliseconds); + + /** + * Sleep for a number of microseconds + */ + static void MicroSleep(uint64_t microseconds); + + /** + * Sleep for a number of nanoseconds + */ + static void NanoSleep(uint64_t nanoseconds); +}; + +extern bool g_TLSforMainCreated; + +// In case of using TLV in main thread, pthread_exit(NULL) has to be called in +// this thread explicitly. +// On the other hand, possibly, because of the kernel bug, there exist +// a problem, if any other thread than main exist during pthread_exit call +// (process can become non-responsive) +// TODO further investigation is required. +template +class ThreadLocalVariable : + public Noncopyable +{ + public: + typedef Type ValueType; + + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, NullReference) + DECLARE_EXCEPTION_TYPE(Base, KeyCreateFailed) + }; + + private: + pthread_key_t m_key; + + struct ManagedValue + { + ValueType value; + Optional guardKey; + }; + + static void MainThreadExitClean() + { + // There is a possible bug in kernel. If this function is called + // before ALL threads are closed, process will hang! + // Because of that, by default this function has to be called in well + // known "threads state". + + // pthread_exit(NULL); + } + + static void InternalDestroy(void *specific) + { + // Destroy underlying type + ManagedValue *instance = static_cast(specific); + if (instance->guardKey.IsNull()) { + delete instance; + } else { + int result = pthread_setspecific(*(instance->guardKey), instance); + + Assert(result == 0 && + "Failed to set thread local variable"); + } + } + + Type &Reference(bool allowInstantiate = false) + { + ManagedValue *instance = + static_cast(pthread_getspecific(m_key)); + + if (!instance) { + // Check if it is allowed to instantiate + if (!allowInstantiate) { + Throw(typename Exception::NullReference); + } + + // checking, if specific data is created for Main thread + // If yes, pthread_exit(NULL) is required + if (!g_TLSforMainCreated) { + if (Thread::IsMainThread()) { + g_TLSforMainCreated = true; + atexit(&MainThreadExitClean); + } + } + + // Need to instantiate underlying type + instance = new ManagedValue(); + + int result = pthread_setspecific(m_key, instance); + + Assert(result == 0 && + "Failed to set thread local variable"); + } + + return instance->value; + } + + public: + ThreadLocalVariable() + { + int result = pthread_key_create(&m_key, &InternalDestroy); + if (result != 0) { + ThrowMsg(typename Exception::KeyCreateFailed, + "Failed to allocate thread local variable: " << result); + } + } + + ~ThreadLocalVariable() + { + pthread_key_delete(m_key); + } + + Type &operator=(const Type &other) + { + Type &reference = Reference(true); + reference = other; + return reference; + } + + bool IsNull() const + { + return pthread_getspecific(m_key) == NULL; + } + + Type& operator*() + { + return Reference(); + } + + const Type& operator*() const + { + return Reference(); + } + + const Type* operator->() const + { + return &Reference(); + } + + Type* operator->() + { + return &Reference(); + } + + bool operator!() const + { + return IsNull(); + } + + void Reset() + { + ManagedValue *specific = + static_cast(pthread_getspecific(m_key)); + + if (!specific) { + return; + } + + // TODO Should be an assert? is it developers fault to Reset Guarded + // value? + specific->guardKey = Optional::Null; + + InternalDestroy(specific); + + int result = pthread_setspecific(m_key, NULL); + + Assert(result == 0 && + "Failed to reset thread local variable"); + } + + // GuardValue(true) allows to defer destroy (by pthread internal + // functionality) thread specific value until GuardValue(false) will be + // called. + void GuardValue(bool guard) + { + ManagedValue *instance = + static_cast(pthread_getspecific(m_key)); + + Assert(instance && "Failed to get the value"); + + instance->guardKey = guard ? m_key : Optional::Null; + } +}; +} // namespace DPL + +#endif // DPL_THREAD_H diff --git a/modules/core/include/dpl/type_list.h b/modules/core/include/dpl/type_list.h new file mode 100644 index 0000000..88afaf2 --- /dev/null +++ b/modules/core/include/dpl/type_list.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file type_list.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Generic type list template + */ +#ifndef DPL_TYPE_LIST_H +#define DPL_TYPE_LIST_H + +#include + +namespace DPL { +class TypeListGuard +{ + public: + template + struct Element + { + struct ERROR_TypeListElementIndexIsOutOfBounds; + typedef ERROR_TypeListElementIndexIsOutOfBounds Type; + }; + + static const size_t Size = 0; +}; + +template +class TypeList +{ + private: + class DummyClass + {}; + + template + struct TypeCounter : public TypeCounter + {}; + + template + struct TypeCounter + { + static const size_t Size = Enum; + }; + + public: + typedef TailType Tail; + typedef HeadType Head; + typedef TypeList ThisType; + + template + struct Element + { + typedef typename TailType::template Element::Type Type; + }; + + template + struct Element<0, DummyType> + { + typedef HeadType Type; + }; + + template + struct Contains + { + typedef typename TailType::template Contains::Yes Yes; + }; + + template + struct Contains + { + typedef int Yes; + }; + + static const size_t Size = TypeCounter::Size; +}; + +template +struct TypeListDecl +{ + typedef TypeList::Type> Type; +}; + +template<> +struct TypeListDecl +{ + typedef TypeListGuard Type; +}; +} // namespace DPL + +#endif // DPL_TYPE_LIST_H diff --git a/modules/core/include/dpl/union_cast.h b/modules/core/include/dpl/union_cast.h new file mode 100644 index 0000000..3f499a4 --- /dev/null +++ b/modules/core/include/dpl/union_cast.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file union_cast.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for union cast + */ +#ifndef DPL_UNION_CAST_H +#define DPL_UNION_CAST_H + +#include + +namespace DPL { +template +TargetType union_cast(const SourceType &data) +{ + union + { + SourceType source; + TargetType target; + } cast; + + std::memset(&cast, 0, sizeof(cast)); + + cast.source = data; + return cast.target; +} +} // namespace DPL + +#endif // DPL_UNION_CAST_H diff --git a/modules/core/include/dpl/waitable_event.h b/modules/core/include/dpl/waitable_event.h new file mode 100644 index 0000000..364bc5c --- /dev/null +++ b/modules/core/include/dpl/waitable_event.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_event.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable event + */ +#ifndef DPL_WAITABLE_EVENT_H +#define DPL_WAITABLE_EVENT_H + +#include +#include +#include +#include + +namespace DPL { +class WaitableEvent : + private Noncopyable +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, DestroyFailed) + DECLARE_EXCEPTION_TYPE(Base, SignalFailed) + DECLARE_EXCEPTION_TYPE(Base, ResetFailed) + }; + + private: + int m_pipe[2]; + + public: + WaitableEvent(); + virtual ~WaitableEvent(); + + WaitableHandle GetHandle() const; + + void Signal() const; + void Reset() const; +}; +} // namespace DPL + +#endif // DPL_WAITABLE_EVENT_H diff --git a/modules/core/include/dpl/waitable_handle.h b/modules/core/include/dpl/waitable_handle.h new file mode 100644 index 0000000..9864f78 --- /dev/null +++ b/modules/core/include/dpl/waitable_handle.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of waitable handle + */ +#ifndef DPL_WAITABLE_HANDLE_H +#define DPL_WAITABLE_HANDLE_H + +#include +#include +#include + +namespace DPL { +/** + * Waitable unix wait handle definition + */ +typedef int WaitableHandle; + +/** + * Waitable handle list + */ +typedef std::vector WaitableHandleList; + +/** + * Wait mode + */ +class WaitMode +{ + public: + enum Type + { + Read, ///< Wait for readability state changes + Write ///< Wait for writability state changes + }; +}; + +/** + * Waitable handle list ex + */ +typedef std::vector > WaitableHandleListEx; + +/** + * Waitable handle index list + */ +typedef std::vector WaitableHandleIndexList; + +/** + * Wait exceptions + */ +DECLARE_EXCEPTION_TYPE(DPL::Exception, WaitFailed) + +/** + * Wait for single handle readability + * Convience function. + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForSingleHandle( + WaitableHandle handle, + unsigned long miliseconds = + 0xFFFFFFFF); + +/** + * Wait for single handle + * Convience function. + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForSingleHandle( + WaitableHandle handle, + WaitMode::Type mode, + unsigned long miliseconds = + 0xFFFFFFFF); + +/** + * Wait for multiple handles readability + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleList &handleList, + unsigned long miliseconds = 0xFFFFFFFF); + +/** + * Wait for multiple handles readability + * + * @return Signaled waitable handle index list + * @throw WaitFailed Fatal error occurred while waiting for signal + */ +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleListEx &handleListEx, + unsigned long miliseconds = 0xFFFFFFFF); +} // namespace DPL + +#endif // DPL_WAITABLE_HANDLE_H diff --git a/modules/core/include/dpl/waitable_handle_watch_support.h b/modules/core/include/dpl/waitable_handle_watch_support.h new file mode 100644 index 0000000..ac0987f --- /dev/null +++ b/modules/core/include/dpl/waitable_handle_watch_support.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle_watch_support.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable handle watch + * support + */ +#ifndef DPL_WAITABLE_HANDLE_WATCH_SUPPORT_H +#define DPL_WAITABLE_HANDLE_WATCH_SUPPORT_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +class Thread; + +class WaitableHandleWatchSupport +{ + public: + class WaitableHandleListener + { + public: + virtual ~WaitableHandleListener() {} + + virtual void OnWaitableHandleEvent(WaitableHandle waitableHandle, + WaitMode::Type mode) = 0; + }; + + protected: + // Invoker waitable handle + // Signaled by Add/Remove methods + // After being signaled one must call Handle invoke to reset invoker + WaitableHandle WaitableInvokerHandle() const; + + // Waitable handle ex list + WaitableHandleListEx WaitableWatcherHandles() const; + + // Perform actions for signaled waitable handle + // Called in execution context, after + void HandleWatcher(WaitableHandle waitableHandle, WaitMode::Type mode); + + // Perform actions after invoker was signaled + void InvokerFinished(); + + // Get invoker context + virtual Thread *GetInvokerThread() = 0; + + // Invoke direct invoker + virtual void HandleDirectInvoker() = 0; + + private: + // Waitable event watchers + struct WaitableHandleWatcher + { + WaitableHandleListener *listener; + WaitMode::Type mode; + + WaitableHandleWatcher(WaitableHandleListener *l, WaitMode::Type m) : + listener(l), + mode(m) + {} + }; + + typedef std::list WaitableHandleListenerList; + + struct WaitableHandleWatchers + { + WaitableHandleListenerList listeners; + size_t readListenersCount; + size_t writeListenersCount; + + WaitableHandleWatchers() : + readListenersCount(0), + writeListenersCount(0) + {} + }; + + typedef std::map WaitableHandleWatchersMap; + + // Waitable event watch support + mutable RecursiveMutex m_watchersMutex; + WaitableHandleWatchersMap m_watchersMap; + WaitableEvent m_watchersInvoker; + WaitableEvent m_watchersInvokerCommit; + + // Invoke call + void CommitInvoker(); + + public: + /** + * Constructor + */ + explicit WaitableHandleWatchSupport(); + + /** + * Destructor + */ + virtual ~WaitableHandleWatchSupport(); + + /** + * Adds listener for specific waitable event + * + * @param[in] listener Listener to attach + * @param[in] waitableHandle Waitable handle to listen for changes + * @param[in] mode Type of changes to listen to + * @return none + * @see WaitMode::Type + */ + void AddWaitableHandleWatch(WaitableHandleListener *listener, + WaitableHandle waitableHandle, + WaitMode::Type mode); + + /** + * Remove listener for specific waitable event + * + * @param[in] listener Listener to detach + * @param[in] waitableHandle Waitable handle to unlisten for changes + * @param[in] mode Type of changes to unlisten to + * @return none + * @see WaitMode::Type + */ + void RemoveWaitableHandleWatch(WaitableHandleListener *listener, + WaitableHandle waitableHandle, + WaitMode::Type mode); + + /** + * Retrieve inherited context + * + * @return Inherited waitable handle watch support + */ + static WaitableHandleWatchSupport *InheritedContext(); +}; +} // namespace DPL + +#endif // DPL_WAITABLE_HANDLE_WATCH_SUPPORT_H diff --git a/modules/core/include/dpl/workaround.h b/modules/core/include/dpl/workaround.h new file mode 100644 index 0000000..19c26ef --- /dev/null +++ b/modules/core/include/dpl/workaround.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file workaround.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of workaround + */ +#ifndef DPL_WORKAROUND_H +#define DPL_WORKAROUND_H + +/** + * Define following macro to track invalid waitable handles + * in WaitForSingle/WaitForMultiple functions + */ +#define DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK + +/** + * Define following macro to enable workaround for problem + * with GLIB loop integration and EBADF error handling + */ +#define DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND + +/** + * Define following macro to enable workaround for problem + * with invalid conversions in htons/ntohs macros + */ +#define DPL_ENABLE_HTONS_NTOHS_I386_WORKAROUND + +#endif // DPL_WORKAROUND_H diff --git a/modules/core/include/dpl/zip_input.h b/modules/core/include/dpl/zip_input.h new file mode 100644 index 0000000..b364fe4 --- /dev/null +++ b/modules/core/include/dpl/zip_input.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file zip_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of zip input + */ +#ifndef DPL_ZIP_INPUT_H +#define DPL_ZIP_INPUT_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +class ZipInput : + private Noncopyable +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, ReadGlobalInfoFailed) + DECLARE_EXCEPTION_TYPE(Base, ReadGlobalCommentFailed) + DECLARE_EXCEPTION_TYPE(Base, SeekFileFailed) + DECLARE_EXCEPTION_TYPE(Base, FileInfoFailed) + DECLARE_EXCEPTION_TYPE(Base, OpenFileFailed) + DECLARE_EXCEPTION_TYPE(Base, ReadFileFailed) + }; + + typedef std::pair FileHandle; + + struct FileInfo + { + // File handle + FileHandle handle; + + // File name and comment + std::string name; + std::string comment; + + // File information + off64_t compressedSize; //< compressed size + off64_t uncompressedSize; //< uncompressed size + + FileInfo() : + handle(), + name(), + comment(), + compressedSize(0), + uncompressedSize(0) + {} + + FileInfo(const FileHandle &handleArg, + const std::string &nameArg, + const std::string &commentArg, + const off64_t &compressedSizeArg, + const off64_t &uncompressedSizeArg) : + handle(handleArg), + name(nameArg), + comment(commentArg), + compressedSize(compressedSizeArg), + uncompressedSize(uncompressedSizeArg) + {} + }; + + class File : + public DPL::AbstractInput + { + private: + void *m_file; + + friend class ZipInput; + File(class Device *device, FileHandle handle); + + public: + ~File(); + + virtual DPL::BinaryQueueAutoPtr Read(size_t size); + }; + + private: + class Device * m_device; + void *m_masterFile; + + size_t m_numberOfFiles; + size_t m_globalCommentSize; + std::string m_globalComment; + size_t m_totalUncompressedSize; + + // At least cache handles + typedef std::vector FileInfoList; + FileInfoList m_fileInfos; + + void ReadGlobalInfo(void *masterFile); + void ReadGlobalComment(void *masterFile); + void ReadInfos(void *masterFile); + + public: + typedef FileInfoList::const_iterator const_iterator; + typedef FileInfoList::const_reverse_iterator const_reverse_iterator; + typedef FileInfoList::size_type size_type; + + public: + /** + * Open zip file from file + */ + explicit ZipInput(const std::string &fileName); + + /** + * Destructor + */ + ~ZipInput(); + + // Iterators + const_iterator begin() const; + const_iterator end() const; + + const_reverse_iterator rbegin() const; + const_reverse_iterator rend() const; + + // Size, empty + size_type size() const; + bool empty() const; + + /** + * Open a binary file for given file name + * + * @return file object + * @param[in] fileName Zip file name to open + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @exception SteamOpenFailed Cannot find file with given handle + * @see BinaryQueue::BufferDeleterFree + */ + File *OpenFile(const std::string &fileName); + + /** + * Get archive global comment + * + * @return Global archive comment + */ + const std::string &GetGlobalComment() const; + size_t GetTotalUncompressedSize() const; +}; +} // namespace DPL + +#endif // DPL_ZIP_INPUT_H diff --git a/modules/core/src/DESCRIPTION b/modules/core/src/DESCRIPTION new file mode 100644 index 0000000..9043c93 --- /dev/null +++ b/modules/core/src/DESCRIPTION @@ -0,0 +1 @@ +Source files diff --git a/modules/core/src/abstract_waitable_input_adapter.cpp b/modules/core/src/abstract_waitable_input_adapter.cpp new file mode 100644 index 0000000..a802a7f --- /dev/null +++ b/modules/core/src/abstract_waitable_input_adapter.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_input_adapter.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract waitable input + * adapter + */ +#include +#include + +namespace DPL { +AbstractWaitableInputAdapter::AbstractWaitableInputAdapter(AbstractInput *input) + : + m_input(input) +{ + m_waitableEvent.Signal(); +} + +BinaryQueueAutoPtr AbstractWaitableInputAdapter::Read(size_t size) +{ + return m_input->Read(size); +} + +WaitableHandle AbstractWaitableInputAdapter::WaitableReadHandle() const +{ + return m_waitableEvent.GetHandle(); +} +} // namespace DPL diff --git a/modules/core/src/abstract_waitable_input_output_adapter.cpp b/modules/core/src/abstract_waitable_input_output_adapter.cpp new file mode 100644 index 0000000..e432b31 --- /dev/null +++ b/modules/core/src/abstract_waitable_input_output_adapter.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_input_output_adapter.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract waitable input + * output adapter + */ +#include +#include + +namespace DPL { +AbstractWaitableInputOutputAdapter::AbstractWaitableInputOutputAdapter( + AbstractInputOutput *inputOutput) : + AbstractWaitableInputAdapter(inputOutput), + AbstractWaitableOutputAdapter(inputOutput) +{} +} // namespace DPL diff --git a/modules/core/src/abstract_waitable_output_adapter.cpp b/modules/core/src/abstract_waitable_output_adapter.cpp new file mode 100644 index 0000000..82c2347 --- /dev/null +++ b/modules/core/src/abstract_waitable_output_adapter.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_waitable_output_adapter.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract waitable output + * adapter + */ +#include +#include + +namespace DPL { +AbstractWaitableOutputAdapter::AbstractWaitableOutputAdapter( + AbstractOutput *output) : + m_output(output) +{ + m_waitableEvent.Signal(); +} + +size_t AbstractWaitableOutputAdapter::Write(const BinaryQueue &buffer, + size_t bufferSize) +{ + return m_output->Write(buffer, bufferSize); +} + +WaitableHandle AbstractWaitableOutputAdapter::WaitableWriteHandle() const +{ + return m_waitableEvent.GetHandle(); +} +} // namespace DPL diff --git a/modules/core/src/address.cpp b/modules/core/src/address.cpp new file mode 100644 index 0000000..34c8861 --- /dev/null +++ b/modules/core/src/address.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file address.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of address + */ +#include +#include +#include +#include + +namespace DPL { +Address::Address() : + m_port(0) +{} + +Address::Address(const std::string &address) : + m_address(address), + m_port(0) +{} + +Address::Address(const std::string &address, unsigned short port) : + m_address(address), + m_port(port) +{} + +Address::~Address() +{} + +std::string Address::GetAddress() const +{ + return m_address; +} + +unsigned short Address::GetPort() const +{ + return m_port; +} + +std::string Address::ToString() const +{ + std::ostringstream out; + out << m_address << ":" << m_port; + return out.str(); +} + +bool Address::operator<(const Address &addr) const +{ + return ToString() < addr.ToString(); +} +} // namespace DPL diff --git a/modules/core/src/application.cpp b/modules/core/src/application.cpp new file mode 100644 index 0000000..9335ded --- /dev/null +++ b/modules/core/src/application.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file application.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC application support + */ +#include +#include +#include + +namespace // anonymous +{ +static DPL::Application *g_application = NULL; +} // namespace anonymous + +namespace DPL { +bool Application::app_create(void *data) +{ + Application *This = static_cast(data); + This->OnCreate(); + return true; +} + +void Application::app_terminate(void *data) +{ + Application *This = static_cast(data); + This->OnTerminate(); +} + +void Application::app_pause(void *data) +{ + Application *This = static_cast(data); + This->OnPause(); +} + +void Application::app_resume(void *data) +{ + Application *This = static_cast(data); + This->OnResume(); +} + +void Application::app_control(app_control_h app_control, void *data) +{ + Application *This = static_cast(data); + + // convert app_control to bundle + bundle *b; + app_control_to_bundle(app_control, &b); + + This->OnReset(b); +} + +Application::Application(int argc, char** argv, + const std::string& applicationName, + bool showMainWindow) : + m_argc(argc), + m_argv(argv), + m_applicationName(applicationName), + m_mainWindowVisible(showMainWindow) +{ + if (g_application != NULL) { + ThrowMsg(Exception::TooManyInstances, + "Only single instance of Application allowed at one time!"); + } + + g_application = this; +} + +Application::~Application() +{ + g_application = NULL; +} + +int Application::Exec() +{ + LogPedantic("Starting application framework..."); + + ui_app_lifecycle_callback_s callback; + callback.create = app_create; + callback.terminate = app_terminate; + callback.pause = app_pause; + callback.resume = app_resume; + callback.app_control = app_control; + + int result = ui_app_main(m_argc, m_argv, &callback, this); + + LogPedantic("Exited application framework"); + + return result; +} + +void Application::OnCreate() +{ + LogPedantic("On application create"); +} + +void Application::OnStart() +{ + LogPedantic("On application start"); +} + +void Application::OnStop() +{ + LogPedantic("On application stop"); +} + +void Application::OnResume() +{ + LogPedantic("On application resume"); +} + +void Application::OnPause() +{ + LogPedantic("On application pause"); +} + +void Application::OnRelaunch() +{ + LogPedantic("On application relaunch"); +} + +void Application::OnReset(bundle *b) +{ + (void)b; + LogPedantic("On application reset"); +} + +void Application::OnTerminate() +{ + LogPedantic("On application terminate"); +} + +void Application::OnLowMemory() +{ + LogPedantic("On application low memory"); +} + +void Application::OnLowBattery() +{ + LogPedantic("On application low battery"); +} + +void Application::OnLanguageChanged() +{ + LogPedantic("On application language changed"); +} + +void Application::Quit() +{ + elm_exit(); +} + +DPL::Atomic ApplicationExt::m_useCount(0); + +ApplicationExt::ApplicationExt(int argc, + char** argv, + const std::string& applicationName, + bool showMainWindow) : + Application(argc, argv, applicationName, showMainWindow) +{} + +ApplicationExt::~ApplicationExt() +{} + +int ApplicationExt::Exec() +{ + if (0 == m_useCount.CompareAndExchange(0, 1)) { + return Application::Exec(); + } else { + elm_run(); + } + return 0; +} + +void ApplicationExt::Quit() +{ + elm_exit(); +} +} // namespace DPL diff --git a/modules/core/src/apply.cpp b/modules/core/src/apply.cpp new file mode 100644 index 0000000..7ba5180 --- /dev/null +++ b/modules/core/src/apply.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file apply.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of apply functionality + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/assert.cpp b/modules/core/src/assert.cpp new file mode 100644 index 0000000..5a18977 --- /dev/null +++ b/modules/core/src/assert.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#include +#include +#include +#include +#include +#include + +namespace DPL { +void AssertProc(const char *condition, + const char *file, + int line, + const char *function) +{ +#define INTERNAL_LOG(message) \ + do \ + { \ + std::ostringstream platformLog; \ + platformLog << message; \ + DPL::Log::LogSystemSingleton::Instance().Pedantic( \ + platformLog.str().c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + while (0) + + // Try to log failed assertion to log system + Try + { + INTERNAL_LOG( + "################################################################################"); + INTERNAL_LOG( + "### DPL assertion failed! ###"); + INTERNAL_LOG( + "################################################################################"); + INTERNAL_LOG("### Condition: " << condition); + INTERNAL_LOG("### File: " << file); + INTERNAL_LOG("### Line: " << line); + INTERNAL_LOG("### Function: " << function); + INTERNAL_LOG( + "################################################################################"); + } catch (Exception) { + // Just ignore possible double errors + } + + // print assertion message to stderr + fprintf(stderr, "Assert!! [%s:%s] %s\n", file, function, condition); + + // Fail with c-library abort + abort(); +} +} // namespace DPL diff --git a/modules/core/src/atomic.cpp b/modules/core/src/atomic.cpp new file mode 100644 index 0000000..2f50074 --- /dev/null +++ b/modules/core/src/atomic.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file atomic.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of atomic + */ +#include +#include + +namespace DPL { +Atomic::Atomic(ValueType value) : + m_value(value) +{} + +Atomic::ValueType Atomic::ExchangeAndAdd(ValueType value) +{ + return g_atomic_int_add(const_cast(&m_value), value); +} + +bool Atomic::CompareAndExchange(ValueType oldValue, ValueType newValue) +{ + return g_atomic_int_compare_and_exchange(const_cast(&m_value), + oldValue, + newValue); +} + +bool Atomic::operator--() +{ + return g_atomic_int_dec_and_test(const_cast(&m_value)) != TRUE; +} + +void Atomic::operator++() +{ + g_atomic_int_inc(const_cast(&m_value)); +} + +Atomic::operator ValueType() const +{ + return g_atomic_int_get(const_cast(&m_value)); +} +} // namespace DPL diff --git a/modules/core/src/binary_queue.cpp b/modules/core/src/binary_queue.cpp new file mode 100644 index 0000000..2234c8f --- /dev/null +++ b/modules/core/src/binary_queue.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file binary_queue.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of binary queue + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +BinaryQueue::BinaryQueue() : + m_size(0) +{} + +BinaryQueue::BinaryQueue(const BinaryQueue &other) : + m_size(0) +{ + AppendCopyFrom(other); +} + +BinaryQueue::~BinaryQueue() +{ + // Remove all remainig buckets + Clear(); +} + +const BinaryQueue &BinaryQueue::operator=(const BinaryQueue &other) +{ + if (this != &other) { + Clear(); + AppendCopyFrom(other); + } + + return *this; +} + +void BinaryQueue::AppendCopyFrom(const BinaryQueue &other) +{ + // To speed things up, always copy as one bucket + void *bufferCopy = malloc(other.m_size); + + if (bufferCopy == NULL) { + throw std::bad_alloc(); + } + + try { + other.Flatten(bufferCopy, other.m_size); + AppendUnmanaged(bufferCopy, other.m_size, &BufferDeleterFree, NULL); + } catch (const std::bad_alloc &) { + // Free allocated memory + free(bufferCopy); + throw; + } +} + +void BinaryQueue::AppendMoveFrom(BinaryQueue &other) +{ + // Copy all buckets + std::copy(other.m_buckets.begin(), + other.m_buckets.end(), std::back_inserter(m_buckets)); + m_size += other.m_size; + + // Clear other, but do not free memory + other.m_buckets.clear(); + other.m_size = 0; +} + +void BinaryQueue::AppendCopyTo(BinaryQueue &other) const +{ + other.AppendCopyFrom(*this); +} + +void BinaryQueue::AppendMoveTo(BinaryQueue &other) +{ + other.AppendMoveFrom(*this); +} + +void BinaryQueue::Clear() +{ + std::for_each(m_buckets.begin(), m_buckets.end(), &DeleteBucket); + m_buckets.clear(); + m_size = 0; +} + +void BinaryQueue::AppendCopy(const void* buffer, size_t bufferSize) +{ + // Create data copy with malloc/free + void *bufferCopy = malloc(bufferSize); + + // Check if allocation succeded + if (bufferCopy == NULL) { + throw std::bad_alloc(); + } + + // Copy user data + memcpy(bufferCopy, buffer, bufferSize); + + try { + // Try to append new bucket + AppendUnmanaged(bufferCopy, bufferSize, &BufferDeleterFree, NULL); + } catch (const std::bad_alloc &) { + // Free allocated memory + free(bufferCopy); + throw; + } +} + +void BinaryQueue::AppendUnmanaged(const void* buffer, + size_t bufferSize, + BufferDeleter deleter, + void* userParam) +{ + // Do not attach empty buckets + if (bufferSize == 0) { + deleter(buffer, bufferSize, userParam); + return; + } + + // Just add new bucket with selected deleter + m_buckets.push_back(new Bucket(buffer, bufferSize, deleter, userParam)); + + // Increase total queue size + m_size += bufferSize; +} + +size_t BinaryQueue::Size() const +{ + return m_size; +} + +bool BinaryQueue::Empty() const +{ + return m_size == 0; +} + +void BinaryQueue::Consume(size_t size) +{ + // Check parameters + if (size > m_size) { + Throw(Exception::OutOfData); + } + + size_t bytesLeft = size; + + // Consume data and/or remove buckets + while (bytesLeft > 0) { + // Get consume size + size_t count = std::min(bytesLeft, m_buckets.front()->left); + + m_buckets.front()->ptr = + static_cast(m_buckets.front()->ptr) + count; + m_buckets.front()->left -= count; + bytesLeft -= count; + m_size -= count; + + if (m_buckets.front()->left == 0) { + DeleteBucket(m_buckets.front()); + m_buckets.pop_front(); + } + } +} + +void BinaryQueue::Flatten(void *buffer, size_t bufferSize) const +{ + // Check parameters + if (bufferSize == 0) { + return; + } + + if (bufferSize > m_size) { + Throw(Exception::OutOfData); + } + + size_t bytesLeft = bufferSize; + void *ptr = buffer; + BucketList::const_iterator bucketIterator = m_buckets.begin(); + Assert(m_buckets.end() != bucketIterator); + + // Flatten data + while (bytesLeft > 0) { + // Get consume size + size_t count = std::min(bytesLeft, (*bucketIterator)->left); + + // Copy data to user pointer + memcpy(ptr, (*bucketIterator)->ptr, count); + + // Update flattened bytes count + bytesLeft -= count; + ptr = static_cast(ptr) + count; + + // Take next bucket + ++bucketIterator; + } +} + +void BinaryQueue::FlattenConsume(void *buffer, size_t bufferSize) +{ + // FIXME: Optimize + Flatten(buffer, bufferSize); + Consume(bufferSize); +} + +void BinaryQueue::DeleteBucket(BinaryQueue::Bucket *bucket) +{ + delete bucket; +} + +void BinaryQueue::BufferDeleterFree(const void* data, + size_t dataSize, + void* userParam) +{ + (void)dataSize; + (void)userParam; + + // Default free deleter + free(const_cast(data)); +} + +BinaryQueue::Bucket::Bucket(const void* data, + size_t dataSize, + BufferDeleter dataDeleter, + void* userParam) : + buffer(data), + ptr(data), + size(dataSize), + left(dataSize), + deleter(dataDeleter), + param(userParam) +{ + Assert(data != NULL); + Assert(deleter != NULL); +} + +BinaryQueue::Bucket::~Bucket() +{ + // Invoke deleter on bucket data + deleter(buffer, size, param); +} + +BinaryQueue::BucketVisitor::~BucketVisitor() +{} + +BinaryQueue::BucketVisitorCall::BucketVisitorCall(BucketVisitor *visitor) : + m_visitor(visitor) +{} + +BinaryQueue::BucketVisitorCall::~BucketVisitorCall() +{} + +void BinaryQueue::BucketVisitorCall::operator()(Bucket *bucket) const +{ + m_visitor->OnVisitBucket(bucket->ptr, bucket->left); +} + +void BinaryQueue::VisitBuckets(BucketVisitor *visitor) const +{ + Assert(visitor != NULL); + + // Visit all buckets + std::for_each(m_buckets.begin(), m_buckets.end(), BucketVisitorCall(visitor)); +} + +BinaryQueueAutoPtr BinaryQueue::Read(size_t size) +{ + // Simulate input stream + size_t available = std::min(size, m_size); + + ScopedFree bufferCopy(malloc(available)); + + if (!bufferCopy) { + throw std::bad_alloc(); + } + + BinaryQueueAutoPtr result(new BinaryQueue()); + + Flatten(bufferCopy.Get(), available); + result->AppendUnmanaged( + bufferCopy.Get(), available, &BufferDeleterFree, NULL); + bufferCopy.Release(); + Consume(available); + + return result; +} + +size_t BinaryQueue::Write(const BinaryQueue &buffer, size_t bufferSize) +{ + // Simulate output stream + AppendCopyFrom(buffer); + return bufferSize; +} +} // namespace DPL diff --git a/modules/core/src/char_traits.cpp b/modules/core/src/char_traits.cpp new file mode 100644 index 0000000..32b9197 --- /dev/null +++ b/modules/core/src/char_traits.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file char_traits.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @biref Char traits are used to create basic_string extended with + * additional features + * Current char traits could be extended in feature to boost + * performance + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/colors.cpp b/modules/core/src/colors.cpp new file mode 100644 index 0000000..0b2fcd4 --- /dev/null +++ b/modules/core/src/colors.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file colors.cpp + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Some constants with definition of colors for Console + * and html output + */ +#include +#include + +namespace DPL { +namespace Colors { +namespace Text { +const char* BOLD_GREEN_BEGIN = "\033[1;32m"; +const char* BOLD_GREEN_END = "\033[m"; +const char* RED_BEGIN = "\033[0;31m"; +const char* RED_END = "\033[m"; +const char* PURPLE_BEGIN = "\033[0;35m"; +const char* PURPLE_END = "\033[m"; +const char* GREEN_BEGIN = "\033[0;32m"; +const char* GREEN_END = "\033[m"; +const char* CYAN_BEGIN = "\033[0;36m"; +const char* CYAN_END = "\033[m"; +const char* BOLD_RED_BEGIN = "\033[1;31m"; +const char* BOLD_RED_END = "\033[m"; +const char* BOLD_YELLOW_BEGIN = "\033[1;33m"; +const char* BOLD_YELLOW_END = "\033[m"; +const char* BOLD_GOLD_BEGIN = "\033[0;33m"; +const char* BOLD_GOLD_END = "\033[m"; +const char* BOLD_WHITE_BEGIN = "\033[1;37m"; +const char* BOLD_WHITE_END = "\033[m"; +} //namespace Text + +namespace Html { +const char* BOLD_GREEN_BEGIN = ""; +const char* BOLD_GREEN_END = ""; +const char* PURPLE_BEGIN = ""; +const char* PURPLE_END = ""; +const char* RED_BEGIN = ""; +const char* RED_END = ""; +const char* GREEN_BEGIN = ""; +const char* GREEN_END = ""; +const char* CYAN_BEGIN = ""; +const char* CYAN_END = ""; +const char* BOLD_RED_BEGIN = ""; +const char* BOLD_RED_END = ""; +const char* BOLD_YELLOW_BEGIN = ""; +const char* BOLD_YELLOW_END = ""; +const char* BOLD_GOLD_BEGIN = ""; +const char* BOLD_GOLD_END = ""; +const char* BOLD_WHITE_BEGIN = ""; +const char* BOLD_WHITE_END = ""; +} //namespace Html +} //namespace Colors +} //namespace DPL diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp new file mode 100644 index 0000000..c05d06c --- /dev/null +++ b/modules/core/src/copy.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file copy.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of copy + */ +#include +#include +#include +#include + +namespace DPL { +namespace // anonymous +{ +const size_t DEFAULT_COPY_BUFFER_SIZE = 16768; +} // namespace anonymous + +void Copy(AbstractWaitableInput *input, AbstractWaitableOutput *output) +{ + Try + { + while (true) { + BinaryQueueAutoPtr buffer; + + while (true) { + // Try to get data immediately + buffer = input->Read(DEFAULT_COPY_BUFFER_SIZE); + + // Do we need to wait for data ? + if (!buffer.get()) { + WaitForSingleHandle( + input->WaitableReadHandle(), WaitMode::Read); + continue; + } + + if (buffer->Empty()) { + return; // Done + } + // Ok, to process + break; + } + + // Write out all data + while (!buffer->Empty()) { + // Try to write all data immediately + size_t count = output->Write(*buffer, buffer->Size()); + + // Do we need to wait for writing data ? + if (count == 0) { + WaitForSingleHandle( + output->WaitableWriteHandle(), WaitMode::Write); + continue; + } + + // Consume data + buffer->Consume(count); + } + } + } + Catch(DPL::Exception) + { + ReThrow(CopyFailed); + } +} + +void Copy(AbstractWaitableInput *input, + AbstractWaitableOutput *output, + size_t totalBytes) +{ + Try + { + size_t bytesLeft = totalBytes; + + while (bytesLeft > 0) { + BinaryQueueAutoPtr buffer; + + // Copy at most left bytes + size_t bytesToCopy = bytesLeft > + DEFAULT_COPY_BUFFER_SIZE ? DEFAULT_COPY_BUFFER_SIZE : bytesLeft; + + while (true) { + // Try to get data immediately + buffer = input->Read(bytesToCopy); + + // Do we need to wait for data ? + if (!buffer.get()) { + WaitForSingleHandle( + input->WaitableReadHandle(), WaitMode::Read); + continue; + } + + if (buffer->Empty()) { + ThrowMsg(CopyFailed, "Unexpected end of abstract input"); + } + + // Ok, to process + break; + } + + // Write out all data + while (!buffer->Empty()) { + // Try to write all data immediately + size_t count = output->Write(*buffer, buffer->Size()); + + // Do we need to wait for writing data ? + if (count == 0) { + WaitForSingleHandle( + output->WaitableWriteHandle(), WaitMode::Write); + continue; + } + + // Consume data + buffer->Consume(count); + bytesLeft -= count; + } + } + } + Catch(DPL::Exception) + { + ReThrow(CopyFailed); + } +} +} // namespace DPL diff --git a/modules/core/src/errno_string.cpp b/modules/core/src/errno_string.cpp new file mode 100644 index 0000000..86cb59b --- /dev/null +++ b/modules/core/src/errno_string.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file errno_string.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of errno string + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace // anonymous +{ +const size_t DEFAULT_ERRNO_STRING_SIZE = 32; +} // namespace anonymous + +std::string GetErrnoString(int error) +{ + size_t size = DEFAULT_ERRNO_STRING_SIZE; + char *buffer = NULL; + + for (;;) { + // Add one extra characted for end of string null value + char *newBuffer = static_cast(::realloc(buffer, size + 1)); + + if (!newBuffer) { + // Failed to realloc + ::free(buffer); + throw std::bad_alloc(); + } + + // Setup reallocated buffer + buffer = newBuffer; + ::memset(buffer, 0, size + 1); + + // Try to retrieve error string +#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE + // The XSI-compliant version of strerror_r() is provided if: + int result = ::strerror_r(error, buffer, size); + + if (result == 0) { + ScopedFree scopedBufferFree(buffer); + return std::string(buffer); + } +#else + errno = 0; + + // Otherwise, the GNU-specific version is provided. + char *result = ::strerror_r(error, buffer, size); + + if (result != NULL) { + ScopedFree scopedBufferFree(buffer); + return std::string(result); + } +#endif + + // Interpret errors + switch (errno) { + case EINVAL: + // We got an invalid errno value + ::free(buffer); + ThrowMsg(InvalidErrnoValue, "Invalid errno value: " << error); + + case ERANGE: + // Incease buffer size and retry + size <<= 1; + continue; + + default: + AssertMsg(0, "Invalid errno value after call to strerror_r!"); + } + } +} +} // namespace DPL diff --git a/modules/core/src/exception.cpp b/modules/core/src/exception.cpp new file mode 100644 index 0000000..d3673e6 --- /dev/null +++ b/modules/core/src/exception.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation of exception system + */ +#include +#include +#include +#include + +namespace DPL { +Exception* Exception::m_lastException = NULL; +unsigned int Exception::m_exceptionCount = 0; +void (*Exception::m_terminateHandler)() = NULL; + +void LogUnhandledException(const std::string &str) +{ + // Logging to console + printf("%s\n", str.c_str()); + + // Logging to dlog + LogPedantic(str); +} + +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function) +{ + // Logging to console + std::ostringstream msg; + msg << "\033[1;5;31m\n=== [" << filename << ":" << line << "] " << + function << " ===\033[m"; + msg << str; + printf("%s\n", msg.str().c_str()); + + // Logging to dlog + DPL::Log::LogSystemSingleton::Instance().Error( + str.c_str(), filename, line, function); +} +} // namespace DPL diff --git a/modules/core/src/file_input.cpp b/modules/core/src/file_input.cpp new file mode 100644 index 0000000..36fb4b5 --- /dev/null +++ b/modules/core/src/file_input.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file file_input.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of named input pipe + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace // anonymous +{ +const size_t DEFAULT_READ_BUFFER_SIZE = 4096; +} // namespace anonymous + +FileInput::FileInput() : + m_fd(-1) +{} + +FileInput::FileInput(const std::string& fileName) : + m_fd(-1) +{ + Open(fileName); +} + +FileInput::~FileInput() +{ + Close(); +} + +void FileInput::Open(const std::string& fileName) +{ + // Open non-blocking + int fd = TEMP_FAILURE_RETRY(open(fileName.c_str(), O_RDONLY | O_NONBLOCK)); + + // Throw an exception if an error occurred + if (fd == -1) { + ThrowMsg(Exception::OpenFailed, fileName); + } + + // Close if any existing + Close(); + + // Save new descriptor + m_fd = fd; + + LogPedantic("Opened file: " << fileName); +} + +void FileInput::Close() +{ + if (m_fd == -1) { + return; + } + + if (TEMP_FAILURE_RETRY(close(m_fd)) == -1) { + Throw(Exception::CloseFailed); + } + + m_fd = -1; + + LogPedantic("Closed file"); +} + +BinaryQueueAutoPtr FileInput::Read(size_t size) +{ + size_t bytesToRead = size > + DEFAULT_READ_BUFFER_SIZE ? DEFAULT_READ_BUFFER_SIZE : size; + + // Malloc default read buffer size + // It is unmanaged, so it can be then attached directly to binary queue + void *buffer = malloc(bytesToRead); + + if (buffer == NULL) { + throw std::bad_alloc(); + } + + LogPedantic("Trying to read " << bytesToRead << " bytes"); + + ssize_t result = TEMP_FAILURE_RETRY(read(m_fd, buffer, bytesToRead)); + + LogPedantic("Read " << result << " bytes from file"); + + if (result > 0) { + // Succedded to read socket data + BinaryQueueAutoPtr binaryQueue(new BinaryQueue()); + + // Append unmanaged memory + binaryQueue->AppendUnmanaged(buffer, + result, + &BinaryQueue::BufferDeleterFree, + NULL); + + // Return buffer + return binaryQueue; + } else if (result == 0) { + // Socket was gracefuly closed + free(buffer); + + // Return empty buffer + return BinaryQueueAutoPtr(new BinaryQueue()); + } else { + // Must first save errno value, because it may be altered + int lastErrno = errno; + + // Free buffer + free(buffer); + + // Interpret error result + (void)lastErrno; + + // FIXME: Handle specific errno + Throw(AbstractInput::Exception::ReadFailed); + } +} + +WaitableHandle FileInput::WaitableReadHandle() const +{ + return static_cast(m_fd); +} +} // namespace DPL diff --git a/modules/core/src/file_output.cpp b/modules/core/src/file_output.cpp new file mode 100644 index 0000000..8342698 --- /dev/null +++ b/modules/core/src/file_output.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file file_output.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of file output + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +FileOutput::FileOutput() : + m_fd(-1) +{} + +FileOutput::FileOutput(const std::string& fileName) : + m_fd(-1) +{ + Open(fileName); +} + +FileOutput::~FileOutput() +{ + Close(); +} + +void FileOutput::Open(const std::string& fileName) +{ + // Open non-blocking + int fd = + TEMP_FAILURE_RETRY(open(fileName.c_str(), O_WRONLY | O_CREAT | + O_TRUNC | + O_NONBLOCK, 0664)); + + // Throw an exception if an error occurred + if (fd == -1) { + ThrowMsg(Exception::OpenFailed, fileName); + } + + // Close if any existing + Close(); + + // Save new descriptor + m_fd = fd; + + LogPedantic("Opened file: " << fileName); +} + +void FileOutput::Close() +{ + if (m_fd == -1) { + return; + } + + if (TEMP_FAILURE_RETRY(close(m_fd)) == -1) { + Throw(Exception::CloseFailed); + } + + m_fd = -1; + + LogPedantic("Closed file"); +} + +size_t FileOutput::Write(const BinaryQueue &buffer, size_t bufferSize) +{ + // Adjust write size + if (bufferSize > buffer.Size()) { + bufferSize = buffer.Size(); + } + + // FIXME: User write visitor to write ! + // WriteVisitor visitor + + ScopedFree flattened(malloc(bufferSize)); + buffer.Flatten(flattened.Get(), bufferSize); + + LogPedantic("Trying to write " << bufferSize << " bytes"); + + ssize_t result = TEMP_FAILURE_RETRY(write(m_fd, flattened.Get(), bufferSize)); + + LogPedantic("Wrote " << result << " bytes to file"); + + if (result > 0) { + // Successfuly written some bytes + return static_cast(result); + } else if (result == 0) { + // This is abnormal result + ThrowMsg(CommonException::InternalError, + "Invalid write result, 0 bytes written"); + } else { + // Interpret error result + // FIXME: Handle errno + Throw(AbstractOutput::Exception::WriteFailed); + } +} + +WaitableHandle FileOutput::WaitableWriteHandle() const +{ + return static_cast(m_fd); +} +} // namespace DPL diff --git a/modules/core/src/generic_event.cpp b/modules/core/src/generic_event.cpp new file mode 100644 index 0000000..f09ff2b --- /dev/null +++ b/modules/core/src/generic_event.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_event.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC generic event + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/lexical_cast.cpp b/modules/core/src/lexical_cast.cpp new file mode 100644 index 0000000..a89abc9 --- /dev/null +++ b/modules/core/src/lexical_cast.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file lexical_cast.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Implementation file for lexical cast + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/main.cpp b/modules/core/src/main.cpp new file mode 100644 index 0000000..1d0326b --- /dev/null +++ b/modules/core/src/main.cpp @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main for EFL + */ +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_SINGLETON(DPL::Main) + +namespace DPL { +namespace // anonymous +{ +// Late EFL event handling +Main *g_lateMain = NULL; +} // namespace anonymous + +Main::Main() +#ifdef DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND +// GLIB loop intergration workaround + : m_oldEcoreSelect(NULL) +#endif // DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND +{ + // Late EFL event handling + Assert(g_lateMain == NULL); + g_lateMain = this; + + // Increment ECORE init count to ensure we have all + // subsystems correctly set-up until main dispatcher dtor + // This is especially important when MainEventDispatcher + // is a global object destroyed no earlier than crt destroy routine + ecore_init(); + +#ifdef DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND + // GLIB loop intergration workaround + union ConvertPointer + { + Ecore_Select_Function pointer; + EcoreSelectType function; + } convert; + + convert.pointer = ecore_main_loop_select_func_get(); + m_oldEcoreSelect = convert.function; + + ecore_main_loop_select_func_set(&EcoreSelectInterceptor); +#endif // DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND + + // Register event invoker + m_invokerHandler = ecore_main_fd_handler_add( + WaitableHandleWatchSupport::WaitableInvokerHandle(), + ECORE_FD_READ, + &StaticDispatchInvoker, + this, + NULL, + NULL); + + if (m_invokerHandler == NULL) { + ThrowMsg(Exception::CreateFailed, "Failed to register invoker handler!"); + } + + // It is impossible that there exist watchers at this time + // No need to add watchers + LogPedantic("ECORE event handler registered"); +} + +Main::~Main() +{ + // Remove any watchers + for (EcoreFdHandlerList::iterator iterator = m_readWatchersList.begin(); + iterator != m_readWatchersList.end(); + ++iterator) + { + ecore_main_fd_handler_del(*iterator); + } + + m_readWatchersList.clear(); + + for (EcoreFdHandlerList::iterator iterator = m_writeWatchersList.begin(); + iterator != m_writeWatchersList.end(); + ++iterator) + { + ecore_main_fd_handler_del(*iterator); + } + + m_writeWatchersList.clear(); + + // Remove event invoker + ecore_main_fd_handler_del(m_invokerHandler); + m_invokerHandler = NULL; + + //set old ecore select function, because after ecore_shutdown() call, + //it is being called once again and it may crash. + ecore_main_loop_select_func_set(m_oldEcoreSelect); + // Decrement ECORE init count + // We do not need ecore routines any more + ecore_shutdown(); + + // Late EFL event handling + Assert(g_lateMain == this); + g_lateMain = NULL; +} + +Eina_Bool Main::StaticDispatchInvoker(void *data, Ecore_Fd_Handler *fd_handler) +{ + LogPedantic("Static ECORE dispatch invoker"); + + Main *This = static_cast
(data); + (void)fd_handler; + + Assert(This != NULL); + + // Late EFL event handling + if (g_lateMain == NULL) { + LogPedantic("WARNING: Late EFL invoker dispatch!"); + } else { + This->DispatchInvoker(); + } + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool Main::StaticDispatchReadWatcher(void* data, + Ecore_Fd_Handler* fd_handler) +{ + LogPedantic("Static ECORE dispatch read watcher"); + + Main *This = static_cast
(data); + + Assert(This != NULL); + + // Late EFL event handling + if (g_lateMain == NULL) { + LogPedantic("WARNING: Late EFL read watcher dispatch!"); + } else { + This->DispatchReadWatcher(static_cast( + ecore_main_fd_handler_fd_get(fd_handler))); + } + + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool Main::StaticDispatchWriteWatcher(void* data, + Ecore_Fd_Handler* fd_handler) +{ + LogPedantic("Static ECORE dispatch write watcher"); + + Main *This = static_cast
(data); + + Assert(This != NULL); + + // Late EFL event handling + if (g_lateMain == NULL) { + LogPedantic("WARNING: Late EFL write watcher dispatch!"); + } else { + This->DispatchWriteWatcher(static_cast( + ecore_main_fd_handler_fd_get(fd_handler))); + } + + return ECORE_CALLBACK_RENEW; +} + +void Main::DispatchInvoker() +{ + LogPedantic("Dispatching invoker..."); + + // Reload watch list + ReloadWatchList(); + + // Handle base invoker + WaitableHandleWatchSupport::InvokerFinished(); + + LogPedantic("Invoker dispatched"); +} + +void Main::ReloadWatchList() +{ + LogPedantic( + "Reloading watch list... (" << m_readWatchersList.size() << " + " << + m_writeWatchersList.size() << ")"); + + // Reload list of watchers + WaitableHandleListEx waitableWatcherHandles = + WaitableHandleWatchSupport::WaitableWatcherHandles(); + + // Remove not existing read watchers + EcoreFdHandlerList::iterator watchersIterator = m_readWatchersList.begin(); + WaitableHandleListEx::iterator handlesIterator; + + while (watchersIterator != m_readWatchersList.end()) { + bool found = false; + + for (handlesIterator = waitableWatcherHandles.begin(); + handlesIterator != waitableWatcherHandles.end(); + ++handlesIterator) + { + if (handlesIterator->second == WaitMode::Read && + handlesIterator->first == + static_cast(ecore_main_fd_handler_fd_get(* + watchersIterator))) + { + found = true; + break; + } + } + + if (!found) { + // Unregister handler + ecore_main_fd_handler_del(*watchersIterator); + + // Remove iterator + EcoreFdHandlerList::iterator next = watchersIterator; + ++next; + + m_readWatchersList.erase(watchersIterator); + watchersIterator = next; + } else { + ++watchersIterator; + } + } + + // Remove not existing write watchers + watchersIterator = m_writeWatchersList.begin(); + + while (watchersIterator != m_writeWatchersList.end()) { + bool found = false; + + for (handlesIterator = waitableWatcherHandles.begin(); + handlesIterator != waitableWatcherHandles.end(); + ++handlesIterator) + { + if (handlesIterator->second == WaitMode::Write && + handlesIterator->first == + static_cast(ecore_main_fd_handler_fd_get(* + watchersIterator))) + { + found = true; + break; + } + } + + if (!found) { + // Unregister handler + ecore_main_fd_handler_del(*watchersIterator); + + // Remove iterator + EcoreFdHandlerList::iterator next = watchersIterator; + ++next; + + m_writeWatchersList.erase(watchersIterator); + watchersIterator = next; + } else { + ++watchersIterator; + } + } + + // Add new read/write watchers + for (handlesIterator = waitableWatcherHandles.begin(); + handlesIterator != waitableWatcherHandles.end(); + ++handlesIterator) + { + if (handlesIterator->second == WaitMode::Read) { + bool found = false; + + for (watchersIterator = m_readWatchersList.begin(); + watchersIterator != m_readWatchersList.end(); + ++watchersIterator) + { + if (handlesIterator->first == + static_cast(ecore_main_fd_handler_fd_get(* + watchersIterator))) + { + found = true; + break; + } + } + + if (!found) { + Ecore_Fd_Handler *handler = ecore_main_fd_handler_add( + handlesIterator->first, + ECORE_FD_READ, + &StaticDispatchReadWatcher, + this, + NULL, + NULL); + if (handler == NULL) { + ThrowMsg(Exception::CreateFailed, + "Failed to register read watcher handler!"); + } + + // Push new watcher to list + m_readWatchersList.push_back(handler); + } + } else if (handlesIterator->second == WaitMode::Write) { + bool found = false; + + for (watchersIterator = m_writeWatchersList.begin(); + watchersIterator != m_writeWatchersList.end(); + ++watchersIterator) + { + if (handlesIterator->first == + static_cast(ecore_main_fd_handler_fd_get(* + watchersIterator))) + { + found = true; + break; + } + } + + if (!found) { + Ecore_Fd_Handler *handler = ecore_main_fd_handler_add( + handlesIterator->first, + ECORE_FD_WRITE, + &StaticDispatchWriteWatcher, + this, + NULL, + NULL); + if (handler == NULL) { + ThrowMsg(Exception::CreateFailed, + "Failed to register write watcher handler!"); + } + + // Push new watcher to list + m_writeWatchersList.push_back(handler); + } + } else { + Assert(0); + } + } + + LogPedantic( + "Watch list reloaded (" << m_readWatchersList.size() << " + " << + m_writeWatchersList.size() << ")"); +} + +void Main::DispatchReadWatcher(WaitableHandle waitableHandle) +{ + LogPedantic("Dispatching read watcher..."); + + // Handle watcher + WaitableHandleWatchSupport::HandleWatcher(waitableHandle, WaitMode::Read); + + LogPedantic("Watcher dispatched"); +} + +void Main::DispatchWriteWatcher(WaitableHandle waitableHandle) +{ + LogPedantic("Dispatching write watcher..."); + + // Handle watcher + WaitableHandleWatchSupport::HandleWatcher(waitableHandle, WaitMode::Write); + + LogPedantic("Watcher dispatched"); +} + +Thread *Main::GetInvokerThread() +{ + return NULL; +} + +void Main::HandleDirectInvoker() +{ + // Handle direct invoker + ReloadWatchList(); +} + +#ifdef DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND +// GLIB loop intergration workaround +int Main::EcoreSelectInterceptor(int nfds, + fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + // We have to check error code here and make another try because of some + // glib error's. + fd_set rfds, wfds, efds; + memcpy(&rfds, readfds, sizeof(fd_set)); + memcpy(&wfds, writefds, sizeof(fd_set)); + memcpy(&efds, exceptfds, sizeof(fd_set)); + + int ret = MainSingleton::Instance().m_oldEcoreSelect(nfds, + readfds, + writefds, + exceptfds, + timeout); + + if (ret == -1) { + // Check each descriptor to see if it is valid + for (int i = 0; i < nfds; i++) { + if (FD_ISSET(i, + readfds) || + FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) + { + // Try to get descriptor flags + int result = fcntl(i, F_GETFL); + + if (result == -1) { + if (errno == EBADF) { + // This a bad descriptor. Remove all occurrences of it. + if (FD_ISSET(i, readfds)) { + LogPedantic( + "GLIB_LOOP_INTEGRATION_WORKAROUND: Bad read descriptor: " + << i); + FD_CLR(i, readfds); + } + + if (FD_ISSET(i, writefds)) { + LogPedantic( + "GLIB_LOOP_INTEGRATION_WORKAROUND: Bad write descriptor: " + << i); + FD_CLR(i, writefds); + } + + if (FD_ISSET(i, exceptfds)) { + LogPedantic( + "GLIB_LOOP_INTEGRATION_WORKAROUND: Bad exception descriptor: " + << i); + FD_CLR(i, exceptfds); + } + } else { + // Unexpected error + Assert(0); + } + } + } + } + + LogPedantic( + "GLIB_LOOP_INTEGRATION_WORKAROUND: Bad read descriptor. Retrying with default select."); + + //Retry with old values and return new error + memcpy(readfds, &rfds, sizeof(fd_set)); + memcpy(writefds, &wfds, sizeof(fd_set)); + memcpy(exceptfds, &efds, sizeof(fd_set)); + + // Trying to do it very short + timeval tm; + tm.tv_sec = 0; + tm.tv_usec = 10; + + if (timeout) { + ret = select(nfds, readfds, writefds, exceptfds, &tm); + } else { + ret = select(nfds, readfds, writefds, exceptfds, NULL); + } + } + + return ret; +} +#endif // DPL_ENABLE_GLIB_LOOP_INTEGRATION_WORKAROUND +} // namespace DPL diff --git a/modules/core/src/mutable_task_list.cpp b/modules/core/src/mutable_task_list.cpp new file mode 100644 index 0000000..f8886fa --- /dev/null +++ b/modules/core/src/mutable_task_list.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file task_list.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief Implementation file for task list + */ +#include +#include +#include + +namespace DPL { +MutableTaskList::MutableTaskList() : + m_running(false) +{ + m_currentTask = m_tasks.end(); +} + +MutableTaskList::~MutableTaskList() +{ + for (Tasks::iterator i = m_tasks.begin(); i != m_tasks.end(); ++i) { + delete *i; + } +} + +void MutableTaskList::AddTask(Task *task) +{ + if(m_tasks.empty()) + { + m_tasks.push_back(task); + m_currentTask = m_tasks.begin(); + } + else + { + m_tasks.push_back(task); + } +} + +bool MutableTaskList::NextStep() +{ + m_running = true; + + AssertMsg( + m_currentTask != m_tasks.end(), + "Task list is empty or all tasks done"); + + bool result = (*m_currentTask)->NextStep(); + + if (result) { + return true; + } + + return ++m_currentTask != m_tasks.end(); +} + +bool MutableTaskList::Abort() +{ + m_tasks.erase(m_currentTask, m_tasks.end()); + m_tasks.reverse(); + for (Tasks::iterator i = m_tasks.begin(); i != m_tasks.end();) { + //If given task does not have any "abortSteps", remove it from the list + if (!(*i)->Abort()) { + delete *i; + i = m_tasks.erase(i); + continue; + } + ++i; + } + + if (m_tasks.empty()) { + return false; + } + + m_currentTask = m_tasks.begin(); + + return true; +} + +size_t MutableTaskList::GetStepCount() const +{ + size_t count = 0; + + for (Tasks::const_iterator i = m_tasks.begin(); i != m_tasks.end(); ++i) { + count += (*i)->GetStepCount(); + } + + return count; +} + +} // namespace DPL diff --git a/modules/core/src/mutex.cpp b/modules/core/src/mutex.cpp new file mode 100644 index 0000000..eed1f2e --- /dev/null +++ b/modules/core/src/mutex.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file mutex.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of mutex + */ +#include +#include +#include +#include +#include + +namespace DPL { +Mutex::Mutex() +{ + if (pthread_mutex_init(&m_mutex, NULL) != 0) { + int error = errno; + + LogPedantic("Failed to create mutex. Errno: " << error); + + ThrowMsg(Exception::CreateFailed, + "Failed to create mutex. Errno: " << error); + } +} + +Mutex::~Mutex() +{ + if (pthread_mutex_destroy(&m_mutex) != 0) { + int error = errno; + + LogPedantic("Failed to destroy mutex. Errno: " << error); + } +} + +void Mutex::Lock() const +{ + if (pthread_mutex_lock(&m_mutex) != 0) { + int error = errno; + + LogPedantic("Failed to lock mutex. Errno: " << error); + + ThrowMsg(Exception::LockFailed, + "Failed to lock mutex. Errno: " << error); + } +} + +void Mutex::Unlock() const +{ + if (pthread_mutex_unlock(&m_mutex) != 0) { + int error = errno; + + LogPedantic("Failed to unlock mutex. Errno: " << error); + + ThrowMsg(Exception::UnlockFailed, + "Failed to unlock mutex. Errno: " << error); + } +} + +Mutex::ScopedLock::ScopedLock(Mutex *mutex) : + m_mutex(mutex) +{ + Assert(mutex != NULL); + m_mutex->Lock(); +} + +Mutex::ScopedLock::~ScopedLock() +{ + Try + { + m_mutex->Unlock(); + } + Catch(Mutex::Exception::UnlockFailed) + { + LogPedantic("Failed to leave mutex scoped lock"); + } +} +} // namespace DPL diff --git a/modules/core/src/named_base_pipe.cpp b/modules/core/src/named_base_pipe.cpp new file mode 100644 index 0000000..9f91d30 --- /dev/null +++ b/modules/core/src/named_base_pipe.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file named_base_pipe.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of named base pipe + */ +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace // anonymous +{ +const mode_t FIFO_MODE = 0600; +} // namespace anonymous + +NamedBasePipe::~NamedBasePipe() +{} + +void NamedBasePipe::Create(const std::string &pipeName) +{ + // Create new fifo + int status = mkfifo(pipeName.c_str(), FIFO_MODE); + + if (status == -1) { + // Ignore error it it already exists + if (errno == EEXIST) { + ThrowMsg(Exception::AlreadyExist, pipeName); + } else { + ThrowMsg(Exception::CreateFailed, pipeName); + } + } +} + +void NamedBasePipe::Destroy(const std::string &fileName) +{ + // Destroy fifo + unlink(fileName.c_str()); // FIXME: Add error handling +} +} // namespace DPL diff --git a/modules/core/src/named_output_pipe.cpp b/modules/core/src/named_output_pipe.cpp new file mode 100644 index 0000000..2a9a1fa --- /dev/null +++ b/modules/core/src/named_output_pipe.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file named_output_pipe.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of named output pipe + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +NamedOutputPipe::NamedOutputPipe() : + m_fifo(-1) +{} + +NamedOutputPipe::~NamedOutputPipe() +{ + Close(); +} + +void NamedOutputPipe::Open(const std::string& pipeName) +{ + // Then open it for reading or writing + int fifo = TEMP_FAILURE_RETRY(open(pipeName.c_str(), O_WRONLY | O_NONBLOCK)); + + if (fifo == -1) { + ThrowMsg(Exception::OpenFailed, pipeName); + } + + m_fifo = fifo; +} + +void NamedOutputPipe::Close() +{ + if (m_fifo == -1) { + return; + } + + if (TEMP_FAILURE_RETRY(close(m_fifo)) == -1) { + Throw(Exception::CloseFailed); + } + + m_fifo = -1; +} + +size_t NamedOutputPipe::Write(const BinaryQueue &buffer, size_t bufferSize) +{ + // Adjust write size + if (bufferSize > buffer.Size()) { + bufferSize = buffer.Size(); + } + + // FIXME: User write visitor to write ! + // WriteVisitor visitor + + ScopedFree flattened(malloc(bufferSize)); + buffer.Flatten(flattened.Get(), bufferSize); + + ssize_t result = + TEMP_FAILURE_RETRY(write(m_fifo, flattened.Get(), bufferSize)); + + if (result > 0) { + // Successfuly written some bytes + return static_cast(result); + } else if (result == 0) { + // This is abnormal result + ThrowMsg(CommonException::InternalError, + "Invalid socket write result, 0 bytes written"); + } else { + // Interpret error result + // FIXME: Handle errno + Throw(AbstractOutput::Exception::WriteFailed); + } +} + +int NamedOutputPipe::WaitableWriteHandle() const +{ + return m_fifo; +} +} // namespace DPL diff --git a/modules/core/src/noncopyable.cpp b/modules/core/src/noncopyable.cpp new file mode 100644 index 0000000..9453655 --- /dev/null +++ b/modules/core/src/noncopyable.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#include +#include + +namespace DPL { +Noncopyable::Noncopyable() +{} + +Noncopyable::~Noncopyable() +{} +} // namespace DPL diff --git a/modules/core/src/once.cpp b/modules/core/src/once.cpp new file mode 100644 index 0000000..f2d4a1a --- /dev/null +++ b/modules/core/src/once.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file once.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of once + */ +#include +#include + +namespace DPL { +void Once::Call(Delegate delegate) +{ + // First chance test + if (m_atomic == 1) { + return; + } + + // Enter mutex + Mutex::ScopedLock lock(&m_mutex); + + // Second chance test + if (m_atomic == 1) { + return; + } + + // Initialization: call delegate + delegate(); + + // Initialization: done + ++m_atomic; +} +} // namespace DPL diff --git a/modules/core/src/read_write_mutex.cpp b/modules/core/src/read_write_mutex.cpp new file mode 100644 index 0000000..ef34758 --- /dev/null +++ b/modules/core/src/read_write_mutex.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file read_write_mutex.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of read write mutex + */ +#include +#include +#include + +namespace DPL { +ReadWriteMutex::ReadWriteMutex() +{ + if (pthread_rwlock_init(&m_rwlock, NULL) != 0) { + Throw(Exception::CreateFailed); + } +} + +ReadWriteMutex::~ReadWriteMutex() +{ + if (pthread_rwlock_destroy(&m_rwlock) != 0) { + Throw(Exception::DestroyFailed); + } +} + +void ReadWriteMutex::ReadLock() const +{ + if (pthread_rwlock_rdlock(&m_rwlock) != 0) { + Throw(Exception::ReadLockFailed); + } +} + +void ReadWriteMutex::WriteLock() const +{ + if (pthread_rwlock_wrlock(&m_rwlock) != 0) { + Throw(Exception::WriteLockFailed); + } +} + +void ReadWriteMutex::Unlock() const +{ + if (pthread_rwlock_unlock(&m_rwlock) != 0) { + Throw(Exception::UnlockFailed); + } +} + +ReadWriteMutex::ScopedReadLock::ScopedReadLock(ReadWriteMutex *mutex) : + m_mutex(mutex) +{ + Assert(mutex != NULL); + m_mutex->ReadLock(); +} + +ReadWriteMutex::ScopedReadLock::~ScopedReadLock() +{ + m_mutex->Unlock(); +} + +ReadWriteMutex::ScopedWriteLock::ScopedWriteLock(ReadWriteMutex *mutex) : + m_mutex(mutex) +{ + Assert(mutex != NULL); + m_mutex->WriteLock(); +} + +ReadWriteMutex::ScopedWriteLock::~ScopedWriteLock() +{ + m_mutex->Unlock(); +} +} // namespace DPL diff --git a/modules/core/src/recursive_mutex.cpp b/modules/core/src/recursive_mutex.cpp new file mode 100644 index 0000000..234d25f --- /dev/null +++ b/modules/core/src/recursive_mutex.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file recursive_mutex.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of recursive mutex + */ +#include +#include +#include + +namespace DPL { +RecursiveMutex::RecursiveMutex() +{ + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + if (pthread_mutex_init(&m_mutex, &attr) != 0) { + Throw(Exception::CreateFailed); + } +} + +RecursiveMutex::~RecursiveMutex() +{ + if (pthread_mutex_destroy(&m_mutex) != 0) { + Throw(Exception::DestroyFailed); + } +} + +void RecursiveMutex::Lock() const +{ + if (pthread_mutex_lock(&m_mutex) != 0) { + Throw(Exception::LockFailed); + } +} + +void RecursiveMutex::Unlock() const +{ + if (pthread_mutex_unlock(&m_mutex) != 0) { + Throw(Exception::UnlockFailed); + } +} + +RecursiveMutex::ScopedLock::ScopedLock(RecursiveMutex *mutex) : + m_mutex(mutex) +{ + Assert(mutex != NULL); + m_mutex->Lock(); +} + +RecursiveMutex::ScopedLock::~ScopedLock() +{ + m_mutex->Unlock(); +} +} // namespace DPL diff --git a/modules/core/src/scoped_dir.cpp b/modules/core/src/scoped_dir.cpp new file mode 100644 index 0000000..96550e6 --- /dev/null +++ b/modules/core/src/scoped_dir.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file scoped_dir.cpp + * @author Iwanek Tomasz (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation scoped directory + */ +#include +#include +#include + +#include +#include +#include + +namespace { + +bool removeRecusive(const char * path) +{ + FTS *fts; + FTSENT *ftsent; + bool rv = true; + char * const paths[] = { const_cast(path), NULL }; + if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) { + return false; + } + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_D: + break; + case FTS_DP: + if (rmdir(ftsent->fts_accpath) != 0) { + rv = false; + } + break; + case FTS_DC: + case FTS_F: + case FTS_NSOK: + case FTS_SL: + case FTS_SLNONE: + case FTS_DEFAULT: + if (unlink(ftsent->fts_accpath) != 0) { + rv = false; + } + break; + case FTS_NS: + rv = false; + break; + case FTS_DOT: + case FTS_DNR: + case FTS_ERR: + default: + rv = false; + break; + } + } + if (fts_close(fts) == -1) { + rv = false; + } + return rv; +} + +} + +namespace DPL { + +ScopedDirPolicy::Type ScopedDirPolicy::NullValue() +{ + return std::string(); +} + +void ScopedDirPolicy::Destroy(Type str) +{ + if(!str.empty()) + { + bool status = removeRecusive(str.c_str()); + if(!status) + { + LogError("Error while removing recursively: " << str); + } + } +} + +ScopedDir::ScopedDir(const std::string & str, mode_t mode) : BaseType(str) +{ + if(!str.empty()) + { + if (mkdir(str.c_str(), mode) == -1) + { + std::string errstr = DPL::GetErrnoString(); + LogError("Error while creating directory: " << str + << " [" << errstr << "]"); + } + } +} + +} // namespace DPL + diff --git a/modules/core/src/semaphore.cpp b/modules/core/src/semaphore.cpp new file mode 100644 index 0000000..387c009 --- /dev/null +++ b/modules/core/src/semaphore.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file semaphore.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of semaphore + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +void Semaphore::Remove(const std::string &fileName) +{ + if (sem_unlink(fileName.c_str()) == -1) { + int error = errno; + LogPedantic("Failed to unlink semaphore. Errno: " << error); + ThrowMsg(Exception::RemoveFailed, + "Failed to unlink semaphore. Errno: " << error); + } +} + +Semaphore::Semaphore(size_t maxLockCount) +{ + LogPedantic("Allocating unnamed semaphore:"); + LogPedantic(" Maximum lock count: " << maxLockCount); + + if (-1 == sem_init(&m_semaphore.unnamed.handle, + 0, + static_cast(maxLockCount))) + { + int error = errno; + + LogPedantic("Failed to create semaphore. Errno: " << error); + + ThrowMsg(Exception::CreateFailed, + "Failed to create semaphore. Errno: " << error); + } + + m_type = Type_Unnamed; +} + +Semaphore::Semaphore(const std::string &fileName, + bool allowCreate, + bool exclusiveCreate, + size_t maxLockCount, + int permissions, + bool unlinkOnDestroy) +{ + LogPedantic("Allocating named semaphore:"); + LogPedantic(" File name: " << fileName); + LogPedantic(" Maximum lock count: " << maxLockCount); + LogPedantic(" File name: " << fileName); + LogPedantic(" Allowed create: " << allowCreate); + LogPedantic(" Exclusive create: " << exclusiveCreate); + LogPedantic(" Permissions: " << permissions); + LogPedantic(" Unlink on destroy: " << unlinkOnDestroy); + + sem_t *semaphore; + + do { + if (allowCreate) { + if (exclusiveCreate) { + semaphore = sem_open(fileName.c_str(), + O_CREAT | O_EXCL, + permissions, + static_cast(maxLockCount)); + } else { + semaphore = sem_open(fileName.c_str(), + O_CREAT, + permissions, + static_cast(maxLockCount)); + } + } else { + semaphore = sem_open(fileName.c_str(), 0); + } + } while (semaphore == SEM_FAILED && errno == EINTR); + + if (semaphore == SEM_FAILED) { + int error = errno; + + LogPedantic("Failed to create semaphore '" << fileName + << "'. Errno: " << error); + + ThrowMsg(Exception::CreateFailed, + "Failed to create semaphore '" << fileName + << "'. Errno: " << error); + } + + m_semaphore.named.handle = semaphore; + + m_semaphore.named.name = strdup(fileName.c_str()); // May be NULL + + if (m_semaphore.named.name == NULL) { + LogPedantic("Out of memory while duplicating semaphore name"); + } + + m_semaphore.named.unlinkOnDestroy = unlinkOnDestroy; + + m_type = Type_Named; +} + +Semaphore::~Semaphore() +{ + InternalDestroy(); +} + +sem_t *Semaphore::InternalGet() const +{ + switch (m_type) { + case Type_Unnamed: + return &m_semaphore.unnamed.handle; + + case Type_Named: + return m_semaphore.named.handle; + + default: + Assert(false && "Invalid type"); + } + + return NULL; +} + +void Semaphore::InternalDestroy() +{ + switch (m_type) { + case Type_Unnamed: + if (sem_destroy(&m_semaphore.unnamed.handle) == -1) { + int error = errno; + + LogPedantic("Failed to destroy semaphore. Errno: " << error); + } + break; + + case Type_Named: + if (sem_close(m_semaphore.named.handle) == -1) { + int error = errno; + + LogPedantic("Failed to close semaphore. Errno: " << error); + } + + if (m_semaphore.named.name != NULL) { + // Unlink named semaphore + if (m_semaphore.named.unlinkOnDestroy && + sem_unlink(m_semaphore.named.name) == -1) + { + int error = errno; + + LogPedantic("Failed to unlink semaphore. Errno: " + << error); + } + + // Free name + free(m_semaphore.named.name); + } + break; + + default: + Assert(false && "Invalid type"); + } +} + +void Semaphore::Lock() const +{ + if (TEMP_FAILURE_RETRY(sem_wait(InternalGet())) != 0) { + int error = errno; + + LogPedantic("Failed to lock semaphore. Errno: " << error); + + ThrowMsg(Exception::LockFailed, + "Failed to lock semaphore. Errno: " << error); + } +} + +void Semaphore::Unlock() const +{ + if (sem_post(InternalGet()) != 0) { + int error = errno; + + LogPedantic("Failed to unlock semaphore. Errno: " << error); + + ThrowMsg(Exception::UnlockFailed, + "Failed to unlock semaphore. Errno: " << error); + } +} + +Semaphore::ScopedLock::ScopedLock(Semaphore *semaphore) : + m_semaphore(semaphore) +{ + Assert(semaphore != NULL); + m_semaphore->Lock(); +} + +Semaphore::ScopedLock::~ScopedLock() +{ + Try + { + m_semaphore->Unlock(); + } + Catch(Semaphore::Exception::UnlockFailed) + { + LogPedantic("Failed to leave semaphore scoped lock"); + } +} +} // namespace DPL diff --git a/modules/core/src/serialization.cpp b/modules/core/src/serialization.cpp new file mode 100644 index 0000000..f8f05ff --- /dev/null +++ b/modules/core/src/serialization.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file serialization.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of data serialization. + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/single_instance.cpp b/modules/core/src/single_instance.cpp new file mode 100644 index 0000000..274b5f8 --- /dev/null +++ b/modules/core/src/single_instance.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file single_instance.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of single instance + */ +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace // anonumous +{ +const char *LOCK_PREFIX_PATH = "/tmp/dpl_single_instance_"; +} +SingleInstance::SingleInstance() : + m_locked(false), + m_fdLock(-1) +{} + +SingleInstance::~SingleInstance() +{ + AssertMsg(!m_locked, "Single instance must be released before exit!"); +} + +bool SingleInstance::TryLock(const std::string &lockName) +{ + LogPedantic("Locking single instance: " << lockName); + + struct flock lock; + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + + // Open lock file + m_fdLock = + TEMP_FAILURE_RETRY(open((std::string(LOCK_PREFIX_PATH) + + lockName).c_str(), + O_WRONLY | O_CREAT, 0666)); + + if (m_fdLock == -1) { + ThrowMsg(Exception::LockError, "Cannot open single instance lock file!"); + } + + // Lock file + int result = TEMP_FAILURE_RETRY(fcntl(m_fdLock, F_SETLK, &lock)); + + // Was the instance successfuly locked ? + if (result == 0) { + LogPedantic("Instance locked: " << lockName); + + // It is locked now + m_locked = true; + + // Done + return true; + } + + if (errno == EACCES || errno == EAGAIN) { + LogPedantic("Instance is already running: " << lockName); + return false; + } + + // This is lock error + ThrowMsg(Exception::LockError, "Cannot lock single instance lock file!"); +} + +void SingleInstance::Release() +{ + if (!m_locked) { + return; + } + + LogPedantic("Unlocking single instance"); + + // Unlock file + struct flock lock; + + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + + int result = TEMP_FAILURE_RETRY(fcntl(m_fdLock, F_SETLK, &lock)); + + // Was the instance successfuly unlocked ? + if (result == -1) { + ThrowMsg(Exception::LockError, + "Cannot unlock single instance lock file!"); + } + + // Close lock file + if (TEMP_FAILURE_RETRY(close(m_fdLock)) == -1) { + ThrowMsg(Exception::LockError, + "Cannot close single instance lock file!"); + } + + m_fdLock = -1; + + // Done + m_locked = false; + LogPedantic("Instance unlocked"); +} +} // namespace DPL diff --git a/modules/core/src/singleton.cpp b/modules/core/src/singleton.cpp new file mode 100644 index 0000000..a76e8ac --- /dev/null +++ b/modules/core/src/singleton.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_event.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/string.cpp b/modules/core/src/string.cpp new file mode 100644 index 0000000..e81ae22 --- /dev/null +++ b/modules/core/src/string.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file string.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO: Completely move to ICU +namespace DPL { +namespace //anonymous +{ +class ASCIIValidator +{ + const std::string& m_TestedString; + + public: + ASCIIValidator(const std::string& aTestedString); + + void operator()(char aCharacter) const; +}; + +ASCIIValidator::ASCIIValidator(const std::string& aTestedString) : + m_TestedString(aTestedString) +{} + +void ASCIIValidator::operator()(char aCharacter) const +{ + // Check for ASCII data range + if (aCharacter <= 0) { + ThrowMsg( + StringException::InvalidASCIICharacter, + "invalid character code " << static_cast(aCharacter) + << " from string [" << + m_TestedString + << "] passed as ASCII"); + } +} + +const iconv_t gc_IconvOperError = reinterpret_cast(-1); +const size_t gc_IconvConvertError = static_cast(-1); +} // namespace anonymous + +String FromUTF8String(const std::string& aIn) +{ + if (aIn.empty()) { + return String(); + } + + size_t inbytes = aIn.size(); + + // Default iconv UTF-32 module adds BOM (4 bytes) in from of string + // The worst case is when 8bit UTF-8 char converts to 32bit UTF-32 + // newsize = oldsize * 4 + end + bom + // newsize - bytes for UTF-32 string + // oldsize - letters in UTF-8 string + // end - end character for UTF-32 (\0) + // bom - Unicode header in front of string (0xfeff) + size_t outbytes = sizeof(wchar_t) * (inbytes + 2); + std::vector output(inbytes + 2, 0); + + size_t outbytesleft = outbytes; + char* inbuf = const_cast(aIn.c_str()); + + // vector is used to provide buffer for iconv which expects char* buffer + // but during conversion from UTF32 uses internaly wchar_t + char* outbuf = reinterpret_cast(&output[0]); + + iconv_t iconvHandle = iconv_open("UTF-32", "UTF-8"); + + if (gc_IconvOperError == iconvHandle) { + int error = errno; + + ThrowMsg(StringException::IconvInitErrorUTF8ToUTF32, + "iconv_open failed for " << "UTF-32 <- UTF-8" << + "error: " << GetErrnoString(error)); + } + + size_t iconvRet = iconv(iconvHandle, + &inbuf, + &inbytes, + &outbuf, + &outbytesleft); + + iconv_close(iconvHandle); + + if (gc_IconvConvertError == iconvRet) { + ThrowMsg(StringException::IconvConvertErrorUTF8ToUTF32, + "iconv failed for " << "UTF-32 <- UTF-8" << "error: " + << GetErrnoString()); + } + + // Ignore BOM in front of UTF-32 + return &output[1]; +} + +std::string ToUTF8String(const DPL::String& aIn) +{ + if (aIn.empty()) { + return std::string(); + } + + size_t inbytes = aIn.size() * sizeof(wchar_t); + size_t outbytes = inbytes + sizeof(char); + + // wstring returns wchar_t but iconv expects char* + // iconv internally is processing input as wchar_t + char* inbuf = reinterpret_cast(const_cast(aIn.c_str())); + std::vector output(inbytes, 0); + char* outbuf = &output[0]; + + size_t outbytesleft = outbytes; + + iconv_t iconvHandle = iconv_open("UTF-8", "UTF-32"); + + if (gc_IconvOperError == iconvHandle) { + ThrowMsg(StringException::IconvInitErrorUTF32ToUTF8, + "iconv_open failed for " << "UTF-8 <- UTF-32" + << "error: " << GetErrnoString()); + } + + size_t iconvRet = iconv(iconvHandle, + &inbuf, + &inbytes, + &outbuf, + &outbytesleft); + + iconv_close(iconvHandle); + + if (gc_IconvConvertError == iconvRet) { + ThrowMsg(StringException::IconvConvertErrorUTF32ToUTF8, + "iconv failed for " << "UTF-8 <- UTF-32" + << "error: " << GetErrnoString()); + } + + return &output[0]; +} + +String FromASCIIString(const std::string& aString) +{ + String output; + + std::for_each(aString.begin(), aString.end(), ASCIIValidator(aString)); + std::copy(aString.begin(), aString.end(), std::back_inserter(output)); + + return output; +} + +String FromUTF32String(const std::wstring& aString) +{ + return String(&aString[0]); +} + +static UChar *ConvertToICU(const String &inputString) +{ + ScopedArray outputString; + int32_t size = 0; + int32_t convertedSize = 0; + UErrorCode error = U_ZERO_ERROR; + + // Calculate size of output string + ::u_strFromWCS(NULL, + 0, + &size, + inputString.c_str(), + -1, + &error); + + if (error == U_ZERO_ERROR || + error == U_BUFFER_OVERFLOW_ERROR) + { + // What buffer size is ok ? + LogPedantic("ICU: Output buffer size: " << size); + } else { + ThrowMsg(StringException::ICUInvalidCharacterFound, + "ICU: Failed to retrieve output string size. Error: " + << error); + } + + // Allocate proper buffer + outputString.Reset(new UChar[size + 1]); + ::memset(outputString.Get(), 0, sizeof(UChar) * (size + 1)); + + error = U_ZERO_ERROR; + + // Do conversion + ::u_strFromWCS(outputString.Get(), + size + 1, + &convertedSize, + inputString.c_str(), + -1, + &error); + + if (!U_SUCCESS(error)) { + ThrowMsg(StringException::ICUInvalidCharacterFound, + "ICU: Failed to convert string. Error: " << error); + } + + // Done + return outputString.Release(); +} + +int StringCompare(const String &left, + const String &right, + bool caseInsensitive) +{ + // Convert input strings + ScopedArray leftICU(ConvertToICU(left)); + ScopedArray rightICU(ConvertToICU(right)); + + if (caseInsensitive) { + return static_cast(u_strcasecmp(leftICU.Get(), rightICU.Get(), 0)); + } else { + return static_cast(u_strcmp(leftICU.Get(), rightICU.Get())); + } +} +} //namespace DPL + +std::ostream& operator<<(std::ostream& aStream, const DPL::String& aString) +{ + return aStream << DPL::ToUTF8String(aString); +} diff --git a/modules/core/src/task.cpp b/modules/core/src/task.cpp new file mode 100644 index 0000000..6d4ff0d --- /dev/null +++ b/modules/core/src/task.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file task.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Radoslaw Wicik (r.wicik@samsung.com) + * @version 1.0 + * @brief Implementation file for abstaract task definition + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/thread.cpp b/modules/core/src/thread.cpp new file mode 100644 index 0000000..0e75810 --- /dev/null +++ b/modules/core/src/thread.cpp @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of thread + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace // anonymous +{ +static const size_t NANOSECONDS_PER_SECOND = + static_cast(1000 * 1000 * 1000); + +static const size_t NANOSECONDS_PER_MILISECOND = + static_cast(1000 * 1000); + +static const size_t NANOSECONDS_PER_MICROSECOND = + static_cast(1000); + +static const pthread_t g_mainThread = pthread_self(); + +class ThreadSpecific +{ + public: + pthread_key_t threadSpecific; + + ThreadSpecific() : + threadSpecific(0) + { + threadSpecific = 0; + pthread_key_create(&threadSpecific, NULL); + } + + virtual ~ThreadSpecific() + { + pthread_key_delete(threadSpecific); + } +}; + +static ThreadSpecific g_threadSpecific; +} // namespace anonymous + +namespace DPL { +bool g_TLSforMainCreated = false; + +Thread::Thread() : + m_thread(0), + m_abandon(false), + m_running(false), + m_directInvoke(false) +{} + +Thread::~Thread() +{ + // Ensure that we quit thread + // Always wait thread by yourself; if thread is still running + // this may be sometimes very bad. When derived, some resources + // may leak or be doubly freed + Quit(); + + // Remove any remainig events + // Thread proc is surely not running now + for (InternalEventList::iterator iterator = m_eventList.begin(); + iterator != m_eventList.end(); + ++iterator) + { + iterator->eventDeleteProc(iterator->event, iterator->userParam); + } + + m_eventList.clear(); +} + +bool Thread::IsMainThread() +{ + return (pthread_equal(pthread_self(), g_mainThread)); +} + +Thread *Thread::GetCurrentThread() +{ + if (pthread_equal(pthread_self(), g_mainThread)) { + return NULL; + } + + void *threadSpecific = pthread_getspecific(g_threadSpecific.threadSpecific); + + // Is this a managed thread ? + if (threadSpecific == NULL) { + Throw(Exception::UnmanagedThread); + } + + return static_cast(threadSpecific); +} + +void *Thread::StaticThreadEntry(void *param) +{ + LogPedantic("Entered static thread entry"); + + // Retrieve context + Thread *This = static_cast(param); + Assert(This != NULL); + + // Set thread specific + int result = pthread_setspecific(g_threadSpecific.threadSpecific, This); + + if (result != 0) { + LogError("Failed to set threadSpecific. Error: " << strerror(result)); + } + + // Enter thread proc + // Do not allow exceptions to hit pthread core + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + This->ThreadEntry(); + } + UNHANDLED_EXCEPTION_HANDLER_END + + // Critical section + { + // Leave running state + Mutex::ScopedLock lock(&This->m_stateMutex); + + This->m_running = false; + + // Abandon thread + if (This->m_abandon) { + LogPedantic("Thread was abandoned"); + pthread_detach(This->m_thread); + } else { + LogPedantic("Thread is joinable"); + } + } + + return NULL; +} + +int Thread::ThreadEntry() +{ + LogPedantic("Entered default thread entry"); + return Exec(); +} + +void Thread::ProcessEvents() +{ + LogPedantic("Processing events"); + + // Steal current event list + InternalEventList stolenEvents; + + // Enter event list critical section + { + Mutex::ScopedLock lock(&m_eventMutex); + m_eventList.swap(stolenEvents); + m_eventInvoker.Reset(); + } + + // Process event list + LogPedantic("Stolen " << stolenEvents.size() << " internal events"); + + for (InternalEventList::iterator iterator = stolenEvents.begin(); + iterator != stolenEvents.end(); + ++iterator) + { + // Dispatch immediate event + iterator->eventDispatchProc(iterator->event, iterator->userParam); + + // Delete event + iterator->eventDeleteProc(iterator->event, iterator->userParam); + } +} + +void Thread::ProcessTimedEvents() +{ + // Critical section on timed events mutex + { + Mutex::ScopedLock lock(&m_timedEventMutex); + + // Get current time + unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds(); + + // Info + LogPedantic( + "Processing timed events. Time now: " << currentTimeMiliseconds << + " ms"); + + // All timed events are sorted chronologically + // Emit timed out events + while (!m_timedEventVector.empty() && + currentTimeMiliseconds >= + m_timedEventVector.begin()->registerTimeMiliseconds + + m_timedEventVector.begin()->dueTimeMiliseconds) + { + // Info + LogPedantic( + "Transforming timed event into immediate event. Absolute due time: " + << + (m_timedEventVector.begin()->registerTimeMiliseconds + + m_timedEventVector.begin()->dueTimeMiliseconds) << + " ms"); + + // Emit immediate event + PushEvent(m_timedEventVector.begin()->event, + m_timedEventVector.begin()->eventDispatchProc, + m_timedEventVector.begin()->eventDeleteProc, + m_timedEventVector.begin()->userParam); + + // Remove timed eventand fix heap + std::pop_heap(m_timedEventVector.begin(), m_timedEventVector.end()); + m_timedEventVector.pop_back(); + } + } +} + +unsigned long Thread::GetCurrentTimeMiliseconds() const +{ + timeval tv; + gettimeofday(&tv, NULL); + return static_cast(tv.tv_sec) * 1000 + + static_cast(tv.tv_usec) / 1000; +} + +int Thread::Exec() +{ + LogPedantic("Executing thread event processing"); + + const std::size_t MIN_HANDLE_LIST_SIZE = 4; + + // Start processing of events + WaitableHandleListEx handleList; + + // index 0: Quit waitable event handle + handleList.push_back(std::make_pair(m_quitEvent.GetHandle(), WaitMode::Read)); + + // index 1: Event occurred event handle + handleList.push_back(std::make_pair(m_eventInvoker.GetHandle(), + WaitMode::Read)); + + // index 2: Timed event occurred event handle + handleList.push_back(std::make_pair(m_timedEventInvoker.GetHandle(), + WaitMode::Read)); + + // index 3: Waitable handle watch support invoker + handleList.push_back(std::make_pair(WaitableHandleWatchSupport:: + WaitableInvokerHandle(), + WaitMode::Read)); + + // + // Watch list might have been initialized before threaded started + // Need to fill waitable event watch list in this case + // + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport::WaitableWatcherHandles(); + std::copy( + waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), std::back_inserter(handleList)); + } + + // Quit flag + bool quit = false; + + while (!quit) { + // Retrieve minimum wait time, according to timed events list + unsigned long minimumWaitTime; + + // Critical section on timed events mutex + { + Mutex::ScopedLock lock(&m_timedEventMutex); + + if (!m_timedEventVector.empty()) { + unsigned long currentTimeMiliseconds = + GetCurrentTimeMiliseconds(); + unsigned long destinationTimeMiliseconds = + m_timedEventVector.begin()->registerTimeMiliseconds + + m_timedEventVector.begin()->dueTimeMiliseconds; + + // Are we already late with timed event ? + if (currentTimeMiliseconds > destinationTimeMiliseconds) { + minimumWaitTime = 0; + } else { + minimumWaitTime = destinationTimeMiliseconds - + currentTimeMiliseconds; + } + } else { + minimumWaitTime = 0xFFFFFFFF; // Infinity + } + } + + // Info + LogPedantic( + "Thread loop minimum wait time: " << minimumWaitTime << " ms"); + + // Do thread waiting + WaitableHandleIndexList waitableHandleIndexList = + WaitForMultipleHandles(handleList, minimumWaitTime); + + if (waitableHandleIndexList.empty()) { + // Timeout occurred. Process timed events. + LogPedantic("Timed event list elapsed invoker"); + ProcessTimedEvents(); + continue; + } + + // Go through each index + for (WaitableHandleIndexList::const_iterator + waitableHandleIndexIterator = waitableHandleIndexList.begin(); + waitableHandleIndexIterator != waitableHandleIndexList.end(); + ++waitableHandleIndexIterator) + { + size_t index = *waitableHandleIndexIterator; + + LogPedantic("Event loop triggered with index: " << index); + + switch (index) { + case 0: + // Quit waitable event handle + quit = true; + break; + + case 1: + // Event occurred event handle + ProcessEvents(); + + // Handle direct invoker + if (m_directInvoke) { + m_directInvoke = false; + + LogPedantic("Handling direct invoker"); + + // Update list + while (handleList.size() > MIN_HANDLE_LIST_SIZE) { + handleList.pop_back(); + } + + // Insert current waitable event handles instead + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport::WaitableWatcherHandles(); + std::copy( + waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), + std::back_inserter(handleList)); + } + } + + // Done + break; + + case 2: + // Timed event list changed + LogPedantic("Timed event list changed invoker"); + ProcessTimedEvents(); + + // Reset timed event invoker + m_timedEventInvoker.Reset(); + + // Done + break; + + case 3: + // Waitable handle watch support invoker + LogPedantic("Waitable handle watch invoker event occurred"); + + // First, remove all previous handles + while (handleList.size() > MIN_HANDLE_LIST_SIZE) { + handleList.pop_back(); + } + + // Insert current waitable event handles instead + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport::WaitableWatcherHandles(); + std::copy( + waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), + std::back_inserter(handleList)); + } + + // Handle invoker in waitable watch support + WaitableHandleWatchSupport::InvokerFinished(); + + LogPedantic("Waitable handle watch invoker event handled"); + + // Done + break; + + default: + // Waitable event watch list + LogPedantic("Waitable handle watch event occurred"); + + // Handle event in waitable handle watch + { + std::pair handle = handleList[index]; + WaitableHandleWatchSupport::HandleWatcher(handle.first, + handle.second); + } + + if (m_directInvoke) { + m_directInvoke = false; + + LogPedantic("Handling direct invoker"); + + // Update list + while (handleList.size() > MIN_HANDLE_LIST_SIZE) { + handleList.pop_back(); + } + + // Insert current waitable event handles instead + { + WaitableHandleListEx waitableHandleWatchHandles = + WaitableHandleWatchSupport:: + WaitableWatcherHandles(); + std::copy(waitableHandleWatchHandles.begin(), + waitableHandleWatchHandles.end(), + std::back_inserter(handleList)); + } + } + + LogPedantic("Waitable handle watch event handled"); + + // Done + break; + } + } + } + + LogPedantic("Leaving thread event processing"); + return 0; +} + +void Thread::Run() +{ + LogPedantic("Running thread"); + + // Critical section + { + Mutex::ScopedLock lock(&m_stateMutex); + + if (m_running) { + return; + } + + // Try to create new thread + if (pthread_create(&m_thread, NULL, &StaticThreadEntry, this) != 0) { + Throw(Exception::RunFailed); + } + + // At default, we abandon thread + m_abandon = true; + + // Enter running state + m_running = true; + } + + LogPedantic("Thread run"); +} + +void Thread::Quit() +{ + pthread_t joinableThread; + + // Critical section + { + Mutex::ScopedLock lock(&m_stateMutex); + + // Is thread running ? + if (!m_running) { + return; + } + + LogPedantic("Quitting thread..."); + + // Do not abandon thread, we will join + m_abandon = false; + + // Singal quit waitable event + m_quitEvent.Signal(); + + // Copy joinable thread identifier, because + // we are leaving critical section + joinableThread = m_thread; + } + + // Wait for joinable thread + void *result; + + if (pthread_join(joinableThread, &result) != 0) { + Throw(Exception::QuitFailed); + } + + LogPedantic("Thread quit"); +} + +void Thread::PushEvent(void *event, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam) +{ + // Enter event list critical section + Mutex::ScopedLock lock(&m_eventMutex); + + // Push new event + m_eventList.push_back(InternalEvent(event, userParam, eventDispatchProc, + eventDeleteProc)); + + // Trigger invoker + m_eventInvoker.Signal(); + + LogPedantic("Event pushed and invoker signaled"); +} + +void Thread::PushTimedEvent(void *event, + double dueTimeSeconds, + EventDispatchProc eventDispatchProc, + EventDeleteProc eventDeleteProc, + void *userParam) +{ + // Check for developer errors + Assert(dueTimeSeconds >= 0.0); + + // Enter timed event list critical section + Mutex::ScopedLock lock(&m_timedEventMutex); + + // Get current time + unsigned long currentTimeMiliseconds = GetCurrentTimeMiliseconds(); + + // Convert to miliseconds + unsigned long dueTimeMiliseconds = + static_cast(1000.0 * dueTimeSeconds); + + // Push new timed event + m_timedEventVector.push_back(InternalTimedEvent(event, userParam, + dueTimeMiliseconds, + currentTimeMiliseconds, + eventDispatchProc, + eventDeleteProc)); + + // Heapify timed events + std::make_heap(m_timedEventVector.begin(), m_timedEventVector.end()); + + // Trigger invoker + m_timedEventInvoker.Signal(); + + LogPedantic( + "Timed event pushed and invoker signaled: due time: " << + dueTimeMiliseconds << " ms, absolute due time: " << + currentTimeMiliseconds + dueTimeMiliseconds << " ms"); +} + +Thread *Thread::GetInvokerThread() +{ + return this; +} + +void Thread::HandleDirectInvoker() +{ + // We must be in ProcessEvents call stack + // Mark that situation to handle direct invoker + m_directInvoke = true; +} + +void Thread::Sleep(uint64_t seconds) +{ + NanoSleep(seconds * NANOSECONDS_PER_SECOND); +} + +void Thread::MiliSleep(uint64_t miliseconds) +{ + NanoSleep(miliseconds * NANOSECONDS_PER_MILISECOND); +} + +void Thread::MicroSleep(uint64_t microseconds) +{ + NanoSleep(microseconds * NANOSECONDS_PER_MICROSECOND); +} + +void Thread::NanoSleep(uint64_t nanoseconds) +{ + timespec requestedTime = { + static_cast( + nanoseconds / NANOSECONDS_PER_SECOND), + + static_cast( + nanoseconds % NANOSECONDS_PER_SECOND) + }; + + timespec remainingTime; + + for (;;) { + if (nanosleep(&requestedTime, &remainingTime) == 0) { + break; + } + + int error = errno; + Assert(error == EINTR); + + requestedTime = remainingTime; + } +} +} // namespace DPL diff --git a/modules/core/src/type_list.cpp b/modules/core/src/type_list.cpp new file mode 100644 index 0000000..fa94806 --- /dev/null +++ b/modules/core/src/type_list.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file type_list.cpp + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Generic type list template + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/union_cast.cpp b/modules/core/src/union_cast.cpp new file mode 100644 index 0000000..ffcb499 --- /dev/null +++ b/modules/core/src/union_cast.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file union_cast.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Implementation file for union cast + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/core/src/waitable_event.cpp b/modules/core/src/waitable_event.cpp new file mode 100644 index 0000000..4808896 --- /dev/null +++ b/modules/core/src/waitable_event.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_event.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable event + */ +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +WaitableEvent::WaitableEvent() +{ + if (pipe(m_pipe) == -1) { + Throw(Exception::CreateFailed); + } + + if (fcntl(m_pipe[0], F_SETFL, O_NONBLOCK | + fcntl(m_pipe[0], F_GETFL)) == -1) + { + Throw(Exception::CreateFailed); + } +} + +WaitableEvent::~WaitableEvent() +{ + if (TEMP_FAILURE_RETRY(close(m_pipe[0])) == -1) { + Throw(Exception::DestroyFailed); + } + + if (TEMP_FAILURE_RETRY(close(m_pipe[1])) == -1) { + Throw(Exception::DestroyFailed); + } +} + +WaitableHandle WaitableEvent::GetHandle() const +{ + return m_pipe[0]; +} + +void WaitableEvent::Signal() const +{ + char data = 0; + + if (TEMP_FAILURE_RETRY(write(m_pipe[1], &data, 1)) != 1) { + Throw(Exception::SignalFailed); + } +} + +void WaitableEvent::Reset() const +{ + char data; + + if (TEMP_FAILURE_RETRY(read(m_pipe[0], &data, 1)) != 1) { + Throw(Exception::ResetFailed); + } +} +} // namespace DPL diff --git a/modules/core/src/waitable_handle.cpp b/modules/core/src/waitable_handle.cpp new file mode 100644 index 0000000..5ea600d --- /dev/null +++ b/modules/core/src/waitable_handle.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable handle + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace // anonymous +{ +void CheckWaitableHandle(WaitableHandle handle) +{ +#ifdef DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK + // Try to get descriptor flags + int result = fcntl(handle, F_GETFL); + + if (result == -1 && errno == EBADF) { + AssertMsg(0, "CheckWaitableHandle: Invalid WaitableHandle! (EBADF)"); + } + + AssertMsg(result != -1, "CheckWaitableHandle: Invalid WaitableHandle!"); +#endif // DPL_ENABLE_WAITABLE_HANDLE_BADF_CHECK +} +} // namespace anonymous + +WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle, + unsigned long miliseconds) +{ + WaitableHandleList waitHandles; + waitHandles.push_back(handle); + return WaitForMultipleHandles(waitHandles, miliseconds); +} + +WaitableHandleIndexList WaitForSingleHandle(WaitableHandle handle, + WaitMode::Type mode, + unsigned long miliseconds) +{ + WaitableHandleListEx waitHandles; + waitHandles.push_back(std::make_pair(handle, mode)); + return WaitForMultipleHandles(waitHandles, miliseconds); +} + +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleList &waitableHandleList, + unsigned long miliseconds) +{ + WaitableHandleListEx handleList; + + for (WaitableHandleList::const_iterator iterator = waitableHandleList.begin(); + iterator != waitableHandleList.end(); + ++iterator) + { + // Wait for multiple objects + handleList.push_back(std::make_pair(*iterator, WaitMode::Read)); + } + + // Do waiting + return WaitForMultipleHandles(handleList, miliseconds); +} + +WaitableHandleIndexList WaitForMultipleHandles( + const WaitableHandleListEx &waitableHandleListEx, + unsigned long miliseconds) +{ + fd_set readFds, writeFds, errorFds; + + // Fill sets + int maxFd = -1; + + FD_ZERO(&readFds); + FD_ZERO(&writeFds); + FD_ZERO(&errorFds); + + // Add read wait handles + for (WaitableHandleListEx::const_iterator iterator = + waitableHandleListEx.begin(); + iterator != waitableHandleListEx.end(); + ++iterator) + { + if (iterator->first > maxFd) { + maxFd = iterator->first; + } + + CheckWaitableHandle(iterator->first); + + // Handle errors along with read and write events + FD_SET(iterator->first, &errorFds); + + if (iterator->second == WaitMode::Read) { + FD_SET(iterator->first, &readFds); + } else if (iterator->second == WaitMode::Write) { + FD_SET(iterator->first, &writeFds); + } + } + + // Do select + timeval timeout; + timeval *effectiveTimeout = NULL; + if (miliseconds != 0xFFFFFFFF) { + timeout.tv_sec = miliseconds / 1000; + timeout.tv_usec = (miliseconds % 1000) * 1000; + effectiveTimeout = &timeout; + } + + if (TEMP_FAILURE_RETRY(select(maxFd + 1, &readFds, &writeFds, &errorFds, + effectiveTimeout)) == -1) + { + Throw(WaitFailed); + } + + // Check results + WaitableHandleIndexList indexes; + size_t index = 0; + + for (WaitableHandleListEx::const_iterator iterator = + waitableHandleListEx.begin(); + iterator != waitableHandleListEx.end(); + ++iterator) + { + // Always return errors, no matter what type of listening is set + if (FD_ISSET(iterator->first, &errorFds)) { + indexes.push_back(index); + } else if (iterator->second == WaitMode::Read) { + if (FD_ISSET(iterator->first, &readFds)) { + indexes.push_back(index); + } + } else if (iterator->second == WaitMode::Write) { + if (FD_ISSET(iterator->first, &writeFds)) { + indexes.push_back(index); + } + } + ++index; + } + + // Successfuly awaited some events or timeout occurred + return indexes; +} +} // namespace DPL diff --git a/modules/core/src/waitable_handle_watch_support.cpp b/modules/core/src/waitable_handle_watch_support.cpp new file mode 100644 index 0000000..53f8b65 --- /dev/null +++ b/modules/core/src/waitable_handle_watch_support.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_handle_watch_support.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable handle watch + * support + */ +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +WaitableHandleWatchSupport::WaitableHandleWatchSupport() +{} + +WaitableHandleWatchSupport::~WaitableHandleWatchSupport() +{ + // Developer assertions + if (!m_watchersMap.empty()) { + LogWarning("### Leaked watchers map dump ###"); + + for (WaitableHandleWatchersMap::const_iterator iterator = + m_watchersMap.begin(); + iterator != m_watchersMap.end(); + ++iterator) + { + LogWarning("### Waitable handle: " << iterator->first); + + LogWarning( + "### Read listeners: " << + iterator->second.readListenersCount); + LogWarning( + "### Write listeners: " << + iterator->second.writeListenersCount); + + for (WaitableHandleListenerList::const_iterator listenersIterator = + iterator->second.listeners.begin(); + listenersIterator != iterator->second.listeners.end(); + ++listenersIterator) + { + LogWarning( + "### Mode: " << listenersIterator->mode << + ". Listener: 0x" << std::hex << listenersIterator->listener); + } + } + } +} + +WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const +{ + return m_watchersInvoker.GetHandle(); +} + +WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const +{ + // Critical section + { + RecursiveMutex::ScopedLock lock(&m_watchersMutex); + + WaitableHandleListEx handleList; + + for (WaitableHandleWatchersMap::const_iterator iterator = + m_watchersMap.begin(); + iterator != m_watchersMap.end(); + ++iterator) + { + // Register waitable event id for wait + // Check if there are any read listeners and write listeners + // and register for both if applicable + if (iterator->second.readListenersCount > 0) { + handleList.push_back(std::make_pair(iterator->first, + WaitMode::Read)); + } + + if (iterator->second.writeListenersCount > 0) { + handleList.push_back(std::make_pair(iterator->first, + WaitMode::Write)); + } + } + + return handleList; + } +} + +void WaitableHandleWatchSupport::InvokerFinished() +{ + LogPedantic("Invoker finished called"); + + // Reset invoker + m_watchersInvoker.Reset(); + + // Commit invoke + m_watchersInvokerCommit.Signal(); +} + +void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle, + WaitMode::Type mode) +{ + // + // Waitable event occurred + // Now call all listeners for that waitable event. It is possible + // that some of listeners early disappeared. This is not a problem. + // Warning: Listeners and/or watcher may also disappear during dispatching + // handlers! + // + LogPedantic("Waitable event occurred"); + + // Critical section for other threads + { + RecursiveMutex::ScopedLock lock(&m_watchersMutex); + + // Notice: We must carefully call watchers here as they may disappear + // (zero listeners) or be created during each of handler call + // All removed listeners are handled correctly. Adding + // additional listener to the same waitable handle + // during handler dispatch sequence is _not_ supported. + WaitableHandleWatchersMap trackedWatchers = m_watchersMap; + + for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator + = trackedWatchers.begin(); + trackedWatchersIterator != trackedWatchers.end(); + ++trackedWatchersIterator) + { + // Check if this watcher still exists + // If not, go to next tracked watcher + if (m_watchersMap.find(trackedWatchersIterator->first) == + m_watchersMap.end()) + { + LogPedantic("Watcher disappeared during watcher handler"); + continue; + } + + // Is this is a waitable handle that we are searching for ? + if (waitableHandle != trackedWatchersIterator->first) { + continue; + } + + // Track watcher listeners list + WaitableHandleListenerList trackedListeners = + trackedWatchersIterator->second.listeners; + + LogPedantic( + "Calling waitable event listeners (" << + trackedListeners.size() << ")..."); + + // Notice: We must carefully call listeners here as they may + // disappear or be created during each of handler call + // All removed listeners are handled correctly. Adding + // additional listener to the same waitable handle + // during handler dispatch sequence is should be also + // handled, as an extremly case. + + // Call all waitable event listeners who listen for that event + for (WaitableHandleListenerList::const_iterator + trackedListenersIterator = trackedListeners.begin(); + trackedListenersIterator != trackedListeners.end(); + ++trackedListenersIterator) + { + // Check if this watcher still exists + // If not, there cannot be another one. Must exit now (after + // break, we actually exit) + if (m_watchersMap.find(trackedWatchersIterator->first) == + m_watchersMap.end()) + { + LogPedantic("Watcher disappeared during watcher handler"); + break; + } + + // Check if this watcher listener still exists + // If not, go to next tracked watcher listener + bool listenerStillExists = false; + + for (WaitableHandleListenerList::const_iterator + searchListenerIterator = + trackedWatchersIterator->second.listeners.begin(); + searchListenerIterator != + trackedWatchersIterator->second.listeners.end(); + ++searchListenerIterator) + { + if (searchListenerIterator->listener == + trackedListenersIterator->listener && + searchListenerIterator->mode == + trackedListenersIterator->mode) + { + listenerStillExists = true; + break; + } + } + + if (!listenerStillExists) { + LogPedantic( + "Watcher listener disappeared during watcher handler"); + break; + } + + // Is this is a listener mode that we are searching for ? + if (mode != trackedListenersIterator->mode) { + continue; + } + + // Call waitable event watch listener + LogPedantic("Before tracker listener call..."); + trackedListenersIterator->listener->OnWaitableHandleEvent( + trackedWatchersIterator->first, + trackedListenersIterator->mode); + LogPedantic("After tracker listener call..."); + } + + // Now call all those listeners who registered during listener calls + // FIXME: Implement! Notice, that scenario may be recursive! + + LogPedantic("Waitable event listeners called"); + + // No more waitable events possible - consistency check + break; + } + } +} + +void WaitableHandleWatchSupport::AddWaitableHandleWatch( + WaitableHandleListener* listener, + WaitableHandle waitableHandle, + WaitMode::Type mode) +{ + // Enter waitable event list critical section + RecursiveMutex::ScopedLock lock(&m_watchersMutex); + + // Find proper list to register into + WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find( + waitableHandle); + + if (mapIterator != m_watchersMap.end()) { + // Assert if there is no such listener already that is listening in this + // mode + for (WaitableHandleListenerList::iterator listenersIterator = + mapIterator->second.listeners.begin(); + listenersIterator != mapIterator->second.listeners.end(); + ++listenersIterator) + { + // Must not insert same listener-mode pair + Assert( + listenersIterator->listener != listener || + listenersIterator->mode != mode); + } + } + + LogPedantic("Adding waitable handle watch: " << waitableHandle); + + // Push new waitable event watch + if (mapIterator != m_watchersMap.end()) { + mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener, + mode)); + } else { + m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher( + listener, mode)); + } + + // Update counters + switch (mode) { + case WaitMode::Read: + m_watchersMap[waitableHandle].readListenersCount++; + break; + + case WaitMode::Write: + m_watchersMap[waitableHandle].writeListenersCount++; + break; + + default: + Assert(0); + } + + // Trigger waitable event invoker to commit changes + CommitInvoker(); + + LogPedantic("Waitable event watch added and invoker signaled"); +} + +void WaitableHandleWatchSupport::RemoveWaitableHandleWatch( + WaitableHandleListener *listener, + WaitableHandle waitableHandle, + WaitMode::Type mode) +{ + // Enter waitable event list critical section + RecursiveMutex::ScopedLock lock(&m_watchersMutex); + + // Find proper list with listener + WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find( + waitableHandle); + + Assert(mapIterator != m_watchersMap.end()); + + // Assert if there is such listener and mode + WaitableHandleListenerList::iterator listIterator = + mapIterator->second.listeners.end(); + + for (WaitableHandleListenerList::iterator listenersIterator = + mapIterator->second.listeners.begin(); + listenersIterator != mapIterator->second.listeners.end(); + ++listenersIterator) + { + // Check same pair listener-mode + if (listenersIterator->listener == listener && + listenersIterator->mode == mode) + { + listIterator = listenersIterator; + break; + } + } + + // Same pair listener-mode must exist + Assert(listIterator != mapIterator->second.listeners.end()); + + LogPedantic("Removing waitable handle watch: " << waitableHandle); + + // Remove waitable event watch + mapIterator->second.listeners.erase(listIterator); + + // Update counters + switch (mode) { + case WaitMode::Read: + mapIterator->second.readListenersCount--; + break; + + case WaitMode::Write: + mapIterator->second.writeListenersCount--; + break; + + default: + Assert(0); + } + + // If list is empty, remove it too + if (mapIterator->second.listeners.empty()) { + m_watchersMap.erase(mapIterator); + } + + // Trigger waitable event invoker to commit changes + CommitInvoker(); + + LogPedantic("Waitable event watch removed and invoker signaled"); +} + +void WaitableHandleWatchSupport::CommitInvoker() +{ + // Check calling context and execute invoker + if (Thread::GetCurrentThread() == GetInvokerThread()) { + LogPedantic("Calling direct invoker"); + + // Direct invoker call + HandleDirectInvoker(); + } else { + LogPedantic("Calling indirect invoker"); + + // Indirect invoker call + m_watchersInvoker.Signal(); + + WaitableHandleList waitHandles; + waitHandles.push_back(m_watchersInvokerCommit.GetHandle()); + WaitForMultipleHandles(waitHandles); + + m_watchersInvokerCommit.Reset(); + } +} + +WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext() +{ + // In threaded context, return thread waitable handle watch implementation + // In main loop, return main waitable handle watch implementation + if (Thread::GetCurrentThread() != NULL) { + return Thread::GetCurrentThread(); + } else { + return &MainSingleton::Instance(); + } +} +} // namespace DPL diff --git a/modules/core/src/zip_input.cpp b/modules/core/src/zip_input.cpp new file mode 100644 index 0000000..fadc60f --- /dev/null +++ b/modules/core/src/zip_input.cpp @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file zip_input.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of zip input + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace // anonymous +{ +const size_t EXTRACT_BUFFER_SIZE = 4096; + +class ScopedUnzClose +{ + private: + unzFile m_file; + + public: + ScopedUnzClose(unzFile file) : + m_file(file) + {} + + ~ScopedUnzClose() + { + if (!m_file) { + return; + } + + if (unzClose(m_file) != UNZ_OK) { + LogPedantic("Failed to close zip input file"); + } + } + + unzFile Release() + { + unzFile file = m_file; + + m_file = NULL; + + return file; + } +}; +} // namespace anonymous + +/* + * Seekable multiplexing device + * + * Explanation: + * Minizip library lacks serious support for multithreaded + * access to zip files. Thus, they cannot be easily extracted + * simulateously. Here is introduced seekable device which does + * have a context with seek index for each file. File is mapped to + * memory and because of that no real synchronization is needed. + * Memory addresses can be indexed. + * + * About generalization: + * To achieve the same results on abstract input device, there must be + * provided a mechanism to read data from random address without + * synchronization. + * In other words: stateless. As described above, stateless property can be + * achieved via memory mapping. + */ +class Device +{ + private: + int m_handle; + off64_t m_size; // file mapping size + unsigned char *m_address; // mapping base address + + struct File + { + off64_t offset; + Device *device; + + File(Device *d) : + offset(0), + device(d) + {} + }; + + public: + Device(const std::string &fileName) + { + LogPedantic("Creating file mapping"); + // Open device and map it to user space + int file = TEMP_FAILURE_RETRY(open(fileName.c_str(), O_RDONLY)); + + if (file == -1) { + int error = errno; + ThrowMsg(ZipInput::Exception::OpenFailed, + "Failed to open file. errno = " << error); + } + + // Scoped close on file + ScopedClose scopedClose(file); + + // Calculate file size + off64_t size = lseek64(file, 0, SEEK_END); + + if (size == static_cast(-1)) { + int error = errno; + ThrowMsg(ZipInput::Exception::OpenFailed, + "Failed to seek file. errno = " << error); + } + + // Map file to usespace + void *address = mmap(0, static_cast(size), + PROT_READ, MAP_SHARED, file, 0); + + if (address == MAP_FAILED) { + int error = errno; + ThrowMsg(ZipInput::Exception::OpenFailed, + "Failed to map file. errno = " << error); + } + + // Release scoped close + m_handle = scopedClose.Release(); + + // Save mapped up address + m_size = size; + m_address = static_cast(address); + + LogPedantic("Created file mapping: " << fileName << + " of size: " << m_size << + " at address: " << std::hex << + static_cast(m_address)); + } + + ~Device() + { + // Close mapping + if (munmap(m_address, static_cast(m_size)) == -1) { + int error = errno; + LogPedantic("Failed to munmap file. errno = " << error); + } + + // Close file descriptor + if (close(m_handle) == -1) { + int error = errno; + LogPedantic("Failed to close file. errno = " << error); + } + } + + // zlib_filefunc64_def interface: files + static voidpf ZCALLBACK open64_file(voidpf opaque, + const void* /*filename*/, + int /*mode*/) + { + Device *device = static_cast(opaque); + + // Open file for master device + return new File(device); + } + + static uLong ZCALLBACK read_file(voidpf opaque, + voidpf pstream, + void* buf, + uLong size) + { + Device *device = static_cast(opaque); + File *deviceFile = static_cast(pstream); + + // Check if offset is out of bounds + if (deviceFile->offset >= device->m_size) { + LogPedantic("Device: read offset out of bounds"); + return -1; + } + + off64_t bytesLeft = device->m_size - + deviceFile->offset; + + off64_t bytesToRead; + + // Calculate bytes to read + if (static_cast(size) > bytesLeft) { + bytesToRead = bytesLeft; + } else { + bytesToRead = static_cast(size); + } + + // Do copy + memcpy(buf, + device->m_address + deviceFile->offset, + static_cast(bytesToRead)); + + // Increment file offset + deviceFile->offset += bytesToRead; + + // Return bytes that were actually read + return static_cast(bytesToRead); + } + + static uLong ZCALLBACK write_file(voidpf /*opaque*/, + voidpf /*stream*/, + const void* /*buf*/, + uLong /*size*/) + { + // Not supported by device + LogPedantic("Unsupported function called!"); + return -1; + } + + static int ZCALLBACK close_file(voidpf /*opaque*/, voidpf stream) + { + File *deviceFile = static_cast(stream); + + // Delete file + delete deviceFile; + + // Always OK + return 0; + } + + static int ZCALLBACK testerror_file(voidpf /*opaque*/, voidpf /*stream*/) + { + // No errors + return 0; + } + + static ZPOS64_T ZCALLBACK tell64_file(voidpf /*opaque*/, voidpf stream) + { + File *deviceFile = static_cast(stream); + + return static_cast(deviceFile->offset); + } + + static long ZCALLBACK seek64_file(voidpf opaque, + voidpf stream, + ZPOS64_T offset, + int origin) + { + Device *device = static_cast(opaque); + File *deviceFile = static_cast(stream); + + switch (origin) { + case ZLIB_FILEFUNC_SEEK_SET: + deviceFile->offset = static_cast(offset); + + break; + + case ZLIB_FILEFUNC_SEEK_CUR: + deviceFile->offset += static_cast(offset); + + break; + + case ZLIB_FILEFUNC_SEEK_END: + deviceFile->offset = + device->m_size - + static_cast(offset); + + break; + + default: + return -1; + } + + return 0; + } +}; + +ZipInput::ZipInput(const std::string &fileName) : + m_device(NULL), + m_numberOfFiles(0), + m_globalComment(), + m_totalUncompressedSize(0), + m_fileInfos() +{ + LogPedantic("Zip input file: " << fileName); + + // Create master device + LogPedantic("Creating master device"); + std::unique_ptr device(new Device(fileName)); + + // Open master file + zlib_filefunc64_def interface; + interface.zopen64_file = &Device::open64_file; + interface.zread_file = &Device::read_file; + interface.zwrite_file = &Device::write_file; + interface.ztell64_file = &Device::tell64_file; + interface.zseek64_file = &Device::seek64_file; + interface.zclose_file = &Device::close_file; + interface.zerror_file = &Device::testerror_file; + interface.opaque = device.get(); + + LogPedantic("Opening zip file"); + unzFile file = unzOpen2_64(NULL, &interface); + + if (file == NULL) { + LogPedantic("Failed to open zip file"); + + // Some errror occured + ThrowMsg(Exception::OpenFailed, + "Failed to open zip file: " << fileName); + } + + // Begin scope + ScopedUnzClose scopedUnzClose(file); + + // Read contents + ReadGlobalInfo(file); + ReadGlobalComment(file); + ReadInfos(file); + + // Release scoped unz close + m_masterFile = scopedUnzClose.Release(); + m_device = device.release(); + + LogPedantic("Zip file opened"); +} + +ZipInput::~ZipInput() +{ + // Close zip + if (unzClose(static_cast(m_masterFile)) != UNZ_OK) { + LogPedantic("Failed to close zip input file"); + } + + // Close device + delete m_device; +} + +void ZipInput::ReadGlobalInfo(void *masterFile) +{ + // Read number of entries and global comment + unz_global_info globalInfo; + + if (unzGetGlobalInfo(static_cast(masterFile), + &globalInfo) != UNZ_OK) + { + LogPedantic("Failed to read zip global info"); + + ThrowMsg(Exception::ReadGlobalInfoFailed, + "Failed to read global info"); + } + + m_numberOfFiles = static_cast(globalInfo.number_entry); + m_globalCommentSize = static_cast(globalInfo.size_comment); + + LogPedantic("Number of files: " << m_numberOfFiles); + LogPedantic("Global comment size: " << m_globalCommentSize); +} + +void ZipInput::ReadGlobalComment(void *masterFile) +{ + ScopedArray comment(new char[m_globalCommentSize + 1]); + + if (unzGetGlobalComment(static_cast(masterFile), + comment.Get(), + m_globalCommentSize + 1) != UNZ_OK) + { + LogPedantic("Failed to read zip global comment"); + + ThrowMsg(Exception::ReadGlobalCommentFailed, + "Failed to read global comment"); + } + + m_globalComment = comment.Get(); + LogPedantic("Global comment: " << m_globalComment); +} + +void ZipInput::ReadInfos(void *masterFile) +{ + // Read infos + m_fileInfos.reserve(m_numberOfFiles); + + if (unzGoToFirstFile(static_cast(masterFile)) != UNZ_OK) { + LogPedantic("Failed to go to first file"); + ThrowMsg(Exception::SeekFileFailed, "Failed to seek first file"); + } + + for (size_t i = 0; i < m_numberOfFiles; ++i) { + unz_file_pos_s filePos; + + if (unzGetFilePos(static_cast(masterFile), + &filePos) != UNZ_OK) + { + LogPedantic("Failed to get file pos"); + ThrowMsg(Exception::FileInfoFailed, "Failed to get zip file info"); + } + + unz_file_info64 fileInfo; + + if (unzGetCurrentFileInfo64(static_cast(masterFile), + &fileInfo, + NULL, + 0, + NULL, + 0, + NULL, + 0) != UNZ_OK) + { + LogPedantic("Failed to get file pos"); + ThrowMsg(Exception::FileInfoFailed, "Failed to get zip file info"); + } + + ScopedArray fileName(new char[fileInfo.size_filename + 1]); + ScopedArray fileComment(new char[fileInfo.size_file_comment + 1]); + + if (unzGetCurrentFileInfo64(static_cast(masterFile), + &fileInfo, + fileName.Get(), + fileInfo.size_filename + 1, + NULL, + 0, + fileComment.Get(), + fileInfo.size_file_comment + 1) != UNZ_OK) + { + LogPedantic("Failed to get file pos"); + ThrowMsg(Exception::FileInfoFailed, "Failed to get zip file info"); + } + + m_fileInfos.push_back( + FileInfo( + FileHandle( + static_cast(filePos.pos_in_zip_directory), + static_cast(filePos.num_of_file) + ), + std::string(fileName.Get()), + std::string(fileComment.Get()), + static_cast(fileInfo.compressed_size), + static_cast(fileInfo.uncompressed_size) + ) + ); + m_totalUncompressedSize += static_cast(fileInfo.uncompressed_size); + + // If this is not the last file, go to next one + if (i != m_numberOfFiles - 1) { + if (unzGoToNextFile( + static_cast(masterFile)) != UNZ_OK) + { + LogPedantic("Failed to go to next file"); + + ThrowMsg(Exception::FileInfoFailed, + "Failed to go to next file"); + } + } + } +} + +ZipInput::const_iterator ZipInput::begin() const +{ + return m_fileInfos.begin(); +} + +ZipInput::const_iterator ZipInput::end() const +{ + return m_fileInfos.end(); +} + +ZipInput::const_reverse_iterator ZipInput::rbegin() const +{ + return m_fileInfos.rbegin(); +} + +ZipInput::const_reverse_iterator ZipInput::rend() const +{ + return m_fileInfos.rend(); +} + +ZipInput::size_type ZipInput::size() const +{ + return m_fileInfos.size(); +} + +ZipInput::File *ZipInput::OpenFile(const std::string &fileName) +{ + FOREACH(iterator, m_fileInfos) + { + if (iterator->name == fileName) { + return new File(m_device, iterator->handle); + } + } + + ThrowMsg(Exception::OpenFileFailed, + "Failed to open zip file: " << fileName); +} + +ZipInput::File::File(class Device *device, FileHandle handle) +{ + // Open file file + zlib_filefunc64_def interface; + interface.zopen64_file = &Device::open64_file; + interface.zread_file = &Device::read_file; + interface.zwrite_file = &Device::write_file; + interface.ztell64_file = &Device::tell64_file; + interface.zseek64_file = &Device::seek64_file; + interface.zclose_file = &Device::close_file; + interface.zerror_file = &Device::testerror_file; + interface.opaque = device; + + LogPedantic("Opening zip file"); + unzFile file = unzOpen2_64(NULL, &interface); + + if (file == NULL) { + LogPedantic("Failed to open zip file"); + + // Some errror occured + ThrowMsg(ZipInput::Exception::OpenFileFailed, + "Failed to open zip file"); + } + + // Begin scope + ScopedUnzClose scopedUnzClose(file); + + // Look up file handle + unz64_file_pos filePos = { + static_cast(handle.first), + static_cast(handle.second) + }; + + if (unzGoToFilePos64(file, &filePos) != UNZ_OK) { + LogPedantic("Failed to seek to zip file"); + + // Some errror occured + ThrowMsg(ZipInput::Exception::OpenFileFailed, + "Failed to seek into zip file"); + } + + // Open current file for reading + if (unzOpenCurrentFile(file) != UNZ_OK) { + LogPedantic("Failed to open current zip file"); + + // Some errror occured + ThrowMsg(ZipInput::Exception::OpenFileFailed, + "Failed to open current zip file"); + } + + // Release scoped unz close + m_file = scopedUnzClose.Release(); + + LogPedantic("Zip file opened"); +} + +ZipInput::File::~File() +{ + // Close current file for reading + if (unzCloseCurrentFile(static_cast(m_file)) != UNZ_OK) { + LogPedantic("Failed to close current zip input file"); + } + + // Close zip file + if (unzClose(static_cast(m_file)) != UNZ_OK) { + LogPedantic("Failed to close zip input file"); + } +} + +DPL::BinaryQueueAutoPtr ZipInput::File::Read(size_t size) +{ + // Do not even try to unzip if requested zero bytes + if (size == 0) { + return DPL::BinaryQueueAutoPtr(new DPL::BinaryQueue()); + } + + // Calc data to read + size_t sizeToRead = size > EXTRACT_BUFFER_SIZE ? + EXTRACT_BUFFER_SIZE : + size; + + // Extract zip file data (one-copy) + ScopedFree rawBuffer(malloc(sizeToRead)); + + if (!rawBuffer) { + throw std::bad_alloc(); + } + + // Do unpack + int bytes = unzReadCurrentFile(static_cast(m_file), + rawBuffer.Get(), + sizeToRead); + + // Internal unzipper error + if (bytes < 0) { + LogPedantic("Extract failed. Error: " << bytes); + + ThrowMsg(ZipInput::Exception::ReadFileFailed, + "Failed to extract file with error: " << bytes); + } + + // Data was read (may be zero bytes) + DPL::BinaryQueueAutoPtr buffer(new DPL::BinaryQueue()); + + buffer->AppendUnmanaged(rawBuffer.Get(), + static_cast(bytes), + &DPL::BinaryQueue::BufferDeleterFree, + NULL); + + rawBuffer.Release(); + + return buffer; +} + +const std::string &ZipInput::GetGlobalComment() const +{ + return m_globalComment; +} + +bool ZipInput::empty() const +{ + return m_fileInfos.empty(); +} + +size_t ZipInput::GetTotalUncompressedSize() const +{ + return m_totalUncompressedSize; +} +} // namespace DPL diff --git a/modules/custom_handler_dao/CMakeLists.txt b/modules/custom_handler_dao/CMakeLists.txt new file mode 100644 index 0000000..4a88649 --- /dev/null +++ b/modules/custom_handler_dao/CMakeLists.txt @@ -0,0 +1,84 @@ +SET(TARGET_CUSTOM_HANDLER_DAO_DB "Sqlite3DbCustomHandler") + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_BINARY_DIR}/modules/custom_handler_dao/database_checksum_custom_handler.h + COMMAND ${CMAKE_SOURCE_DIR}/modules/custom_handler_dao/orm/gen_db_md5.sh + ARGS ${CMAKE_BINARY_DIR}/modules/custom_handler_dao/database_checksum_custom_handler.h + ${CMAKE_SOURCE_DIR}/modules/custom_handler_dao/orm/custom_handler_db + DEPENDS ${CMAKE_SOURCE_DIR}/modules/custom_handler_dao/orm/custom_handler_db + ${CMAKE_SOURCE_DIR}/modules/custom_handler_dao/orm/gen_db_md5.sh + COMMENT "Generating WRT custom handlers database checksum" + ) + +ADD_CUSTOM_COMMAND( OUTPUT .wrt_custom_handler.db + COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/.wrt_custom_handler.db + COMMAND gcc -Wall -include ${CMAKE_BINARY_DIR}/modules/custom_handler_dao/database_checksum_custom_handler.h -I${PROJECT_SOURCE_DIR}/modules/db/include -I${PROJECT_SOURCE_DIR}/modules/custom_handler_dao/orm -E ${PROJECT_SOURCE_DIR}/modules/custom_handler_dao/orm/custom_handler_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_BINARY_DIR}/wrt_custom_handler_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_BINARY_DIR}/.wrt_custom_handler.db ".read ${CMAKE_CURRENT_BINARY_DIR}/wrt_custom_handler_db.sql" || rm -f ${CMAKE_CURRENT_BINARY_DIR}/.wrt_custom_handler.db + DEPENDS ${CMAKE_BINARY_DIR}/modules/custom_handler_dao/database_checksum_custom_handler.h ${PROJECT_SOURCE_DIR}/modules/custom_handler_dao/orm/custom_handler_db_sql_generator.h ${PROJECT_SOURCE_DIR}/modules/custom_handler_dao/orm/custom_handler_db + ) + +ADD_CUSTOM_COMMAND( OUTPUT .wrt_custom_handler.db-journal + COMMAND touch + ARGS ${CMAKE_CURRENT_BINARY_DIR}/.wrt_custom_handler.db-journal + ) + +ADD_CUSTOM_TARGET(${TARGET_CUSTOM_HANDLER_DAO_DB} ALL DEPENDS .wrt_custom_handler.db .wrt_custom_handler.db-journal) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/wrt_custom_handler_db.sql DESTINATION share/wrt-engine/) + +############################################################################### + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(CUSTOM_HANDLER_DAO_DEPS + glib-2.0 + dlog + REQUIRED) + +SET(CUSTOM_HANDLER_DAO_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/modules/custom_handler_dao/include + ${PROJECT_SOURCE_DIR}/modules/custom_handler_dao/orm + ${PROJECT_SOURCE_DIR}/modules/core/include + ${PROJECT_SOURCE_DIR}/modules/db/include + ${PROJECT_SOURCE_DIR}/modules/log/include +) + + +SET(CUSTOM_HANDLER_DAO_RO_SOURCES + dao/CustomHandlerDatabase.cpp + dao/custom_handler_dao_read_only.cpp +) + +SET(CUSTOM_HANDLER_DAO_RW_SOURCES + dao/custom_handler_dao.cpp +) + + +INCLUDE_DIRECTORIES(${CUSTOM_HANDLER_DAO_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${CUSTOM_HANDLER_DAO_DEPS_INCLUDE_DIRS}) + +ADD_LIBRARY(${TARGET_CUSTOM_HANDLER_DAO_RO_LIB} SHARED ${CUSTOM_HANDLER_DAO_RO_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_CUSTOM_HANDLER_DAO_RO_LIB} PROPERTIES SOVERSION ${API_VERSION} VERSION ${VERSION}) +SET_TARGET_PROPERTIES(${TARGET_CUSTOM_HANDLER_DAO_RO_LIB} PROPERTIES COMPILE_FLAGS "-include ${CMAKE_BINARY_DIR}/modules/custom_handler_dao/database_checksum_custom_handler.h") +TARGET_LINK_LIBRARIES(${TARGET_CUSTOM_HANDLER_DAO_RO_LIB} ${TARGET_CUSTOM_HANDLER_DAO_LIB}) +ADD_DEPENDENCIES(${TARGET_CUSTOM_HANDLER_DAO_RO_LIB} ${TARGET_CUSTOM_HANDLER_DAO_DB}) + +ADD_LIBRARY(${TARGET_CUSTOM_HANDLER_DAO_RW_LIB} SHARED ${CUSTOM_HANDLER_DAO_RW_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_CUSTOM_HANDLER_DAO_RW_LIB} PROPERTIES SOVERSION ${API_VERSION} VERSION ${VERSION}) +SET_TARGET_PROPERTIES(${TARGET_CUSTOM_HANDLER_DAO_RW_LIB} PROPERTIES COMPILE_FLAGS "-include ${CMAKE_BINARY_DIR}/modules/custom_handler_dao/database_checksum_custom_handler.h") +TARGET_LINK_LIBRARIES(${TARGET_CUSTOM_HANDLER_DAO_RW_LIB} ${TARGET_CUSTOM_HANDLER_DAO_RO_LIB}) +ADD_DEPENDENCIES(${TARGET_CUSTOM_HANDLER_DAO_RW_LIB} ${TARGET_CUSTOM_HANDLER_DAO_DB}) + +INSTALL(TARGETS ${TARGET_CUSTOM_HANDLER_DAO_RO_LIB} DESTINATION lib) +INSTALL(TARGETS ${TARGET_CUSTOM_HANDLER_DAO_RW_LIB} DESTINATION lib) + +INSTALL(FILES + include/wrt-commons/custom-handler-dao-ro/common_dao_types.h + include/wrt-commons/custom-handler-dao-ro/CustomHandlerDatabase.h + include/wrt-commons/custom-handler-dao-ro/custom_handler_dao_read_only.h + DESTINATION include/dpl-efl/wrt-commons/custom-handler-dao-ro +) + +INSTALL(FILES + include/wrt-commons/custom-handler-dao-rw/custom_handler_dao.h + DESTINATION include/dpl-efl/wrt-commons/custom-handler-dao-rw +) diff --git a/modules/custom_handler_dao/dao/CustomHandlerDatabase.cpp b/modules/custom_handler_dao/dao/CustomHandlerDatabase.cpp new file mode 100644 index 0000000..5f26fd7 --- /dev/null +++ b/modules/custom_handler_dao/dao/CustomHandlerDatabase.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +namespace CustomHandlerDB { +namespace Interface { +namespace { +const char* CustomHandler_DB_DATABASE = "/opt/usr/dbspace/.wrt_custom_handler.db"; +DPL::DB::SqlConnection::Flag::Type CustomHandler_DB_FLAGS = + DPL::DB::SqlConnection::Flag::UseLucene; +} + +DPL::Mutex g_dbQueriesMutex; +DPL::DB::ThreadDatabaseSupport g_dbInterface(CustomHandler_DB_DATABASE, + CustomHandler_DB_FLAGS); + +void attachDatabaseRO() +{ + g_dbInterface.AttachToThread(DPL::DB::SqlConnection::Flag::RO); +} + +void attachDatabaseRW() +{ + g_dbInterface.AttachToThread(DPL::DB::SqlConnection::Flag::RW); +} + +void detachDatabase() +{ + g_dbInterface.DetachFromThread(); +} +} //namespace Interface +} //namespace CustomHandlerDB diff --git a/modules/custom_handler_dao/dao/custom_handler_dao.cpp b/modules/custom_handler_dao/dao/custom_handler_dao.cpp new file mode 100644 index 0000000..6d57771 --- /dev/null +++ b/modules/custom_handler_dao/dao/custom_handler_dao.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file custom_handler_dao.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the definition of custom handler dao class. + */ + +#include +#include +#include +#include + +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::custom_handler; + +namespace CustomHandlerDB { +namespace { +template +void fillRow(T& row, const CustomHandler& handler, const DPL::String& pkgName) +{ + row.Set_app_id(pkgName); + row.Set_target(handler.target); + row.Set_base_url(handler.base_url); + row.Set_url(handler.url); + row.Set_title(handler.title); + row.Set_user_allowed(handler.user_decision); +} +} // namespace + +CustomHandlerDAO::CustomHandlerDAO(const DPL::String& pkgName) : + CustomHandlerDAOReadOnly(pkgName) +{} + +CustomHandlerDAO::~CustomHandlerDAO() +{} + +void CustomHandlerDAO::registerContentHandler(const CustomHandler& handler) +{ + LogDebug("Registering content handler " << handler.target << " " << + handler.base_url); + Try { + if (handler.user_decision & Agreed) { + //need to disable all previous, agreed entries + CUSTOM_HANDLER_DB_SELECT(select, ContentHandlers); + select->Where(And(Equals(handler.target), + Or(Equals(Agreed), + Equals( + AgreedPermanently)) + )); + ContentHandlers::Select::RowList rows = select->GetRowList(); + if (rows.size() > 1) { + //more than one activ content handler - not good. Remove all. + //this should never happen + LogError("Database data incoherent."); + CUSTOM_HANDLER_DB_DELETE(deleteContent, ContentHandlers); + deleteContent->Where(And(Equals( + handler.target), + Or(Equals(Agreed), + Equals( + AgreedPermanently)))); + deleteContent->Execute(); + //all content handlers removed. New one can be inserted + } else if (!rows.empty()) { + //one active handler. Can be updaed + LogDebug("Activ content handler exist. Update"); + CUSTOM_HANDLER_DB_UPDATE(update, ContentHandlers); + update->Where(And(Equals(handler. + target), + Or(Equals( + Agreed), + Equals( + AgreedPermanently)) + )); + ContentHandlers::Row rowToUpdate = rows.front(); + + if (handler.user_decision & DecisionSaved) { + //do not ask about previous one + rowToUpdate.Set_user_allowed(DeclinedPermanently); + } else { + //ask for next time + rowToUpdate.Set_user_allowed(Declined); + } + update->Values(rowToUpdate); + update->Execute(); + } + } + LogDebug("Inserting new content handler"); + ContentHandlers::Row row; + fillRow(row, handler, m_pkgName); + if (getContentHandler(handler.target, handler.url, handler.base_url)) { + LogDebug("Content handler exist. Update its state"); + CUSTOM_HANDLER_DB_UPDATE(updateRow, ContentHandlers); + updateRow->Where(And(Equals(m_pkgName), + And(Equals(handler. + target), + And(Equals(handler. + url), + Equals( + handler.base_url))))); + updateRow->Values(row); + updateRow->Execute(); + LogDebug("updated"); + return; + } + CUSTOM_HANDLER_DB_INSERT(insert, ContentHandlers); + insert->Values(row); + insert->Execute(); + LogDebug("insterted"); + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to register custom handler"); + } +} + +void CustomHandlerDAO::registerProtocolHandler(const CustomHandler& handler) +{ + LogDebug("Registering protocol handler " << handler.target << " " << + handler.base_url); + Try { + if (handler.user_decision & Agreed) { + //need to disable all previous, agreed entries + CUSTOM_HANDLER_DB_SELECT(select, ProtocolHandlers); + select->Where(And(Equals(handler.target), + Or(Equals(Agreed), + Equals( + AgreedPermanently)) + )); + ProtocolHandlers::Select::RowList rows = select->GetRowList(); + if (rows.size() > 1) { + //more than one activ protocol handler - not good. Remove all. + //this should never happen + LogError("Database data incoherent."); + CUSTOM_HANDLER_DB_DELETE(deleteProtocol, ProtocolHandlers); + deleteProtocol->Where(And(Equals( + handler.target), + Or(Equals(Agreed), + Equals( + AgreedPermanently)))); + deleteProtocol->Execute(); + //all protocol handlers removed. New one can be inserted + } else if (!rows.empty()) { + //one active handler. Can be updaed + CUSTOM_HANDLER_DB_UPDATE(update, ProtocolHandlers); + update->Where(And(Equals(handler. + target), + Or(Equals( + Agreed), + Equals( + AgreedPermanently)) + )); + ProtocolHandlers::Row rowToUpdate = rows.front(); + + if (handler.user_decision & DecisionSaved) { + //do not ask about previous one + rowToUpdate.Set_user_allowed(DeclinedPermanently); + } else { + //ask for next time + rowToUpdate.Set_user_allowed(Declined); + } + update->Values(rowToUpdate); + update->Execute(); + } + } + LogDebug("Inserting new protocol handler"); + ProtocolHandlers::Row row; + fillRow(row, handler, m_pkgName); + if (getProtocolHandler(handler.target, handler.url, + handler.base_url)) + { + LogDebug("Protocol handler exist. Update its state"); + CUSTOM_HANDLER_DB_UPDATE(updateRow, ProtocolHandlers); + updateRow->Where(And(Equals(m_pkgName), + And(Equals(handler. + target), + And(Equals(handler. + url), + Equals( + handler.base_url))))); + updateRow->Values(row); + updateRow->Execute(); + LogDebug("updated"); + return; + } + CUSTOM_HANDLER_DB_INSERT(insert, ProtocolHandlers); + insert->Values(row); + insert->Execute(); + LogDebug("insterted"); + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to register custom handler"); + } +} + +void CustomHandlerDAO::unregisterContentHandler(const DPL::String& target, + const DPL::String& url) +{ + LogDebug("Removing content handler " << target << " " << url); + Try { + CUSTOM_HANDLER_DB_DELETE(deleteFrom, ContentHandlers); + deleteFrom->Where(And(Equals(m_pkgName), + And(Equals(target), + Equals(url)))); + deleteFrom->Execute(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to remove content handler"); + } +} + +void CustomHandlerDAO::unregisterProtocolHandler(const DPL::String& target, + const DPL::String& url) +{ + LogDebug("Removing protocol handler " << target << " " << url); + Try { + CUSTOM_HANDLER_DB_DELETE(deleteFrom, ProtocolHandlers); + deleteFrom->Where(And(Equals(m_pkgName), + And(Equals(target), + Equals(url)))); + deleteFrom->Execute(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to remove content handler"); + } +} + +void CustomHandlerDAO::unregisterContentHandler(const DPL::String& target, + const DPL::String& url, + const DPL::String& baseURL) +{ + LogDebug("Removing content handler " << target << " " << url); + Try { + CUSTOM_HANDLER_DB_DELETE(deleteFrom, ContentHandlers); + deleteFrom->Where(And(Equals(m_pkgName), + And(Equals(target), + And(Equals(url), + Equals(baseURL))))); + deleteFrom->Execute(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to remove content handler"); + } +} + +void CustomHandlerDAO::unregisterProtocolHandler(const DPL::String& target, + const DPL::String& url, + const DPL::String& baseURL) +{ + LogDebug("Removing protocol handler " << target << " " << url); + Try { + CUSTOM_HANDLER_DB_DELETE(deleteFrom, ProtocolHandlers); + deleteFrom->Where(And(Equals(m_pkgName), + And(Equals(target), + And(Equals(url), + Equals( + baseURL))))); + deleteFrom->Execute(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to remove content handler"); + } +} + +void CustomHandlerDAO::removeWidgetProtocolHandlers() +{ + LogDebug("ente"); + Try { + CUSTOM_HANDLER_DB_DELETE(deleteProtocol, ProtocolHandlers); + deleteProtocol->Where(Equals(m_pkgName)); + deleteProtocol->Execute(); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to remove widget protoc"); + } +} + +void CustomHandlerDAO::removeWidgetContentHandlers() +{ + LogDebug("ente"); + Try { + CUSTOM_HANDLER_DB_DELETE(deleteContent, ContentHandlers); + deleteContent->Where(Equals(m_pkgName)); + deleteContent->Execute(); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAO::Exception::DatabaseError, + "Failed to remove widget entries"); + } +} +} // namespace CustomHandlerDB diff --git a/modules/custom_handler_dao/dao/custom_handler_dao_read_only.cpp b/modules/custom_handler_dao/dao/custom_handler_dao_read_only.cpp new file mode 100644 index 0000000..fd88c12 --- /dev/null +++ b/modules/custom_handler_dao/dao/custom_handler_dao_read_only.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of custom handler dao class. + * + * @file custom_handler_dao_read_only.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of custom handler dao + */ + +#include +#include + +#include + +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::custom_handler; + +namespace CustomHandlerDB { +namespace { +template +CustomHandlerPtr getSingleHandler(std::list row) +{ + CustomHandlerPtr handler; + if (!row.empty()) { + // There should be only one + if (row.size() > 1) { + ThrowMsg(CustomHandlerDAOReadOnly::Exception::DatabaseError, + "More than one handler registered"); + } + + handler.reset(new CustomHandler()); + handler->target = row.front().Get_target(); + handler->base_url = row.front().Get_base_url(); + handler->url = row.front().Get_url(); + handler->title = row.front().Get_title(); + handler->user_decision = + static_cast(row.front().Get_user_allowed()); + } + return handler; +} +} // namespace + +CustomHandlerDAOReadOnly::CustomHandlerDAOReadOnly(const DPL::String& pkgName) + : + m_pkgName(pkgName) +{} + +CustomHandlerDAOReadOnly::~CustomHandlerDAOReadOnly() +{} + +CustomHandlerPtr CustomHandlerDAOReadOnly::getProtocolHandler( + const DPL::String& protocol, + const DPL::String& url) +{ + LogDebug("Getting protocol handler"); + Try { + CUSTOM_HANDLER_DB_SELECT(select, ProtocolHandlers); + + select->Where(And(Equals(m_pkgName), + And(Equals(protocol), + Equals(url)))); + + std::list list = select->GetRowList(); + return getSingleHandler(list); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAOReadOnly::Exception::DatabaseError, + "Failed to get protocol handler"); + } +} + +CustomHandlerPtr CustomHandlerDAOReadOnly::getContentHandler( + const DPL::String& content, + const DPL::String& url) +{ + LogDebug("Getting content handler"); + Try { + CUSTOM_HANDLER_DB_SELECT(select, ContentHandlers); + + select->Where(And(Equals(m_pkgName), + And(Equals(content), + Equals(url)))); + + std::list list = select->GetRowList(); + return getSingleHandler(list); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAOReadOnly::Exception::DatabaseError, + "Failed to get content handler"); + } +} + +CustomHandlerPtr CustomHandlerDAOReadOnly::getActivProtocolHandler( + const DPL::String& protocol) +{ + LogDebug("Getting active protocol handler"); + Try { + CUSTOM_HANDLER_DB_SELECT(select, ProtocolHandlers); + + select->Where(And(Equals(m_pkgName), + Equals(protocol))); + + std::list list = select->GetRowList(); + CustomHandlerPtr handler; + + FOREACH(it, list) { + if (it->Get_user_allowed() & Agreed) { + handler.reset(new CustomHandler()); + handler->base_url = it->Get_base_url(); + handler->target = it->Get_target(); + handler->title = it->Get_title(); + handler->url = it->Get_url(); + handler->user_decision = + static_cast(it->Get_user_allowed()); + } + } + return handler; + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAOReadOnly::Exception::DatabaseError, + "Failed to get protocol handler"); + } +} + +CustomHandlerPtr CustomHandlerDAOReadOnly::getProtocolHandler( + const DPL::String& protocol, + const DPL::String& url, + const DPL::String& baseURL) +{ + LogDebug("Check if protocol is registered"); + Try { + CUSTOM_HANDLER_DB_SELECT(select, ProtocolHandlers); + + select->Where(And(Equals(m_pkgName), + And(Equals(protocol), + And(Equals(url), + Equals(baseURL) + ) + ) + ) + ); + + std::list list = select->GetRowList(); + return getSingleHandler(list); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAOReadOnly::Exception::DatabaseError, + "Failed to get content handler"); + } +} + +CustomHandlerPtr CustomHandlerDAOReadOnly::getActivContentHandler( + const DPL::String& content) +{ + LogDebug("Getting active content handler"); + Try { + CUSTOM_HANDLER_DB_SELECT(select, ContentHandlers); + + select->Where(And(Equals(m_pkgName), + Equals(content))); + + std::list list = select->GetRowList(); + CustomHandlerPtr handler; + + FOREACH(it, list) { + if (it->Get_user_allowed() & Agreed) { + handler.reset(new CustomHandler()); + handler->base_url = it->Get_base_url(); + handler->target = it->Get_target(); + handler->title = it->Get_title(); + handler->url = it->Get_url(); + handler->user_decision = + static_cast(it->Get_user_allowed()); + } + } + return handler; + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAOReadOnly::Exception::DatabaseError, + "Failed to get protocol handler"); + } +} + +CustomHandlerPtr CustomHandlerDAOReadOnly::getContentHandler( + const DPL::String& content, + const DPL::String& url, + const DPL::String& baseURL) +{ + LogDebug("Check if content is registered"); + Try { + CUSTOM_HANDLER_DB_SELECT(select, ContentHandlers); + + select->Where(And(Equals(m_pkgName), + And(Equals(content), + And(Equals(url), + Equals(baseURL))))); + + std::list list = select->GetRowList(); + return getSingleHandler(list); + } Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(CustomHandlerDAOReadOnly::Exception::DatabaseError, + "Failed to get content handler"); + } +} +} // namespace CustomHandlerDB diff --git a/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/CustomHandlerDatabase.h b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/CustomHandlerDatabase.h new file mode 100644 index 0000000..4eabd55 --- /dev/null +++ b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/CustomHandlerDatabase.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _CUSTOM_HANDLER_DATABASE_H_ +#define _CUSTOM_HANDLER_DATABASE_H_ + +#include +#include +#include + +namespace CustomHandlerDB { +namespace Interface { +void attachDatabaseRO(); +void attachDatabaseRW(); +void detachDatabase(); + +extern DPL::Mutex g_dbQueriesMutex; +extern DPL::DB::ThreadDatabaseSupport g_dbInterface; +} // namespace Interface +} // namespace CustomHandlerDB + +#define CUSTOM_HANDLER_DB_INTERNAL(tlsCommand, InternalType) \ + static DPL::ThreadLocalVariable *tlsCommand##Ptr = NULL; \ + { \ + DPL::Mutex::ScopedLock lock( \ + &CustomHandlerDB::Interface::g_dbQueriesMutex); \ + if (!tlsCommand##Ptr) { \ + static DPL::ThreadLocalVariable tmp; \ + tlsCommand##Ptr = &tmp; \ + } \ + } \ + DPL::ThreadLocalVariable &tlsCommand = *tlsCommand##Ptr; \ + if (tlsCommand.IsNull()) \ + { \ + tlsCommand = InternalType(&CustomHandlerDB::Interface::g_dbInterface); \ + } + +#define CUSTOM_HANDLER_DB_SELECT(name, type) \ + CUSTOM_HANDLER_DB_INTERNAL(name, type::Select) + +#define CUSTOM_HANDLER_DB_INSERT(name, type) \ + CUSTOM_HANDLER_DB_INTERNAL(name, type::Insert) + +#define CUSTOM_HANDLER_DB_UPDATE(name, type) \ + CUSTOM_HANDLER_DB_INTERNAL(name, type::Update) + +#define CUSTOM_HANDLER_DB_DELETE(name, type) \ + CUSTOM_HANDLER_DB_INTERNAL(name, type::Delete) + +#endif /* _CUSTOM_HANDLER_DATABASE_H_ */ + diff --git a/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/common_dao_types.h b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/common_dao_types.h new file mode 100644 index 0000000..e5a59f0 --- /dev/null +++ b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/common_dao_types.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file common_dao_types.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of + * common data types for custom handler database. + */ +#ifndef SRC_MODULES_CUSTOM_HANDLERS_DAO_COMMON_DAO_TYPES_H_ +#define SRC_MODULES_CUSTOM_HANDLERS_DAO_COMMON_DAO_TYPES_H_ + +#include +#include +#include + +namespace CustomHandlerDB { +/** + * @brief Custom Handler struct + * + * Describes custom handler for protocol and content. + */ +enum HandlerState { + Agreed = 0x01, //user agreed to use protocol only, + //but want to ask in next occurence + Declined = 0x02, //user declined to use protocol, + //but want to ask in next occurence + //in fact it is used when user wants to cover saved + // agreed + //decision by agreeing to another one without save. + DecisionSaved = 0x04, //user dont want to ask again + AgreedPermanently = Agreed | DecisionSaved, + DeclinedPermanently = Declined | DecisionSaved +}; + +struct CustomHandler +{ + DPL::String target; // protocol/content ("mailto"/"application/x-soup") + DPL::String base_url; // base url of registered page + DPL::String url; // url used for protocol/content handling + DPL::String title; // user friendly handler name + HandlerState user_decision; +}; + +typedef std::shared_ptr CustomHandlerPtr; +typedef std::list CustomHandlersList; +} // namespace CustomHandlerDB + +#endif /* SRC_MODULES_CUSTOM_HANDLERS_DAO_COMMON_DAO_TYPES_H_ */ diff --git a/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/custom_handler_dao_read_only.h b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/custom_handler_dao_read_only.h new file mode 100644 index 0000000..8ad4979 --- /dev/null +++ b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-ro/custom_handler_dao_read_only.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of custom handler dao class. + * + * @file custom_handler_dao_read_only.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of custom handler dao + */ + +#ifndef _CUSTOM_HANDLER_DAO_READ_ONLY_H_ +#define _CUSTOM_HANDLER_DAO_READ_ONLY_H_ + +#include +#include +#include "common_dao_types.h" + +namespace CustomHandlerDB { +class CustomHandlerDAOReadOnly +{ + public: + /** + * CustomHandlerDAOReadOnly Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + }; + + public: + explicit CustomHandlerDAOReadOnly(const DPL::String& pkgName); + virtual ~CustomHandlerDAOReadOnly(); + + /** + * Returns protocol handler + */ + CustomHandlerPtr getProtocolHandler(const DPL::String& protocol, + const DPL::String& url); + CustomHandlerPtr getProtocolHandler(const DPL::String& protocol, + const DPL::String& url, + const DPL::String& baseURL); + + /** + * Returns protocol handler that is agreed or agreed and saved and match + * tizenID + */ + CustomHandlerPtr getActivProtocolHandler(const DPL::String& protocol); + + /** + * Returns content handler + */ + CustomHandlerPtr getContentHandler(const DPL::String& content, + const DPL::String& url); + CustomHandlerPtr getContentHandler(const DPL::String& protocol, + const DPL::String& url, + const DPL::String& baseURL); + + /** + * Returns content handler that is agreed or agreed and saved and match + * tizenID + */ + CustomHandlerPtr getActivContentHandler(const DPL::String& content); + + protected: + DPL::String m_pkgName; +}; +} // namespace CustomHandlerDB + +#endif // _CUSTOM_HANDLER_DAO_READ_ONLY_H_ + diff --git a/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-rw/custom_handler_dao.h b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-rw/custom_handler_dao.h new file mode 100644 index 0000000..9a478cb --- /dev/null +++ b/modules/custom_handler_dao/include/wrt-commons/custom-handler-dao-rw/custom_handler_dao.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of custom handler dao class. + * + * @file custom_handler_dao.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of custom handler dao + */ +#ifndef _CUSTOM_HANDLER_DAO_H_ +#define _CUSTOM_HANDLER_DAO_H_ + +#include + +namespace CustomHandlerDB { +class CustomHandlerDAO : public CustomHandlerDAOReadOnly +{ + public: + explicit CustomHandlerDAO(const DPL::String& pkgName); + virtual ~CustomHandlerDAO(); + + /** + * Registers custom content handler + */ + void registerContentHandler(const CustomHandler& handler); + + /** + * Registers custom protocol handler + */ + void registerProtocolHandler(const CustomHandler& handler); + + /** + * Unregisters custom content handler + */ + void unregisterContentHandler(const DPL::String& target, + const DPL::String& burl); + /** + * Unregisters custom protocol handler + */ + void unregisterProtocolHandler(const DPL::String& target, + const DPL::String& url); + + void unregisterContentHandler(const DPL::String& target, + const DPL::String& url, + const DPL::String& baseURL); + + void unregisterProtocolHandler(const DPL::String& target, + const DPL::String& url, + const DPL::String& baseURL); + + /** + * Removes all widget entries connected to given ID + */ + void removeWidgetProtocolHandlers(); + void removeWidgetContentHandlers(); +}; +} // namespace CustomHandlerDB + +#endif // _CUSTOM_HANDLER_DAO_H_ diff --git a/modules/custom_handler_dao/orm/custom_handler_db b/modules/custom_handler_dao/orm/custom_handler_db new file mode 100644 index 0000000..848c84a --- /dev/null +++ b/modules/custom_handler_dao/orm/custom_handler_db @@ -0,0 +1,34 @@ +SQL( + BEGIN TRANSACTION; +) + +CREATE_TABLE(ProtocolHandlers) + COLUMN_NOT_NULL(app_id, TEXT,) + COLUMN_NOT_NULL(target, TEXT,) + COLUMN_NOT_NULL(base_url, TEXT,) + COLUMN_NOT_NULL(url, TEXT,) + COLUMN_NOT_NULL(title, TEXT,) + COLUMN_NOT_NULL(user_allowed, INT,) + + TABLE_CONSTRAINTS( + PRIMARY KEY (app_id, target, base_url, url) + ) +CREATE_TABLE_END() + +CREATE_TABLE(ContentHandlers) + COLUMN_NOT_NULL(app_id, TEXT,) + COLUMN_NOT_NULL(target, TEXT,) + COLUMN_NOT_NULL(base_url, TEXT,) + COLUMN_NOT_NULL(url, TEXT,) + COLUMN_NOT_NULL(title, TEXT,) + COLUMN_NOT_NULL(user_allowed, INT,) + + TABLE_CONSTRAINTS( + PRIMARY KEY (app_id, target, base_url, url) + ) +CREATE_TABLE_END() + +SQL( + COMMIT; +) + diff --git a/modules/custom_handler_dao/orm/custom_handler_db_definitions b/modules/custom_handler_dao/orm/custom_handler_db_definitions new file mode 100644 index 0000000..1bc2bcd --- /dev/null +++ b/modules/custom_handler_dao/orm/custom_handler_db_definitions @@ -0,0 +1,6 @@ +DATABASE_START(custom_handler) + +#include "custom_handler_db" +#include "version_db" + +DATABASE_END() diff --git a/modules/custom_handler_dao/orm/custom_handler_db_sql_generator.h b/modules/custom_handler_dao/orm/custom_handler_db_sql_generator.h new file mode 100644 index 0000000..9b007de --- /dev/null +++ b/modules/custom_handler_dao/orm/custom_handler_db_sql_generator.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file custom_handler_db_sql_generator.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL + * input file from database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. +#include + +#include "custom_handler_db_definitions" diff --git a/modules/custom_handler_dao/orm/gen_db_md5.sh b/modules/custom_handler_dao/orm/gen_db_md5.sh new file mode 100755 index 0000000..22c2530 --- /dev/null +++ b/modules/custom_handler_dao/orm/gen_db_md5.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +CHECKSUM=`cat ${2} ${3} 2>/dev/null | md5sum 2>/dev/null | cut -d\ -f1 2>/dev/null` +echo "#define DB_CHECKSUM DB_VERSION_${CHECKSUM}" > ${1} +echo "#define DB_CHECKSUM_STR \"DB_VERSION_${CHECKSUM}\"" >> ${1} + diff --git a/modules/custom_handler_dao/orm/orm_generator_custom_handler.h b/modules/custom_handler_dao/orm/orm_generator_custom_handler.h new file mode 100644 index 0000000..35c43a2 --- /dev/null +++ b/modules/custom_handler_dao/orm/orm_generator_custom_handler.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ORM_GENERATOR_CUSTOM_HANDLER_H_ +#define _ORM_GENERATOR_CUSTOM_HANDLER_H_ + +#define ORM_GENERATOR_DATABASE_NAME custom_handler_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif // _ORM_GENERATOR_CUSTOM_HANDLER_H_ diff --git a/modules/custom_handler_dao/orm/version_db b/modules/custom_handler_dao/orm/version_db new file mode 100644 index 0000000..7e20d8d --- /dev/null +++ b/modules/custom_handler_dao/orm/version_db @@ -0,0 +1,5 @@ +SQL( + BEGIN TRANSACTION; + CREATE TABLE DB_CHECKSUM (version INT); + COMMIT; +) diff --git a/modules/db/config.cmake b/modules/db/config.cmake new file mode 100644 index 0000000..96ccbb9 --- /dev/null +++ b/modules/db/config.cmake @@ -0,0 +1,45 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_DB_SOURCES + ${PROJECT_SOURCE_DIR}/modules/db/src/naive_synchronization_object.cpp + ${PROJECT_SOURCE_DIR}/modules/db/src/orm.cpp + ${PROJECT_SOURCE_DIR}/modules/db/src/sql_connection.cpp + ${PROJECT_SOURCE_DIR}/modules/db/src/thread_database_support.cpp + PARENT_SCOPE +) + + +SET(DPL_DB_HEADERS + ${PROJECT_SOURCE_DIR}/modules/db/include/dpl/db/naive_synchronization_object.h + ${PROJECT_SOURCE_DIR}/modules/db/include/dpl/db/orm_generator.h + ${PROJECT_SOURCE_DIR}/modules/db/include/dpl/db/orm.h + ${PROJECT_SOURCE_DIR}/modules/db/include/dpl/db/orm_interface.h + ${PROJECT_SOURCE_DIR}/modules/db/include/dpl/db/orm_macros.h + ${PROJECT_SOURCE_DIR}/modules/db/include/dpl/db/sql_connection.h + ${PROJECT_SOURCE_DIR}/modules/db/include/dpl/db/thread_database_support.h + PARENT_SCOPE +) + +SET(DPL_DB_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/db/include + PARENT_SCOPE +) diff --git a/modules/db/include/dpl/db/naive_synchronization_object.h b/modules/db/include/dpl/db/naive_synchronization_object.h new file mode 100644 index 0000000..2f63a0f --- /dev/null +++ b/modules/db/include/dpl/db/naive_synchronization_object.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file naive_synchronization_object.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL naive + * synchronization object + */ +#ifndef DPL_NAIVE_SYNCHRONIZATION_OBJECT_H +#define DPL_NAIVE_SYNCHRONIZATION_OBJECT_H + +#include + +namespace DPL { +namespace DB { +/** + * Naive synchronization object used to synchronize SQL connection + * to the same database across different threads and processes + */ +class NaiveSynchronizationObject : + public SqlConnection::SynchronizationObject +{ + public: + // [SqlConnection::SynchronizationObject] + virtual void Synchronize(); + virtual void NotifyAll(); +}; +} // namespace DB +} // namespace DPL + +#endif // DPL_NAIVE_SYNCHRONIZATION_OBJECT_H diff --git a/modules/db/include/dpl/db/orm.h b/modules/db/include/dpl/db/orm.h new file mode 100644 index 0000000..652e8e1 --- /dev/null +++ b/modules/db/include/dpl/db/orm.h @@ -0,0 +1,1116 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief DPL-ORM: Object-relational mapping for sqlite database, written on top of DPL. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef DPL_ORM_H +#define DPL_ORM_H + +namespace DPL { +namespace DB { +namespace ORM { + +//TODO move to type utils +#define DPL_CHECK_TYPE_INSTANTIABILITY(type) \ + { \ + type _ignored_; \ + (void)_ignored_; \ + } + +#define DECLARE_COLUMN_TYPE_LIST() typedef DPL::TypeListDecl< +#define SELECTED_COLUMN(table_name, column_name) table_name::column_name, +#define DECLARE_COLUMN_TYPE_LIST_END(name) DPL::TypeListGuard>::Type name; + +typedef size_t ColumnIndex; +typedef size_t ArgumentIndex; +typedef DPL::Optional OptionalString; +typedef DPL::Optional OptionalInteger; +typedef DPL::DB::SqlConnection::DataCommand DataCommand; + +namespace RelationTypes { + extern const char Equal[]; + extern const char LessThan[]; + extern const char And[]; + extern const char Or[]; + extern const char Is[]; + extern const char In[]; + //TODO define more relation types +} + +namespace DataCommandUtils { + //TODO move to DPL::DataCommand? + void BindArgument(DataCommand *command, ArgumentIndex index, int argument); + void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalInteger& argument); + void BindArgument(DataCommand *command, ArgumentIndex index, const DPL::String& argument); + void BindArgument(DataCommand *command, ArgumentIndex index, const OptionalString& argument); +} +class __attribute__ ((visibility("hidden"))) Expression { +public: + virtual ~Expression() {} + virtual std::string GetString() const = 0; + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) = 0; +}; + +typedef std::shared_ptr ExpressionPtr; + +namespace OrderingUtils { + +template inline std::string OrderByInternal() +{ + std::string order = OrderByInternal(); + if(!order.empty()) return CompoundType::Head::GetString() + ", " + order; + else return CompoundType::Head::GetString(); +} + +template<> inline std::string OrderByInternal() +{ + return std::string(); +} + +} + +template +class __attribute__ ((visibility("hidden"))) OrderingExpression { +protected: + static std::string GetSchemaAndName() + { + std::string statement; + statement += ColumnType::GetTableName(); + statement += "."; + statement += ColumnType::GetColumnName(); + statement += " "; + return statement; + } +public: + virtual ~OrderingExpression() {} +}; + +template +class __attribute__ ((visibility("hidden"))) BinaryExpression : public Expression { +protected: + LeftExpression m_leftExpression; + RightExpression m_rightExpression; + bool m_outerParenthesis; +public: + BinaryExpression(const LeftExpression& leftExpression, const RightExpression& rightExpression, bool outerParenthesis = true) : + m_leftExpression(leftExpression), + m_rightExpression(rightExpression), + m_outerParenthesis(outerParenthesis) + {} + + virtual std::string GetString() const + { + return (m_outerParenthesis ? "( " : " " ) + + m_leftExpression.GetString() + " " + Operator + " " + m_rightExpression.GetString() + + (m_outerParenthesis ? " )" : " " ) ; + } + + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) + { + index = m_leftExpression.BindTo(command, index); + return m_rightExpression.BindTo(command, index); + } + + template + struct ValidForTable { + typedef std::pair::Yes , + typename RightExpression::template ValidForTable::Yes > + Yes; + }; +}; + +template +BinaryExpression + And(const LeftExpression& leftExpression, const RightExpression& rightExpression) +{ + return BinaryExpression + (leftExpression, rightExpression); +} + +template +BinaryExpression + Or(const LeftExpression& leftExpression, const RightExpression& rightExpression) +{ + return BinaryExpression + (leftExpression, rightExpression); +} + +template +class __attribute__ ((visibility("hidden"))) ExpressionWithArgument : public Expression { +protected: + ArgumentType argument; + +public: + explicit ExpressionWithArgument(const ArgumentType& _argument) : argument(_argument) {} + + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) + { + DataCommandUtils::BindArgument(command, index, argument); + return index + 1; + } +}; + +template +class __attribute__ ((visibility("hidden"))) Compare : public ExpressionWithArgument { +public: + explicit Compare(typename ColumnData::ColumnType column) : + ExpressionWithArgument(column) + {} + + virtual std::string GetString() const + { + std::string statement; + statement += ColumnData::GetTableName(); + statement += "."; + statement += ColumnData::GetColumnName(); + statement += " "; + statement += Relation; + statement += " ?"; + return statement; + } + + template + struct ValidForTable { + typedef typename TableDefinition::ColumnList::template Contains Yes; + }; +}; +#define ORM_DEFINE_COMPARE_EXPRESSION(name, relationType) \ + template \ + class __attribute__ ((visibility("hidden"))) name : public Compare { \ + public: \ + name(typename ColumnData::ColumnType column) : \ + Compare(column) \ + {} \ + }; + +ORM_DEFINE_COMPARE_EXPRESSION(Equals, Equal) +ORM_DEFINE_COMPARE_EXPRESSION(Is, Is) + +#define ORM_DEFINE_ORDERING_EXPRESSION(name, value) \ + template \ + class __attribute__ ((visibility("hidden"))) name \ + : OrderingExpression { \ + public: \ + static std::string GetString() \ + { \ + std::string statement = OrderingExpression::GetSchemaAndName(); \ + statement += value; \ + return statement; \ + } \ + }; + +ORM_DEFINE_ORDERING_EXPRESSION(OrderingAscending, "ASC") +ORM_DEFINE_ORDERING_EXPRESSION(OrderingDescending, "DESC") + +template +class __attribute__ ((visibility("hidden"))) CompareBinaryColumn { +private: + std::string m_relation; +public: + CompareBinaryColumn(const char* Relation) : + m_relation(Relation) + {} + + virtual ~CompareBinaryColumn() {} + + virtual std::string GetString() const + { + std::string statement; + statement += ColumnData1::GetTableName(); + statement += "."; + statement += ColumnData1::GetColumnName(); + statement += " "; + statement += m_relation; + statement += " "; + statement += ColumnData2::GetTableName(); + statement += "."; + statement += ColumnData2::GetColumnName(); + + return statement; + } +}; + +template +CompareBinaryColumn + Equal() +{ + return CompareBinaryColumn(RelationTypes::Equal); +} + +template +class __attribute__ ((visibility("hidden"))) NumerousArguments : public Expression { +protected: + std::set m_argumentList; +public: + NumerousArguments(const std::set& argumentList) : m_argumentList(argumentList) {} + + virtual std::string GetString() const + { + std::string statement; + statement += ColumnData::GetColumnName(); + statement += " "; + statement += Relation; + statement += " ( "; + + int argumentCount = m_argumentList.size(); + while(argumentCount) + { + statement += "?"; + argumentCount--; + if (argumentCount) + { + statement += ", "; + } + } + + statement += " )"; + + return statement; + } + + virtual ArgumentIndex BindTo(DataCommand *command, ArgumentIndex index) + { + ArgumentIndex argumentIndex = index; + FOREACH(argumentIt, m_argumentList) + { + DataCommandUtils::BindArgument(command, argumentIndex, *argumentIt); + argumentIndex++; + } + return argumentIndex + 1; + } + + template + struct ValidForTable { + typedef typename TableDefinition::ColumnList::template Contains Yes; + }; +}; + +#define ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(name, relationType) \ + template \ + class __attribute__ ((visibility("hidden"))) name : public NumerousArguments { \ + public: \ + name(std::set column) : \ + NumerousArguments(column) \ + {} \ + }; + +ORM_DEFINE_COMPARE_EXPRESSION_NUMEROUS_ARGUMENTS(In, In) + +template +ColumnType GetColumnFromCommand(ColumnIndex columnIndex, DataCommand *command); + +class __attribute__ ((visibility("hidden"))) CustomColumnBase { +public: + CustomColumnBase() {} + virtual ~CustomColumnBase() {} +}; + +template +class __attribute__ ((visibility("hidden"))) CustomColumn : public CustomColumnBase { +private: + ColumnType m_columnData; + +public: + CustomColumn() {} + CustomColumn(ColumnType data) + { + m_columnData = data; + } + + void SetColumnData(ColumnType data) + { + m_columnData = data; + } + + ColumnType GetColumnData() const + { + return m_columnData; + } +}; + +template +class __attribute__ ((visibility("hidden"))) CustomRowUtil { +public: + static void MakeColumnList(std::vector& columnList) + { + typedef CustomColumn Type; + Type* pColumn = new Type(); + columnList.push_back(pColumn); + CustomRowUtil::MakeColumnList(columnList); + } + + static void CopyColumnList(const std::vector& srcList, std::vector& dstList) + { + CopyColumnList(srcList, dstList, 0); + } + + static ColumnIndex GetColumnIndex(const std::string& columnName) + { + return GetColumnIndex(columnName, 0); + } + +private: + static void CopyColumnList(const std::vector& srcList, std::vector& dstList, ColumnIndex index) + { + typedef CustomColumn Type; + Type* pColumn = new Type(((Type*)(srcList.at(index)))->GetColumnData()); + dstList.push_back(pColumn); + CustomRowUtil::CopyColumnList(srcList, dstList, index + 1); + } + + static ColumnIndex GetColumnIndex(const std::string& columnName, ColumnIndex index) + { + if (ColumnList::Head::GetColumnName() == columnName) + return index; + + return CustomRowUtil::GetColumnIndex(columnName, index + 1); + } + +template +friend class CustomRowUtil; +}; + +template<> +class __attribute__ ((visibility("hidden"))) CustomRowUtil { +public: + static void MakeColumnList(std::vector&) {} +private: + static void CopyColumnList(const std::vector&, std::vector&, ColumnIndex) {} + static ColumnIndex GetColumnIndex(const std::string&, ColumnIndex) { return -1; } + +template +friend class CustomRowUtil; +}; + +template +class __attribute__ ((visibility("hidden"))) CustomRow { +private: + std::vector m_columns; + +public: + CustomRow() + { + CustomRowUtil::MakeColumnList(m_columns); + } + + CustomRow(const CustomRow& r) + { + CustomRowUtil::CopyColumnList(r.m_columns, m_columns); + } + + virtual ~CustomRow() + { + while (!m_columns.empty()) + { + CustomColumnBase* pCustomColumn = m_columns.back(); + m_columns.pop_back(); + if (pCustomColumn) + delete pCustomColumn; + } + } + + template + void SetColumnData(ColumnIndex columnIndex, ColumnType data) + { + typedef CustomColumn Type; + Assert(columnIndex < m_columns.size()); + Type* pColumn = dynamic_cast(m_columns.at(columnIndex)); + Assert(pColumn); + pColumn->SetColumnData(data); + } + + template + typename ColumnData::ColumnType GetColumnData() + { + typedef CustomColumn Type; + ColumnIndex index = CustomRowUtil::GetColumnIndex(ColumnData::GetColumnName()); + Assert(index < m_columns.size()); + Type* pColumn = dynamic_cast(m_columns.at(index)); + Assert(pColumn); + return pColumn->GetColumnData(); + } +}; + +template +void SetColumnData(CustomRow& row, ColumnType columnData, ColumnIndex columnIndex) +{ + row.SetColumnData(columnIndex, columnData); +} + +template +class __attribute__ ((visibility("hidden"))) FillCustomRowUtil { +public: + static void FillCustomRow(CustomRow& row, DataCommand* command) + { + FillCustomRow(row, 0, command); + } + +private: + static void FillCustomRow(CustomRow& row, ColumnIndex columnIndex, DataCommand* command) + { + typename ColumnList::Head::ColumnType columnData; + columnData = GetColumnFromCommand(columnIndex, command); + SetColumnData(row, columnData, columnIndex); + FillCustomRowUtil::FillCustomRow(row, columnIndex + 1, command); + } + +template +friend class FillCustomRowUtil; +}; + +template +class __attribute__ ((visibility("hidden"))) FillCustomRowUtil { +private: + static void FillCustomRow(CustomRow&, ColumnIndex, DataCommand *) + { /* do nothing, we're past the last element of column list */ } + +template +friend class FillCustomRowUtil; +}; + +template +class __attribute__ ((visibility("hidden"))) FillRowUtil { +public: + static void FillRow(Row& row, DataCommand *command) + { + FillRow(row, 0, command); + } + +private: + static void FillRow(Row& row, ColumnIndex columnIndex, DataCommand *command) + { + typename ColumnList::Head::ColumnType rowField; + rowField = GetColumnFromCommand(columnIndex, command); + ColumnList::Head::SetRowField(row, rowField); + FillRowUtil::FillRow(row, columnIndex + 1, command); + } + +template +friend class FillRowUtil; +}; + +template +class __attribute__ ((visibility("hidden"))) FillRowUtil { +private: + static void FillRow(Row&, ColumnIndex, DataCommand *) + { /* do nothing, we're past the last element of column list */ } + +template +friend class FillRowUtil; +}; + +template +class __attribute__ ((visibility("hidden"))) JoinUtil { +public: + static std::string GetColumnNames() + { + std::string result; + result = ColumnList::Head::GetTableName(); + result += "."; + result += ColumnList::Head::GetColumnName(); + if (ColumnList::Tail::Size > 0) + result += ", "; + + return result += JoinUtil::GetColumnNames(); + } + + static std::string GetJoinTableName(const std::string& tableName) + { + std::string joinTableName = ColumnList::Head::GetTableName(); + if (tableName.find(joinTableName) == std::string::npos) + return joinTableName; + + return JoinUtil::GetJoinTableName(tableName); + } +}; + +template<> +class __attribute__ ((visibility("hidden"))) JoinUtil { +public: + static std::string GetColumnNames() { return ""; } + static std::string GetJoinTableName(std::string) { return ""; } +}; + +class Exception { +public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, SelectReuseWithDifferentQuerySignature) + DECLARE_EXCEPTION_TYPE(Base, RowFieldNotInitialized) + DECLARE_EXCEPTION_TYPE(Base, EmptyUpdateStatement) +}; + +template +class __attribute__ ((visibility("hidden"))) Query +{ +protected: + explicit Query(IOrmInterface* interface) : + m_interface(interface), + m_command(NULL) + { + } + + virtual ~Query() + { + if (m_command == NULL) + return; + + TableDefinition::FreeTableDataCommand(m_command, m_interface); + } + + IOrmInterface* m_interface; + DataCommand *m_command; + std::string m_commandString; + ArgumentIndex m_bindArgumentIndex; +}; + +template +class __attribute__ ((visibility("hidden"))) QueryWithWhereClause : public Query +{ +protected: + ExpressionPtr m_whereExpression; + + void Prepare() + { + if ( !!m_whereExpression ) + { + this->m_commandString += " WHERE "; + this->m_commandString += m_whereExpression->GetString(); + } + } + + void Bind() + { + if ( !!m_whereExpression ) + { + this->m_bindArgumentIndex = m_whereExpression->BindTo( + this->m_command, this->m_bindArgumentIndex); + } + } + +public: + explicit QueryWithWhereClause(IOrmInterface* interface) : + Query(interface) + { + } + + template + void Where(const Expression& expression) + { + DPL_CHECK_TYPE_INSTANTIABILITY(typename Expression::template ValidForTable::Yes); + if ( !!m_whereExpression && ( typeid(Expression) != typeid(*m_whereExpression) ) ) + { + std::ostringstream str; + str << "Current ORM implementation doesn't allow to reuse Select" + " instance with different query signature (particularly " + "WHERE on different column).\n"; + str << "Query: "; + str << this->m_commandString; + ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature, + str.str()); + } + //TODO maybe don't make a copy here but just generate the string part of the query. + m_whereExpression.reset(new Expression(expression)); + } + +}; + +template +class __attribute__ ((visibility("hidden"))) Delete : public QueryWithWhereClause +{ +protected: + void Prepare() + { + if ( !this->m_command) + { + this->m_commandString = "DELETE FROM "; + this->m_commandString += TableDefinition::GetName(); + + QueryWithWhereClause::Prepare(); + + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query::m_interface); + LogPedantic("Prepared SQL command " << this->m_commandString); + } + } + + void Bind() + { + this->m_bindArgumentIndex = 1; + QueryWithWhereClause::Bind(); + } + +public: + explicit Delete(IOrmInterface *interface = NULL) : + QueryWithWhereClause(interface) + { + } + + void Execute() + { + Prepare(); + Bind(); + this->m_command->Step(); + this->m_command->Reset(); + } +}; + +namespace { +class BindVisitor { +private: + DataCommand *m_command; +public: + ArgumentIndex m_bindArgumentIndex; + + BindVisitor(DataCommand *command) : + m_command(command), + m_bindArgumentIndex(1) + {} + + template + void Visit(const char*, const ColumnType& value, bool isSet) + { + if ( isSet ) + { + DataCommandUtils::BindArgument(m_command, m_bindArgumentIndex, value); + m_bindArgumentIndex++; + } + } +}; +} //anonymous namespace +template +class __attribute__ ((visibility("hidden"))) Insert : public Query +{ +public: + typedef typename TableDefinition::Row Row; + typedef DPL::DB::SqlConnection::RowID RowID; + +protected: + DPL::Optional m_orClause; + Row m_row; + + class PrepareVisitor { + public: + std::string m_columnNames; + std::string m_values; + + template + void Visit(const char* name, const ColumnType&, bool isSet) + { + if ( isSet ) + { + if ( !m_columnNames.empty() ) + { + m_columnNames += ", "; + m_values += ", "; + } + m_columnNames += name; + m_values += "?"; + } + } + }; + + void Prepare() + { + if ( !this->m_command ) + { + this->m_commandString = "INSERT "; + if ( !!m_orClause ) + { + this->m_commandString += " OR " + *m_orClause + " "; + } + this->m_commandString += "INTO "; + this->m_commandString += TableDefinition::GetName(); + + PrepareVisitor visitor; + m_row.VisitColumns(visitor); + + this->m_commandString += " ( " + visitor.m_columnNames + " ) "; + this->m_commandString += "VALUES ( " + visitor.m_values + " )"; + + LogPedantic("Prepared SQL command " << this->m_commandString); + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query::m_interface); + } + } + + void Bind() + { + BindVisitor visitor(this->m_command); + m_row.VisitColumns(visitor); + } + +public: + explicit Insert( + IOrmInterface* interface = NULL, + const DPL::Optional& orClause = DPL::Optional::Null) : + Query(interface), + m_orClause(orClause) + { + } + + void Values(const Row& row) + { + if ( this->m_command ) + { + if ( !row.IsSignatureMatching(m_row) ) + { + ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature, + "Current ORM implementation doesn't allow to reuse Insert instance " + "with different query signature."); + } + } + m_row = row; + } + + RowID Execute() + { + Prepare(); + Bind(); + this->m_command->Step(); + + RowID result = TableDefinition::GetLastInsertRowID( + Query::m_interface); + + this->m_command->Reset(); + return result; + } +}; + +template +class __attribute__ ((visibility("hidden"))) Select : public QueryWithWhereClause +{ +public: + typedef typename TableDefinition::ColumnList ColumnList; + typedef typename TableDefinition::Row Row; + + typedef std::list RowList; +protected: + DPL::Optional m_orderBy; + std::string m_JoinClause; + bool m_distinctResults; + + void Prepare(const char* selectColumnName) + { + if ( !this->m_command ) + { + this->m_commandString = "SELECT "; + if (m_distinctResults) + this->m_commandString += "DISTINCT "; + this->m_commandString += selectColumnName; + this->m_commandString += " FROM "; + this->m_commandString += TableDefinition::GetName(); + + this->m_commandString += m_JoinClause; + + QueryWithWhereClause::Prepare(); + + if ( !m_orderBy.IsNull() ) + { + this->m_commandString += " ORDER BY " + *m_orderBy; + } + + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query::m_interface); + + LogPedantic("Prepared SQL command " << this->m_commandString); + } + } + + void Bind() + { + this->m_bindArgumentIndex = 1; + QueryWithWhereClause::Bind(); + } + + template + ColumnType GetColumn(ColumnIndex columnIndex) + { + return GetColumnFromCommand(columnIndex, this->m_command); + } + + Row GetRow() + { + Row row; + FillRowUtil::FillRow(row, this->m_command); + return row; + } + + template + CustomRow GetCustomRow() + { + CustomRow row; + FillCustomRowUtil::FillCustomRow(row, this->m_command); + return row; + } + +public: + + explicit Select(IOrmInterface *interface = NULL) : + QueryWithWhereClause(interface), + m_distinctResults(false) + { + } + + void Distinct() + { + m_distinctResults = true; + } + + template + void OrderBy(const CompoundType&) + { + m_orderBy = OrderingUtils::OrderByInternal(); + } + + void OrderBy(const std::string & orderBy) //backward compatibility + { + m_orderBy = orderBy; + } + + void OrderBy(const char * orderBy) //backward compatibility + { + m_orderBy = std::string(orderBy); + } + + template + void Join(const Expression& expression) { + std::string usedTableNames = TableDefinition::GetName(); + if (!m_JoinClause.empty()) + usedTableNames += m_JoinClause; + + this->m_JoinClause += " JOIN "; + this->m_JoinClause += JoinUtil::GetJoinTableName(usedTableNames); + this->m_JoinClause += " ON "; + this->m_JoinClause += expression.GetString(); + } + + template + typename ColumnData::ColumnType GetSingleValue() + { + Prepare(ColumnData::GetColumnName()); + Bind(); + this->m_command->Step(); + + typename ColumnData::ColumnType result = + GetColumn(0); + + this->m_command->Reset(); + return result; + } + + //TODO return range - pair of custom iterators + template + std::list GetValueList() + { + Prepare(ColumnData::GetColumnName()); + Bind(); + + std::list resultList; + + while (this->m_command->Step()) + resultList.push_back(GetColumn(0)); + + this->m_command->Reset(); + return resultList; + } + + Row GetSingleRow() + { + Prepare("*"); + Bind(); + this->m_command->Step(); + + Row result = GetRow(); + + this->m_command->Reset(); + return result; + } + + //TODO return range - pair of custom iterators + RowList GetRowList() + { + Prepare("*"); + Bind(); + + RowList resultList; + + while (this->m_command->Step()) + resultList.push_back(GetRow()); + + this->m_command->Reset(); + return resultList; + } + + template + CustomRow GetCustomSingleRow() + { + Prepare(JoinUtil::GetColumnNames().c_str()); + Bind(); + this->m_command->Step(); + + CustomRow result = GetCustomRow(); + + this->m_command->Reset(); + return result; + } + + template + std::list GetCustomRowList() + { + Prepare(JoinUtil::GetColumnNames().c_str()); + Bind(); + + std::list resultList; + + while (this->m_command->Step()) + resultList.push_back(GetCustomRow()); + + this->m_command->Reset(); + return resultList; + } +}; + +template +class __attribute__ ((visibility("hidden"))) Update : public QueryWithWhereClause { +public: + typedef typename TableDefinition::Row Row; + +protected: + DPL::Optional m_orClause; + Row m_row; + + class PrepareVisitor { + public: + std::string m_setExpressions; + + template + void Visit(const char* name, const ColumnType&, bool isSet) + { + if ( isSet ) + { + if ( !m_setExpressions.empty() ) + { + m_setExpressions += ", "; + } + m_setExpressions += name; + m_setExpressions += " = "; + m_setExpressions += "?"; + } + } + }; + + void Prepare() + { + if ( !this->m_command ) + { + this->m_commandString = "UPDATE "; + if ( !!m_orClause ) + { + this->m_commandString += " OR " + *m_orClause + " "; + } + this->m_commandString += TableDefinition::GetName(); + this->m_commandString += " SET "; + + // got through row columns and values + PrepareVisitor visitor; + m_row.VisitColumns(visitor); + + if(visitor.m_setExpressions.empty()) + { + ThrowMsg(Exception::EmptyUpdateStatement, "No SET expressions in update statement"); + } + + this->m_commandString += visitor.m_setExpressions; + + // where + QueryWithWhereClause::Prepare(); + + this->m_command = TableDefinition::AllocTableDataCommand( + this->m_commandString.c_str(), + Query::m_interface); + LogPedantic("Prepared SQL command " << this->m_commandString); + } + } + + void Bind() + { + BindVisitor visitor(this->m_command); + m_row.VisitColumns(visitor); + + this->m_bindArgumentIndex = visitor.m_bindArgumentIndex; + QueryWithWhereClause::Bind(); + } + + +public: + explicit Update(IOrmInterface *interface = NULL, + const DPL::Optional& orClause = DPL::Optional::Null) : + QueryWithWhereClause(interface), + m_orClause(orClause) + { + } + + void Values(const Row& row) + { + if ( this->m_command ) + { + if ( !row.IsSignatureMatching(m_row) ) + { + ThrowMsg(Exception::SelectReuseWithDifferentQuerySignature, + "Current ORM implementation doesn't allow to reuse Update instance " + "with different query signature."); + } + } + m_row = row; + } + + void Execute() + { + Prepare(); + Bind(); + this->m_command->Step(); + this->m_command->Reset(); + } +}; + +} //namespace ORM +} //namespace DB +} //namespace DPL + +#endif // DPL_ORM_H diff --git a/modules/db/include/dpl/db/orm_generator.h b/modules/db/include/dpl/db/orm_generator.h new file mode 100644 index 0000000..8bd9fdb --- /dev/null +++ b/modules/db/include/dpl/db/orm_generator.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm_generator.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the DPL-ORM table definitions from database definitions. + */ + +#ifndef ORM_GENERATOR_DATABASE_NAME +#error You need to define database name in ORM_GENERATOR_DATABASE_NAME define before you include orm_generator.h file +#endif + +#include + +#define ORM_GENERATOR_DATABASE_NAME_LOCAL + +#ifdef DPL_ORM_GENERATOR_H +#warning orm_generator.h is included multiply times. Make sure it has different ORM_GENERATOR_DATABASE_NAME set. +#endif + +#define DPL_ORM_GENERATOR_H + + +#include +#include +#include +#include +#include +#include +#include + +/* + +This is true only when exactly one db is available. + +#if (defined DECLARE_COLUMN) || (defined INT) || (defined TINYINT) || \ + (defined INTEGER) || (defined BIGINT) || defined(VARCHAR) || defined(TEXT) || \ + (defined SQL) || (defined TABLE_CONSTRAINTS) || (defined OPTIONAL) || \ + (defined DATABASE_START) || (defined DATABASE_END) || (defined CREATE_TABLE) || \ + (defined COLUMN) || (defined COLUMN_NOT_NULL) || (defined CREATE_TABLE_END) + +#error This file temporarily defines many macros with generic names. To avoid name clash please include \ + this file as early as possible. If this is not possible please report this problem to DPL developers. + +#endif +*/ + +namespace DPL { +namespace DB { +namespace ORM { + +// Global macros + +#define STRINGIFY(s) _str(s) +#define _str(s) #s +#define DECLARE_COLUMN(FIELD, TYPE) \ + struct FIELD { \ + typedef TYPE ColumnType; \ + static const char* GetTableName() { return GetName(); } \ + static const char* GetColumnName() { return STRINGIFY(FIELD); } \ + static void SetRowField(Row& row, const TYPE& _value) { row.Set_##FIELD(_value);} \ + }; + +#define INT int +#define TINYINT int +#define INTEGER int //TODO: should be long long? +#define BIGINT int //TODO: should be long long? +#define VARCHAR(x) DPL::String +#define TEXT DPL::String + +#define SQL(...) +#define TABLE_CONSTRAINTS(...) +#define OPTIONAL(type) DPL::Optional< type > +#define DATABASE_START(db_name) \ + namespace db_name \ + { \ + class ScopedTransaction \ + { \ + bool m_commited; \ + IOrmInterface *m_interface; \ + \ + public: \ + ScopedTransaction(IOrmInterface *interface) : \ + m_commited(false), \ + m_interface(interface) \ + { \ + Assert(interface != NULL); \ + m_interface->TransactionBegin(); \ + } \ + \ + ~ScopedTransaction() \ + { \ + if (!m_commited) \ + m_interface->TransactionRollback(); \ + } \ + \ + void Commit() \ + { \ + m_interface->TransactionCommit(); \ + m_commited = true; \ + } \ + }; + +#define DATABASE_END() } + +// RowBase ostream operator<< declaration + +#define CREATE_TABLE(name) \ + namespace name { \ + class RowBase; \ + inline std::ostream& operator<<(std::ostream& ostr, const RowBase& row); \ + } +#define COLUMN_NOT_NULL(name, type, ...) +#define COLUMN(name, type, ...) +#define CREATE_TABLE_END() + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +#undef DATABASE_START +#define DATABASE_START(db_name) namespace db_name { + +// RowBase class + +#define CREATE_TABLE(name) namespace name { class RowBase { \ + public: friend std::ostream& operator<<(std::ostream&, const RowBase&); +#define COLUMN_NOT_NULL(name, type, ...) \ + protected: type name; bool m_##name##_set; \ + public: void Set_##name(const type& _value) { \ + m_##name##_set = true; \ + this->name = _value; \ + } \ + public: type Get_##name() const { \ + if ( !m_##name##_set ) { \ + ThrowMsg(Exception::RowFieldNotInitialized, \ + "You tried to read a row field that hasn't been set yet."); \ + } \ + return name; \ + } + +#define COLUMN(name, type, ...) \ + protected: OPTIONAL(type) name; bool m_##name##_set; \ + public: void Set_##name(const OPTIONAL(type)& _value) { \ + m_##name##_set = true; \ + this->name = _value; \ + } \ + public: OPTIONAL(type) Get_##name() const { \ + if ( !m_##name##_set ) { \ + ThrowMsg(Exception::RowFieldNotInitialized, \ + "You tried to read a row field that hasn't been set yet."); \ + } \ + return name; \ + } +#define CREATE_TABLE_END() }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase ostream operator<< + +#define CREATE_TABLE(name) std::ostream& name::operator<<(std::ostream& ostr, const RowBase& row) { using ::operator<< ; ostr << STRINGIFY(name) << " ("; +#define COLUMN_NOT_NULL(name, type, ...) ostr << " '" << row.name << "'" ; +#define COLUMN(name, type, ...) ostr << " '" << row.name << "'" ; +#define CREATE_TABLE_END() ostr << " )" ; return ostr; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase2 class (== RowBase + operator==) + +#define CREATE_TABLE(name) namespace name { class RowBase2 : public RowBase { \ + public: bool operator==(const RowBase2& row) const { return true +#define COLUMN_NOT_NULL(name, type, ...) && (this->name == row.name) +#define COLUMN(name, type, ...) && (this->name == row.name) +#define CREATE_TABLE_END() ; } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase3 class (== RowBase2 + operator<) + +#define CREATE_TABLE(name) namespace name { class RowBase3 : public RowBase2 { \ + public: bool operator<(const RowBase3& row) const { +#define COLUMN_NOT_NULL(name, type, ...) if (this->name < row.name) { return true; } if (this->name > row.name) { return false; } +#define COLUMN(name, type, ...) if (this->name < row.name) { return true; } if (this->name > row.name) { return false; } +#define CREATE_TABLE_END() return false; } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase4 class (== RowBase3 + IsSignatureMatching ) + +#define CREATE_TABLE(name) namespace name { class RowBase4 : public RowBase3 { \ + public: bool IsSignatureMatching(const RowBase4& row) const { return true +#define COLUMN_NOT_NULL(name, type, ...) && (this->m_##name##_set == row.m_##name##_set) +#define COLUMN(name, type, ...) && (this->m_##name##_set == row.m_##name##_set) +#define CREATE_TABLE_END() ; } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// RowBase5 class (== RowBase4 + default constructor) + +#define CREATE_TABLE(name) namespace name { class RowBase5 : public RowBase4 { \ + public: RowBase5() { +#define COLUMN_NOT_NULL(name, type, ...) m_##name##_set = false; +#define COLUMN(name, type, ...) m_##name##_set = false; +#define CREATE_TABLE_END() } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// Row class (== RowBase5 + ForEachColumn ) + +#define CREATE_TABLE(name) namespace name { class Row : public RowBase5 { \ + public: template \ + void VisitColumns(Visitor& visitor) const { +#define COLUMN_NOT_NULL(name, type, ...) visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set); +#define COLUMN(name, type, ...) visitor.Visit(STRINGIFY(name), this->name, this->m_##name##_set); +#define CREATE_TABLE_END() } }; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// Field structure declarations + +#define CREATE_TABLE(name) namespace name { \ + static const char* GetName() { return STRINGIFY(name); } +#define COLUMN_NOT_NULL(name, type, ...) DECLARE_COLUMN(name, type) +#define COLUMN(name, type, ...) DECLARE_COLUMN(name, OPTIONAL(type)) +#define CREATE_TABLE_END() } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// ColumnList typedef + +#define CREATE_TABLE(name) namespace name { typedef DPL::TypeListDecl< +#define COLUMN_NOT_NULL(name, type, ...) name, +#define COLUMN(name, type, ...) name, +#define CREATE_TABLE_END() DPL::TypeListGuard>::Type ColumnList; } + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// TableDefinition struct + +#define CREATE_TABLE(table_name) \ + namespace table_name { \ + struct TableDefinition { \ + typedef table_name::ColumnList ColumnList; \ + typedef table_name::Row Row; \ + static const char* GetName() { return STRINGIFY(table_name); } \ + static DPL::DB::SqlConnection::DataCommand *AllocTableDataCommand( \ + const std::string &statement, \ + IOrmInterface *interface) \ + { \ + Assert(interface != NULL); \ + return interface->AllocDataCommand(statement); \ + } \ + static void FreeTableDataCommand( \ + DPL::DB::SqlConnection::DataCommand *command, \ + IOrmInterface *interface) \ + { \ + Assert(interface != NULL); \ + interface->FreeDataCommand(command); \ + } \ + static DPL::DB::SqlConnection::RowID GetLastInsertRowID( \ + IOrmInterface *interface) \ + { \ + Assert(interface != NULL); \ + return interface->GetLastInsertRowID(); \ + } \ + }; \ + } + +#define COLUMN_NOT_NULL(name, type, ...) +#define COLUMN(name, type, ...) +#define CREATE_TABLE_END() + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + +// Query typedefs + +#define CREATE_TABLE(name) \ + namespace name { \ + typedef Select Select; \ + typedef Insert Insert; \ + typedef Delete Delete; \ + typedef Update Update; \ + } +#define COLUMN_NOT_NULL(name, type, ...) +#define COLUMN(name, type, ...) +#define CREATE_TABLE_END() + +#include ORM_GENERATOR_DATABASE_NAME_LOCAL + +#undef CREATE_TABLE +#undef COLUMN_NOT_NULL +#undef COLUMN +#undef CREATE_TABLE_END + + +// Global undefs +#undef INT +#undef TINYINT +#undef INTEGER +#undef BIGINT +#undef VARCHAR +#undef TEXT + +#undef SQL +#undef TABLE_CONSTRAINTS +#undef OPTIONAL +#undef DATABASE_START +#undef DATABASE_END + +} //namespace ORM +} //namespace DB +} //namespace DPL + +#undef ORM_GENERATOR_DATABASE_NAME +#undef ORM_GENERATOR_DATABASE_NAME_LOCAL diff --git a/modules/db/include/dpl/db/orm_interface.h b/modules/db/include/dpl/db/orm_interface.h new file mode 100644 index 0000000..62ec073 --- /dev/null +++ b/modules/db/include/dpl/db/orm_interface.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm_interface.h + * @author Lukasz Marek (l.marek@samsung.com) + * @version 1.0 + */ + +#include +#include + +#ifndef DPL_ORM_INTERFACE_H +#define DPL_ORM_INTERFACE_H + +namespace DPL { +namespace DB { +namespace ORM { +class IOrmInterface +{ + public: + virtual ~IOrmInterface() {} + virtual DPL::DB::SqlConnection::DataCommand *AllocDataCommand( + const std::string &statement) = 0; + virtual void FreeDataCommand(DPL::DB::SqlConnection::DataCommand *command) + = 0; + virtual void TransactionBegin() = 0; + virtual void TransactionCommit() = 0; + virtual void TransactionRollback() = 0; + virtual DPL::DB::SqlConnection::RowID GetLastInsertRowID() = 0; +}; +} +} +} + +#endif diff --git a/modules/db/include/dpl/db/orm_macros.h b/modules/db/include/dpl/db/orm_macros.h new file mode 100644 index 0000000..a038523 --- /dev/null +++ b/modules/db/include/dpl/db/orm_macros.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm_macros.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL input file from + * database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. + +#define CREATE_TABLE(name) CREATE TABLE name( +#define COLUMN(name, type, ...) name type __VA_ARGS__, +#define COLUMN_NOT_NULL(name, type, ...) name type __VA_ARGS__ not null, +#define SQL(...) __VA_ARGS__ +#define TABLE_CONSTRAINTS(...) __VA_ARGS__, +#define CREATE_TABLE_END() CHECK(1) ); +#define DATABASE_START(db_name) +#define DATABASE_END() + diff --git a/modules/db/include/dpl/db/sql_connection.h b/modules/db/include/dpl/db/sql_connection.h new file mode 100644 index 0000000..d1eab36 --- /dev/null +++ b/modules/db/include/dpl/db/sql_connection.h @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file sql_connection.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL connection + */ +#ifndef DPL_SQL_CONNECTION_H +#define DPL_SQL_CONNECTION_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DB { +/** + * SQL connection class + */ +class SqlConnection +{ + public: + /** + * SQL Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, SyntaxError) + DECLARE_EXCEPTION_TYPE(Base, ConnectionBroken) + DECLARE_EXCEPTION_TYPE(Base, InternalError) + DECLARE_EXCEPTION_TYPE(Base, InvalidColumn) + }; + + typedef int ColumnIndex; + typedef int ArgumentIndex; + + /* + * SQL processed data command + */ + class DataCommand : + private Noncopyable + { + private: + SqlConnection *m_masterConnection; + sqlite3_stmt *m_stmt; + + void CheckBindResult(int result); + void CheckColumnIndex(SqlConnection::ColumnIndex column); + + DataCommand(SqlConnection *connection, const char *buffer); + + friend class SqlConnection; + + public: + virtual ~DataCommand(); + + /** + * Bind null to the prepared statement argument + * + * @param position Index of argument to bind value to + */ + void BindNull(ArgumentIndex position); + + /** + * Bind int to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInteger(ArgumentIndex position, int value); + + /** + * Bind int8_t to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt8(ArgumentIndex position, int8_t value); + + /** + * Bind int16 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt16(ArgumentIndex position, int16_t value); + + /** + * Bind int32 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt32(ArgumentIndex position, int32_t value); + + /** + * Bind int64 to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt64(ArgumentIndex position, int64_t value); + + /** + * Bind float to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindFloat(ArgumentIndex position, float value); + + /** + * Bind double to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindDouble(ArgumentIndex position, double value); + + /** + * Bind string to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const char *value); + + /** + * Bind string to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const String& value); + + /** + * Bind optional int to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInteger(ArgumentIndex position, const Optional &value); + + /** + * Bind optional int8 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt8(ArgumentIndex position, const Optional &value); + + /** + * Bind optional int16 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt16(ArgumentIndex position, const Optional &value); + + /** + * Bind optional int32 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt32(ArgumentIndex position, const Optional &value); + + /** + * Bind optional int64 to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindInt64(ArgumentIndex position, const Optional &value); + + /** + * Bind optional float to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindFloat(ArgumentIndex position, const Optional &value); + + /** + * Bind optional double to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindDouble(ArgumentIndex position, const Optional &value); + + /** + * Bind optional string to the prepared statement argument. + * If optional is not set null will be bound + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const Optional &value); + + /** + * Execute the prepared statement and/or move + * to the next row of the result + * + * @return True when there was a row returned + */ + bool Step(); + + /** + * Reset prepared statement's arguments + * All parameters will become null + */ + void Reset(); + + /** + * Checks whether column value is null + * + * @throw Exception::InvalidColumn + */ + bool IsColumnNull(ColumnIndex column); + + /** + * Get integer value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int GetColumnInteger(ColumnIndex column); + + /** + * Get int8 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int8_t GetColumnInt8(ColumnIndex column); + + /** + * Get int16 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int16_t GetColumnInt16(ColumnIndex column); + /** + * Get int32 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int32_t GetColumnInt32(ColumnIndex column); + + /** + * Get int64 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + int64_t GetColumnInt64(ColumnIndex column); + + /** + * Get float value from column in current row. + * + * @throw Exception::InvalidColumn + */ + float GetColumnFloat(ColumnIndex column); + + /** + * Get double value from column in current row. + * + * @throw Exception::InvalidColumn + */ + double GetColumnDouble(ColumnIndex column); + + /** + * Get string value from column in current row. + * + * @throw Exception::InvalidColumn + */ + std::string GetColumnString(ColumnIndex column); + + /** + * Get optional integer value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalInteger(ColumnIndex column); + + /** + * Get optional int8 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalInt8(ColumnIndex column); + + /** + * Get optional int16value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalInt16(ColumnIndex column); + + /** + * Get optional int32 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalInt32(ColumnIndex column); + + /** + * Get optional int64 value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalInt64(ColumnIndex column); + + /** + * Get optional float value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalFloat(ColumnIndex column); + + /** + * Get optional double value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalDouble(ColumnIndex column); + + /** + * Get optional string value from column in current row. + * + * @throw Exception::InvalidColumn + */ + Optional GetColumnOptionalString(ColumnIndex column); + }; + + // Move on copy semantics + typedef std::auto_ptr DataCommandAutoPtr; + + // Open flags + class Flag + { + public: + enum Type + { + None = 1 << 0, + UseLucene = 1 << 1 + }; + + enum Option + { + RO = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY, + /** + * *TODO: please remove CREATE option from RW flag when all places + * that need that switched do CRW + */ + RW = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE, + CRW = RW | SQLITE_OPEN_CREATE + }; + }; + + // RowID + typedef sqlite3_int64 RowID; + + /** + * Synchronization object used to synchronize SQL connection + * to the same database across different threads and processes + */ + class SynchronizationObject + { + public: + virtual ~SynchronizationObject() {} + + /** + * Synchronizes SQL connection for multiple clients. + */ + virtual void Synchronize() = 0; + + /** + * Notify all waiting clients that the connection is no longer locked. + */ + virtual void NotifyAll() = 0; + }; + + protected: + sqlite3 *m_connection; + + // Options + bool m_usingLucene; + + // Stored data procedures + int m_dataCommandsCount; + + // Synchronization object + std::unique_ptr m_synchronizationObject; + + virtual void Connect(const std::string &address, + Flag::Type = Flag::None, Flag::Option = Flag::RO); + virtual void Disconnect(); + + void TurnOnForeignKeys(); + + static SynchronizationObject *AllocDefaultSynchronizationObject(); + + public: + /** + * Open SQL connection + * + * Synchronization is archieved by using provided asynchronization object. + * If synchronizationObject is set to NULL, so synchronization is performed. + * Ownership of the synchronization object is transfered to sql connection + * object. + * + * @param address Database file name + * @param flags Open flags + * @param synchronizationObject A synchronization object to use. + */ + explicit SqlConnection(const std::string &address = std::string(), + Flag::Type flags = Flag::None, + Flag::Option options = Flag::RO, + SynchronizationObject *synchronizationObject = + AllocDefaultSynchronizationObject()); + + /** + * Destructor + */ + virtual ~SqlConnection(); + + /** + * Execute SQL command without result + * + * @param format + * @param ... + */ + void ExecCommand(const char *format, ...) DPL_DEPRECATED_WITH_MESSAGE( + "To prevent sql injection do not use this \ + method for direct sql execution"); + + /** + * Execute BEGIN; command to start new transaction + * + */ + void BeginTransaction(); + + /** + * Execute ROLLBACK; command to discard changes made + * + */ + void RollbackTransaction(); + + /** + * Execute COMMIT; command to commit changes in database + * + */ + void CommitTransaction(); + + /** + * Prepare stored procedure + * + * @param format SQL statement + * @return Data command representing stored procedure + */ + DataCommandAutoPtr PrepareDataCommand(const char *format, ...); + + /** + * Check whether given table exists + * + * @param tableName Name of the table to check + * @return True if given table name exists + */ + bool CheckTableExist(const char *tableName); + + /** + * Get last insert operation new row id + * + * @return Row ID + */ + RowID GetLastInsertRowID() const; +}; +} // namespace DB +} // namespace DPL + +#endif // DPL_SQL_CONNECTION_H diff --git a/modules/db/include/dpl/db/thread_database_support.h b/modules/db/include/dpl/db/thread_database_support.h new file mode 100644 index 0000000..04ec923 --- /dev/null +++ b/modules/db/include/dpl/db/thread_database_support.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread_database_support.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk) + * @version 1.0 + * @brief This file contains the declaration of thread database support + */ + +#ifndef DPL_THREAD_DATABASE_SUPPORT_H +#define DPL_THREAD_DATABASE_SUPPORT_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DB { +/** + * Thread database support + * + * Associate database connection with thread lifecycle + * + */ + +class ThreadDatabaseSupport : + public DPL::DB::ORM::IOrmInterface +{ + private: + typedef DPL::DB::SqlConnection *SqlConnectionPtr; + typedef DPL::ThreadLocalVariable TLVSqlConnectionPtr; + typedef DPL::ThreadLocalVariable TLVSizeT; + typedef DPL::ThreadLocalVariable TLVBool; + + TLVSqlConnectionPtr m_connection; + TLVBool m_linger; + TLVSizeT m_refCounter; + TLVSizeT m_transactionDepth; + TLVSizeT m_attachCount; + TLVBool m_transactionCancel; + std::string m_address; + DPL::DB::SqlConnection::Flag::Type m_flags; + + TLVSqlConnectionPtr &Connection() + { + return m_connection; + } + + TLVBool &Linger() + { + return m_linger; + } + + TLVSizeT &RefCounter() + { + return m_refCounter; + } + + TLVSizeT &TransactionDepth() + { + return m_transactionDepth; + } + + TLVSizeT &AttachCount() + { + return m_attachCount; + } + + TLVBool &TransactionCancel() + { + return m_transactionCancel; + } + + void CheckedConnectionDelete() + { + Assert(!Connection().IsNull()); + Assert(*Linger() == true); + + if (*RefCounter() > 0 || *AttachCount() > 0) { + return; + } + + // Destroy connection + LogDebug("Destroying thread database connection: " << m_address); + + delete *Connection(); + + // Blocking destroy + Connection().GuardValue(false); + Linger().GuardValue(false); + RefCounter().GuardValue(false); + TransactionCancel().GuardValue(false); + TransactionDepth().GuardValue(false); + AttachCount().GuardValue(false); + + Connection().Reset(); + Linger().Reset(); + RefCounter().Reset(); + TransactionCancel().Reset(); + TransactionDepth().Reset(); + AttachCount().Reset(); + } + + void TransactionUnref() + { + LogPedantic("Unref transaction"); + + if (--(*TransactionDepth()) == 0) { + LogPedantic("Transaction is finalized"); + + if (*TransactionCancel()) { + LogPedantic("Transaction will be rolled back"); + (*Connection())->RollbackTransaction(); + } else { + LogPedantic("Transaction will be commited"); + (*Connection())->CommitTransaction(); + } + } + } + + public: + ThreadDatabaseSupport(const std::string &address, + DPL::DB::SqlConnection::Flag::Type flags) : + m_address(address), + m_flags(flags) + {} + + virtual ~ThreadDatabaseSupport() + {} + + void AttachToThread( + DPL::DB::SqlConnection::Flag::Option options = + DPL::DB::SqlConnection::Flag::RO) + { + Linger() = false; + + if (!Connection().IsNull()) { + // Add reference + ++*AttachCount(); + return; + } + + // Initialize SQL connection described in traits + LogDebug("Attaching thread database connection: " << m_address); + + Connection() = new DPL::DB::SqlConnection( + m_address.c_str(), m_flags, options); + + RefCounter() = 0; + + AttachCount() = 1; + + //Init Transaction related variables + TransactionDepth() = 0; + TransactionCancel() = false; + + // Blocking destroy + Connection().GuardValue(true); + Linger().GuardValue(true); + RefCounter().GuardValue(true); + TransactionDepth().GuardValue(true); + AttachCount().GuardValue(true); + TransactionCancel().GuardValue(true); + } + + void DetachFromThread() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Remove reference + --*AttachCount(); + + if (*AttachCount() > 0) { + return; + } + + // It must not be in linger state yet + Assert(*Linger() == false); + + LogDebug("Detaching thread database connection: " << m_address); + + // Enter linger state + *Linger() = true; + + // Checked delete + CheckedConnectionDelete(); + } + + bool IsAttached() + { + return !AttachCount().IsNull() && *AttachCount() > 0; + } + + DPL::DB::SqlConnection::DataCommand *AllocDataCommand( + const std::string &statement) + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Calling thread must not be in linger state + Assert(*Linger() == false); + + // Add reference + ++*RefCounter(); + + // Create new unmanaged data command + return (*Connection())->PrepareDataCommand(statement.c_str()).release(); + } + + void FreeDataCommand(DPL::DB::SqlConnection::DataCommand *command) + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Delete data command + delete command; + + // Unreference SQL connection + --*RefCounter(); + + // If it is linger state, connection may be destroyed + if (*Linger() == true) { + CheckedConnectionDelete(); + } + } + + void TransactionBegin() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + LogPedantic("Begin transaction"); + + // Addref transaction + if (++(*TransactionDepth()) == 1) { + LogPedantic("Transaction is initialized"); + + TransactionCancel() = false; + (*Connection())->BeginTransaction(); + } + } + + void TransactionCommit() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + LogPedantic("Commit transaction"); + + // Unref transation + TransactionUnref(); + } + + void TransactionRollback() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + // Cancel and unref transaction + TransactionCancel() = true; + TransactionUnref(); + } + + DPL::DB::SqlConnection::RowID GetLastInsertRowID() + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + return (*Connection())->GetLastInsertRowID(); + } + + bool CheckTableExist(const char *name) + { + // Calling thread must support thread database connections + Assert(!Connection().IsNull()); + + return (*Connection())->CheckTableExist(name); + } +}; +} +} + +#endif // DPL_THREAD_DATABASE_SUPPORT_H diff --git a/modules/db/src/naive_synchronization_object.cpp b/modules/db/src/naive_synchronization_object.cpp new file mode 100644 index 0000000..1ac71ca --- /dev/null +++ b/modules/db/src/naive_synchronization_object.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file naive_synchronization_object.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL naive + * synchronization object + */ +#include +#include +#include + +namespace { + unsigned int seed = time(NULL); +} + +namespace DPL { +namespace DB { +void NaiveSynchronizationObject::Synchronize() +{ + // Sleep for about 10ms - 30ms + Thread::MiliSleep(10 + rand_r(&seed) % 20); +} + +void NaiveSynchronizationObject::NotifyAll() +{ + // No need to inform about anything +} +} // namespace DB +} // namespace DPL diff --git a/modules/db/src/orm.cpp b/modules/db/src/orm.cpp new file mode 100644 index 0000000..c69415d --- /dev/null +++ b/modules/db/src/orm.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file orm.cpp + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Static definitions and function template specialziations of + * DPL-ORM. + */ +#include +#include + +namespace DPL { +namespace DB { +namespace ORM { +namespace RelationTypes { +const char Equal[] = "="; +const char LessThan[] = "<"; +const char And[] = "AND"; +const char Or[] = "OR"; +const char Is[] = "IS"; +const char In[] = "IN"; +} + +template<> +int GetColumnFromCommand(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnInteger(columnIndex); +} + +template<> +DPL::String GetColumnFromCommand(ColumnIndex columnIndex, + DataCommand *command) +{ + return DPL::FromUTF8String(command->GetColumnString(columnIndex)); +} + +template<> +OptionalInteger GetColumnFromCommand(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnOptionalInteger(columnIndex); +} + +template<> +OptionalString GetColumnFromCommand(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnOptionalString(columnIndex); +} + +template<> +double GetColumnFromCommand(ColumnIndex columnIndex, + DataCommand *command) +{ + return command->GetColumnDouble(columnIndex); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + int argument) +{ + command->BindInteger(index, argument); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + const OptionalInteger& argument) +{ + command->BindInteger(index, argument); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + const DPL::String& argument) +{ + command->BindString(index, argument); +} + +void DataCommandUtils::BindArgument(DataCommand *command, + ArgumentIndex index, + const OptionalString& argument) +{ + command->BindString(index, argument); +} +} +} +} diff --git a/modules/db/src/sql_connection.cpp b/modules/db/src/sql_connection.cpp new file mode 100644 index 0000000..60c6621 --- /dev/null +++ b/modules/db/src/sql_connection.cpp @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file sql_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of SQL connection + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DB { +namespace // anonymous +{ +class ScopedNotifyAll : + public Noncopyable +{ + private: + SqlConnection::SynchronizationObject *m_synchronizationObject; + + public: + explicit ScopedNotifyAll( + SqlConnection::SynchronizationObject *synchronizationObject) : + m_synchronizationObject(synchronizationObject) + {} + + ~ScopedNotifyAll() + { + if (!m_synchronizationObject) { + return; + } + + LogPedantic("Notifying after successful synchronize"); + m_synchronizationObject->NotifyAll(); + } +}; +} // namespace anonymous + +SqlConnection::DataCommand::DataCommand(SqlConnection *connection, + const char *buffer) : + m_masterConnection(connection), + m_stmt(NULL) +{ + Assert(connection != NULL); + + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get()); + + for (;;) { + int ret = sqlite3_prepare_v2(connection->m_connection, + buffer, strlen(buffer), + &m_stmt, NULL); + + if (ret == SQLITE_OK) { + LogPedantic("Data command prepared successfuly"); + break; + } else if (ret == SQLITE_BUSY) { + LogPedantic("Collision occurred while preparing SQL command"); + + // Synchronize if synchronization object is available + if (connection->m_synchronizationObject) { + LogPedantic("Performing synchronization"); + connection->m_synchronizationObject->Synchronize(); + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + const char *error = sqlite3_errmsg(m_masterConnection->m_connection); + + LogPedantic("SQL prepare data command failed"); + LogPedantic(" Statement: " << buffer); + LogPedantic(" Error: " << error); + + ThrowMsg(Exception::SyntaxError, error); + } + + LogPedantic("Prepared data command: " << buffer); + + // Increment stored data command count + ++m_masterConnection->m_dataCommandsCount; +} + +SqlConnection::DataCommand::~DataCommand() +{ + LogPedantic("SQL data command finalizing"); + + if (sqlite3_finalize(m_stmt) != SQLITE_OK) { + LogPedantic("Failed to finalize data command"); + } + + // Decrement stored data command count + --m_masterConnection->m_dataCommandsCount; +} + +void SqlConnection::DataCommand::CheckBindResult(int result) +{ + if (result != SQLITE_OK) { + const char *error = sqlite3_errmsg( + m_masterConnection->m_connection); + + LogPedantic("Failed to bind SQL statement parameter"); + LogPedantic(" Error: " << error); + + ThrowMsg(Exception::SyntaxError, error); + } +} + +void SqlConnection::DataCommand::BindNull( + SqlConnection::ArgumentIndex position) +{ + CheckBindResult(sqlite3_bind_null(m_stmt, position)); + LogPedantic("SQL data command bind null: [" + << position << "]"); +} + +void SqlConnection::DataCommand::BindInteger( + SqlConnection::ArgumentIndex position, + int value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, value)); + LogPedantic("SQL data command bind integer: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt8( + SqlConnection::ArgumentIndex position, + int8_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast(value))); + LogPedantic("SQL data command bind int8: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt16( + SqlConnection::ArgumentIndex position, + int16_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast(value))); + LogPedantic("SQL data command bind int16: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt32( + SqlConnection::ArgumentIndex position, + int32_t value) +{ + CheckBindResult(sqlite3_bind_int(m_stmt, position, + static_cast(value))); + LogPedantic("SQL data command bind int32: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindInt64( + SqlConnection::ArgumentIndex position, + int64_t value) +{ + CheckBindResult(sqlite3_bind_int64(m_stmt, position, + static_cast(value))); + LogPedantic("SQL data command bind int64: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindFloat( + SqlConnection::ArgumentIndex position, + float value) +{ + CheckBindResult(sqlite3_bind_double(m_stmt, position, + static_cast(value))); + LogPedantic("SQL data command bind float: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindDouble( + SqlConnection::ArgumentIndex position, + double value) +{ + CheckBindResult(sqlite3_bind_double(m_stmt, position, value)); + LogPedantic("SQL data command bind double: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const char *value) +{ + if (!value) { + BindNull(position); + return; + } + + // Assume that text may disappear + CheckBindResult(sqlite3_bind_text(m_stmt, position, + value, strlen(value), + SQLITE_TRANSIENT)); + + LogPedantic("SQL data command bind string: [" + << position << "] -> " << value); +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const String &value) +{ + BindString(position, ToUTF8String(value).c_str()); +} + +void SqlConnection::DataCommand::BindInteger( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInteger(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt8( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt8(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt16( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt16(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt32( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt32(position, *value); + } +} + +void SqlConnection::DataCommand::BindInt64( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindInt64(position, *value); + } +} + +void SqlConnection::DataCommand::BindFloat( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindFloat(position, *value); + } +} + +void SqlConnection::DataCommand::BindDouble( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (value.IsNull()) { + BindNull(position); + } else { + BindDouble(position, *value); + } +} + +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const Optional &value) +{ + if (!!value) { + BindString(position, ToUTF8String(*value).c_str()); + } else { + BindNull(position); + } +} + +bool SqlConnection::DataCommand::Step() +{ + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll( + m_masterConnection->m_synchronizationObject.get()); + + for (;;) { + int ret = sqlite3_step(m_stmt); + + if (ret == SQLITE_ROW) { + LogPedantic("SQL data command step ROW"); + return true; + } else if (ret == SQLITE_DONE) { + LogPedantic("SQL data command step DONE"); + return false; + } else if (ret == SQLITE_BUSY) { + LogPedantic("Collision occurred while executing SQL command"); + + // Synchronize if synchronization object is available + if (m_masterConnection->m_synchronizationObject) { + LogPedantic("Performing synchronization"); + + m_masterConnection-> + m_synchronizationObject->Synchronize(); + + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + const char *error = sqlite3_errmsg(m_masterConnection->m_connection); + + LogPedantic("SQL step data command failed"); + LogPedantic(" Error: " << error); + + ThrowMsg(Exception::InternalError, error); + } +} + +void SqlConnection::DataCommand::Reset() +{ + /* + * According to: + * http://www.sqlite.org/c3ref/stmt.html + * + * if last sqlite3_step command on this stmt returned an error, + * then sqlite3_reset will return that error, althought it is not an error. + * So sqlite3_reset allways succedes. + */ + sqlite3_reset(m_stmt); + + LogPedantic("SQL data command reset"); +} + +void SqlConnection::DataCommand::CheckColumnIndex( + SqlConnection::ColumnIndex column) +{ + if (column < 0 || column >= sqlite3_column_count(m_stmt)) { + ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds"); + } +} + +bool SqlConnection::DataCommand::IsColumnNull( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column type: [" << column << "]"); + CheckColumnIndex(column); + return sqlite3_column_type(m_stmt, column) == SQLITE_NULL; +} + +int SqlConnection::DataCommand::GetColumnInteger( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column integer: [" << column << "]"); + CheckColumnIndex(column); + int value = sqlite3_column_int(m_stmt, column); + LogPedantic(" Value: " << value); + return value; +} + +int8_t SqlConnection::DataCommand::GetColumnInt8( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column int8: [" << column << "]"); + CheckColumnIndex(column); + int8_t value = static_cast(sqlite3_column_int(m_stmt, column)); + LogPedantic(" Value: " << value); + return value; +} + +int16_t SqlConnection::DataCommand::GetColumnInt16( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column int16: [" << column << "]"); + CheckColumnIndex(column); + int16_t value = static_cast(sqlite3_column_int(m_stmt, column)); + LogPedantic(" Value: " << value); + return value; +} + +int32_t SqlConnection::DataCommand::GetColumnInt32( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column int32: [" << column << "]"); + CheckColumnIndex(column); + int32_t value = static_cast(sqlite3_column_int(m_stmt, column)); + LogPedantic(" Value: " << value); + return value; +} + +int64_t SqlConnection::DataCommand::GetColumnInt64( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column int64: [" << column << "]"); + CheckColumnIndex(column); + int64_t value = static_cast(sqlite3_column_int64(m_stmt, column)); + LogPedantic(" Value: " << value); + return value; +} + +float SqlConnection::DataCommand::GetColumnFloat( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column float: [" << column << "]"); + CheckColumnIndex(column); + float value = static_cast(sqlite3_column_double(m_stmt, column)); + LogPedantic(" Value: " << value); + return value; +} + +double SqlConnection::DataCommand::GetColumnDouble( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column double: [" << column << "]"); + CheckColumnIndex(column); + double value = sqlite3_column_double(m_stmt, column); + LogPedantic(" Value: " << value); + return value; +} + +std::string SqlConnection::DataCommand::GetColumnString( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column string: [" << column << "]"); + CheckColumnIndex(column); + + const char *value = reinterpret_cast( + sqlite3_column_text(m_stmt, column)); + + LogPedantic("Value: " << (value ? value : "NULL")); + + if (value == NULL) { + return std::string(); + } + + return std::string(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalInteger( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional integer: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + int value = sqlite3_column_int(m_stmt, column); + LogPedantic(" Value: " << value); + return Optional(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalInt8( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional int8: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + int8_t value = static_cast(sqlite3_column_int(m_stmt, column)); + LogPedantic(" Value: " << value); + return Optional(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalInt16( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional int16: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + int16_t value = static_cast(sqlite3_column_int(m_stmt, column)); + LogPedantic(" Value: " << value); + return Optional(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalInt32( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional int32: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + int32_t value = static_cast(sqlite3_column_int(m_stmt, column)); + LogPedantic(" Value: " << value); + return Optional(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalInt64( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional int64: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + int64_t value = static_cast(sqlite3_column_int64(m_stmt, column)); + LogPedantic(" Value: " << value); + return Optional(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalFloat( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional float: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + float value = static_cast(sqlite3_column_double(m_stmt, column)); + LogPedantic(" Value: " << value); + return Optional(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalDouble( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional double: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + double value = sqlite3_column_double(m_stmt, column); + LogPedantic(" Value: " << value); + return Optional(value); +} + +Optional SqlConnection::DataCommand::GetColumnOptionalString( + SqlConnection::ColumnIndex column) +{ + LogPedantic("SQL data command get column optional string: [" + << column << "]"); + CheckColumnIndex(column); + if (sqlite3_column_type(m_stmt, column) == SQLITE_NULL) { + return Optional::Null; + } + const char *value = reinterpret_cast( + sqlite3_column_text(m_stmt, column)); + LogPedantic("Value: " << value); + String s = FromUTF8String(value); + return Optional(s); +} + +void SqlConnection::Connect(const std::string &address, + Flag::Type type, + Flag::Option flag) +{ + if (m_connection != NULL) { + LogPedantic("Already connected."); + return; + } + LogPedantic("Connecting to DB: " << address << "..."); + + // Connect to database + int result = -1; + int retry = 5; + while( result != SQLITE_OK){ + if (type & Flag::UseLucene) { + result = db_util_open_with_options( + address.c_str(), + &m_connection, + flag, + NULL); + + m_usingLucene = true; + LogPedantic("Lucene index enabled"); + } else { + result = sqlite3_open_v2( + address.c_str(), + &m_connection, + flag, + NULL); + + m_usingLucene = false; + LogPedantic("Lucene index disabled"); + } + + if (result == SQLITE_OK) { + LogPedantic("Connected to DB"); + } else { + LogPedantic("Failed to connect to DB! ret="<BindString(1, tableName); + + if (!command->Step()) { + LogPedantic("No matching records in table"); + return false; + } + + return command->GetColumnString(0) == tableName; +} + +SqlConnection::SqlConnection(const std::string &address, + Flag::Type flag, + Flag::Option option, + SynchronizationObject *synchronizationObject) : + m_connection(NULL), + m_usingLucene(false), + m_dataCommandsCount(0), + m_synchronizationObject(synchronizationObject) +{ + LogPedantic("Opening database connection to: " << address); + + // Connect to DB + SqlConnection::Connect(address, flag, option); + + if (!m_synchronizationObject) { + LogPedantic("No synchronization object defined"); + } +} + +SqlConnection::~SqlConnection() +{ + LogPedantic("Closing database connection"); + + // Disconnect from DB + Try + { + SqlConnection::Disconnect(); + } + Catch(Exception::Base) + { + LogPedantic("Failed to disconnect from database"); + } +} + +void SqlConnection::ExecCommand(const char *format, ...) +{ + if (m_connection == NULL) { + LogPedantic("Cannot execute command. Not connected to DB!"); + return; + } + + if (format == NULL) { + LogPedantic("Null query!"); + ThrowMsg(Exception::SyntaxError, "Null statement"); + } + + char *rawBuffer; + + va_list args; + va_start(args, format); + + if (vasprintf(&rawBuffer, format, args) == -1) { + rawBuffer = NULL; + } + + va_end(args); + + ScopedFree buffer(rawBuffer); + + if (!buffer) { + LogPedantic("Failed to allocate statement string"); + return; + } + + LogPedantic("Executing SQL command: " << buffer.Get()); + + // Notify all after potentially synchronized database connection access + ScopedNotifyAll notifyAll(m_synchronizationObject.get()); + + for (;;) { + char *errorBuffer; + + int ret = sqlite3_exec(m_connection, + buffer.Get(), + NULL, + NULL, + &errorBuffer); + + std::string errorMsg; + + // Take allocated error buffer + if (errorBuffer != NULL) { + errorMsg = errorBuffer; + sqlite3_free(errorBuffer); + } + + if (ret == SQLITE_OK) { + return; + } + + if (ret == SQLITE_BUSY) { + LogPedantic("Collision occurred while executing SQL command"); + + // Synchronize if synchronization object is available + if (m_synchronizationObject) { + LogPedantic("Performing synchronization"); + m_synchronizationObject->Synchronize(); + continue; + } + + // No synchronization object defined. Fail. + } + + // Fatal error + LogPedantic("Failed to execute SQL command. Error: " << errorMsg); + ThrowMsg(Exception::SyntaxError, errorMsg); + } +} + +SqlConnection::DataCommandAutoPtr SqlConnection::PrepareDataCommand( + const char *format, + ...) +{ + if (m_connection == NULL) { + LogPedantic("Cannot execute data command. Not connected to DB!"); + return DataCommandAutoPtr(); + } + + char *rawBuffer; + + va_list args; + va_start(args, format); + + if (vasprintf(&rawBuffer, format, args) == -1) { + rawBuffer = NULL; + } + + va_end(args); + + ScopedFree buffer(rawBuffer); + + if (!buffer) { + LogPedantic("Failed to allocate statement string"); + return DataCommandAutoPtr(); + } + + LogPedantic("Executing SQL data command: " << buffer.Get()); + + return DataCommandAutoPtr(new DataCommand(this, buffer.Get())); +} + +SqlConnection::RowID SqlConnection::GetLastInsertRowID() const +{ + return static_cast(sqlite3_last_insert_rowid(m_connection)); +} + +void SqlConnection::TurnOnForeignKeys() +{ + ExecCommand("PRAGMA foreign_keys = ON;"); +} + +void SqlConnection::BeginTransaction() +{ + ExecCommand("BEGIN;"); +} + +void SqlConnection::RollbackTransaction() +{ + ExecCommand("ROLLBACK;"); +} + +void SqlConnection::CommitTransaction() +{ + ExecCommand("COMMIT;"); +} + +SqlConnection::SynchronizationObject * +SqlConnection::AllocDefaultSynchronizationObject() +{ + return new NaiveSynchronizationObject(); +} +} // namespace DB +} // namespace DPL diff --git a/modules/db/src/thread_database_support.cpp b/modules/db/src/thread_database_support.cpp new file mode 100644 index 0000000..101640f --- /dev/null +++ b/modules/db/src/thread_database_support.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread_database_support.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk) + * @version 1.0 + * @brief This file contains the definition of thread database support + */ +#include +#include \ No newline at end of file diff --git a/modules/dbus/config.cmake b/modules/dbus/config.cmake new file mode 100644 index 0000000..f2fefde --- /dev/null +++ b/modules/dbus/config.cmake @@ -0,0 +1,56 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_DBUS_SOURCES + ${PROJECT_SOURCE_DIR}/modules/dbus/src/connection.cpp + ${PROJECT_SOURCE_DIR}/modules/dbus/src/dispatcher.cpp + ${PROJECT_SOURCE_DIR}/modules/dbus/src/interface.cpp + ${PROJECT_SOURCE_DIR}/modules/dbus/src/object.cpp + ${PROJECT_SOURCE_DIR}/modules/dbus/src/object_proxy.cpp + ${PROJECT_SOURCE_DIR}/modules/dbus/src/server.cpp + PARENT_SCOPE +) + + +SET(DPL_DBUS_HEADERS + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/connection.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dbus_client.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dbus_deserialization.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dbus_interface_dispatcher.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dbus_serialization.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dbus_server_deserialization.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dbus_server_serialization.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dbus_signature.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/dispatcher.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/glib_util.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/exception.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/interface.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/method_proxy.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/object.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/object_proxy.h + ${PROJECT_SOURCE_DIR}/modules/dbus/include/dpl/dbus/server.h + PARENT_SCOPE +) + +SET(DPL_DBUS_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/dbus/include + PARENT_SCOPE +) diff --git a/modules/dbus/include/dpl/dbus/connection.h b/modules/dbus/include/dpl/dbus/connection.h new file mode 100644 index 0000000..4a455ad --- /dev/null +++ b/modules/dbus/include/dpl/dbus/connection.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file connection.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_CONNECTION_H +#define DPL_DBUS_CONNECTION_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +namespace ConnectionEvents { +/** + * Emitted when service name is acquired. + * + * Arg0 Acquired name. + */ +DECLARE_GENERIC_EVENT_1(ServiceNameAcquiredEvent, std::string) + +/** + * Emitted when service name is lost. + * + * Arg0 Lost name. + */ +DECLARE_GENERIC_EVENT_1(ServiceNameLostEvent, std::string) + +/** + * Emitted when remote host closes connection. + * + * Arg0 Low-level error message. + */ +DECLARE_GENERIC_EVENT_1(ConnectionBrokenEvent, std::string) + +/** + * Emitted when invalid or malformed data appear on connection. + * + * Arg0 Low-level error message. + */ +DECLARE_GENERIC_EVENT_1(ConnectionInvalidEvent, std::string) +} + +class Server; + +class Connection; +typedef std::shared_ptr ConnectionPtr; + +typedef std::shared_ptr ObjectProxyPtr; + +class Connection : + public DPL::Event::EventSupport, + public DPL::Event::EventSupport, + public DPL::Event::EventSupport, + public DPL::Event::EventSupport +{ + public: + /** + * Acquires connection to session bus. + * + * @return Session bus connection. + * @throw DBus::Exception If unable to connect to session bus. + */ + static ConnectionPtr sessionBus(); + + /** + * Acquires connection to system bus. + * + * @return System bus connection. + * @throw DBus::Exception If unable to connect to system bus. + */ + static ConnectionPtr systemBus(); + + /** + * Acquires connection to specified bus. + * + * @return Bus connection. + * @throw DBus::Exception If unable to connect to a bus. + */ + static ConnectionPtr connectTo(GBusType busType); + + /** + * Acquires connection to for specified address. + * + * @return Connection. + * @throw DBus::Exception If unable to connect. + * + * @remarks Address should be in DBus format (@see DBus documentation). + */ + static ConnectionPtr connectTo(const std::string& address); + + ~Connection(); + + /** + * Sets up a service on the connection. + * + * @param serviceName Service to register. + * @throw DBus::Exception If registration failed. + * + * @remarks Add objects before services to prevent notifications about new + * interfaces being added. + */ + void registerService(const std::string& serviceName); + + /** + * Unregisters a service from the connection. + * + * @param serviceName Service to unregister. + * @throw DBus::Exception If service not registered. + */ + void unregisterService(const std::string& serviceName); + + /** + * Adds object to the connection. + * + * @param object Object to register. + * @throw DBus::Exception If registration failed. + * + * @remarks Add objects before services to prevent notifications about new + * interfaces being added. + */ + void registerObject(const ObjectPtr& object); + + /** + * Removed object from the connection. + * + * @param objectPath Path of the object to unregister. + * @throw DBus::Exception If object not registered. + */ + void unregisterObject(const std::string& objectPath); + + /** + * Creates proxy to remote objects. + * + * @param serviceName Name of the DBus service. + * @param objectPath DBus path to the object. + * @return Object proxy. + * @throw DBus::ConnectionClosedException If connection is closed. + */ + ObjectProxyPtr createObjectProxy(const std::string& serviceName, + const std::string& objectPath); + + private: + friend class Server; + + typedef std::map RegisteredServices; + + struct ObjectRegistration + { + ObjectRegistration(guint _registrationId, const ObjectPtr& _object) : + registrationId(_registrationId), + object(_object) + {} + + guint registrationId; + ObjectPtr object; + }; + typedef std::map RegisteredObjects; + + static void onServiceNameAcquired(GDBusConnection* connection, + const gchar* serviceName, + gpointer data); + + static void onServiceNameLost(GDBusConnection* connection, + const gchar* serviceName, + gpointer data); + + static void onConnectionClosed(GDBusConnection* connection, + gboolean peerVanished, + GError* error, + gpointer data); + + explicit Connection(GDBusConnection* connection); + + GDBusConnection* m_connection; + + RegisteredServices m_registeredServices; + + RegisteredObjects m_registeredObjects; +}; +} +} + +#endif // DPL_DBUS_CONNECTION_H diff --git a/modules/dbus/include/dpl/dbus/dbus_client.h b/modules/dbus/include/dpl/dbus/dbus_client.h new file mode 100644 index 0000000..061ec46 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dbus_client.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dbus_client.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Header file for DBus generic client support + */ + +#ifndef DPL_DBUS_DBUS_CLIENT_H_ +#define DPL_DBUS_DBUS_CLIENT_H_ + +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +/* + * DBus::Client class is intended to act as simple DBus client. To call a method + * on remote service "Service", on remote object "Object", interface + * "Interface",use it like this: + * + * + * DBus::Client client("Object", "Service", "Interface"); + * (...) // variables declarations + * client.call("Method name", arg1, arg2, arg2, ... argN, + * &outArg1, &outArg2, &outArg3, ..., &outArgN); + * + * + * As You can see, input parameters of the call are passed with reference, + * output ones are passed as pointers - parameters MUST be passed this way. + * + * To call a void function (no out params), just pass in arguments to Call(). + * + * Currently client supports serialization and deserialization of simple types + * (int, char, float, unsigned), strings (std::string and char*) and + * some STL containers (std::vector, std::list, std::map, std::set, std::pair). + * Structures and classes are not (yet) supported. + */ + +class Client +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DBusClientException) + }; + + Client(std::string serverPath, + std::string serviceName, + std::string interfaceName) : + m_serviceName(serviceName), + m_serverPath(serverPath), + m_interfaceName(interfaceName) + { + DBusError error; + + dbus_error_init(&error); + m_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (NULL == m_connection) { + LogPedantic("Couldn't get DBUS connection. Error: " << + error.message); + dbus_error_free(&error); + ThrowMsg(Exception::DBusClientException, + "Couldn't get DBUS connection."); + } + } + + template + void call(const char* methodName, const Args& ... args) + { + DBusMessage* message = dbus_message_new_method_call( + m_serviceName.c_str(), + m_serverPath.c_str(), + m_interfaceName.c_str(), + methodName); + DBusMessageIter argsIterator; + dbus_message_iter_init_append(message, &argsIterator); + call(message, &argsIterator, args ...); + dbus_message_unref(message); + } + + template + void call(std::string methodName, const Args& ... args) + { + call(methodName.c_str(), args ...); + } + + ~Client() + { + dbus_connection_unref(m_connection); + } + + private: + + DBusMessage* makeCall( + DBusMessage* message) + { + DBusError error; + dbus_error_init(&error); + DBusMessage* ret = dbus_connection_send_with_reply_and_block( + m_connection, + message, + -1, + &error); + if (NULL == ret) { + LogPedantic("Error sending DBUS message: " << + error.message); + dbus_error_free(&error); + ThrowMsg(Exception::DBusClientException, + "Error sending DBUS message."); + } + return ret; + } + + void call(DBusMessage* message, DBusMessageIter* /*argsIterator*/) + { + DBusMessage* ret = makeCall(message); + if (ret != NULL) { + dbus_message_unref(ret); + } else { + LogPedantic("Error getting DBUS response."); + ThrowMsg(Exception::DBusClientException, + "Error getting DBUS response."); + } + } + + template + void call( + DBusMessage* message, + DBusMessageIter* argsIterator, + const T& invalue, + const Args& ... args) + { + if (!Serialization::serialize(argsIterator, invalue)) { + LogPedantic("Error in serialization."); + ThrowMsg(Exception::DBusClientException, + "Error in serialization."); + } + call(message, argsIterator, args ...); + } + + template + void call( + DBusMessage* message, + DBusMessageIter* argsIterator, + const T* invalue, + const Args& ... args) + { + if (!Serialization::serialize(argsIterator, invalue)) { + LogPedantic("Error in serialization."); + ThrowMsg(Exception::DBusClientException, + "Error in serialization."); + } + call(message, argsIterator, args ...); + } + + template + void call( + DBusMessage* message, + DBusMessageIter* argsIterator, + const T* invalue) + { + if (!Serialization::serialize(argsIterator, invalue)) { + LogPedantic("Error in serialization."); + ThrowMsg(Exception::DBusClientException, + "Error in serialization."); + } + call(message, argsIterator); + } + + template + void call( + DBusMessage* message, + DBusMessageIter* /*argsIterator*/, + T* out, + const Args& ... args) + { + DBusMessage* ret = makeCall(message); + if (ret != NULL) { + DBusMessageIter responseIterator; + dbus_message_iter_init(ret, &responseIterator); + returnFromCall(&responseIterator, out, args ...); + dbus_message_unref(ret); + } + } + + template + void returnFromCall( + DBusMessageIter* responseIterator, + T* out, + const Args& ... args) + { + if (!Deserialization::deserialize(responseIterator, out)) { + LogPedantic("Error in deserialization."); + ThrowMsg(Exception::DBusClientException, + "Error in deserialization."); + } + returnFromCall(responseIterator, args ...); + } + + template + void returnFromCall(DBusMessageIter* responseIterator, T* out) + { + if (!Deserialization::deserialize(responseIterator, out)) { + LogPedantic("Error in deserialization."); + ThrowMsg(Exception::DBusClientException, + "Error in deserialization."); + } + } + + std::string m_serviceName, m_serverPath, m_interfaceName; + DBusConnection* m_connection; +}; +} // namespace DBus +} // namespace DPL + +#endif // DPL_DBUS_DBUS_CLIENT_H_ diff --git a/modules/dbus/include/dpl/dbus/dbus_deserialization.h b/modules/dbus/include/dpl/dbus/dbus_deserialization.h new file mode 100644 index 0000000..2a05db8 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dbus_deserialization.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dbus_deserialization.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Header file for DBus data deserialization + */ + +#ifndef DPL_DBUS_DBUS_DESERIALIZATION_H_ +#define DPL_DBUS_DBUS_DESERIALIZATION_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +struct Deserialization +{ + static bool deserializePrimitive( + DBusMessageIter* responseIterator, + void* arg, + int type) + { + if (dbus_message_iter_get_arg_type(responseIterator) != type) { + return false; + } + dbus_message_iter_get_basic(responseIterator, arg); + return true; + } + + // char* and all integer types + doubles + template + static bool deserialize(DBusMessageIter* responseIterator, T* arg) + { + if (dbus_message_iter_get_arg_type(responseIterator) + != SimpleType::value) + { + return false; + } + dbus_message_iter_get_basic(responseIterator, arg); + return true; + } + + // float case - read as double + static bool deserialize(DBusMessageIter* responseIterator, float* arg) + { + double d; + if (!deserialize(responseIterator, &d)) { + return false; + } + *arg = static_cast(d); + return true; + } + + // std::string + static bool deserialize( + DBusMessageIter* responseIterator, + std::string* arg) + { + char* str = NULL; + if (!deserialize(responseIterator, &str)) { + return false; + } + *arg = std::string(str); + return true; + } + + // dbus array deserialization + template + static bool deserializeContainer( + DBusMessageIter* responseIterator, + T* arg) + { + if (dbus_message_iter_get_arg_type(responseIterator) + != DBUS_TYPE_ARRAY) + { + return false; + } + DBusMessageIter subIterator; + dbus_message_iter_recurse(responseIterator, &subIterator); + while (dbus_message_iter_get_arg_type(&subIterator) + != DBUS_TYPE_INVALID) + { + arg->push_back(typename T::value_type()); + if (!deserialize(&subIterator, &arg->back())) { + return false; + } + dbus_message_iter_next(&subIterator); + } + return true; + } + + // std::vector + template + static bool deserialize( + DBusMessageIter* responseIterator, + std::vector* arg) + { + return deserializeContainer(responseIterator, arg); + } + + // std::list + template + static bool deserialize( + DBusMessageIter* responseIterator, + std::list* arg) + { + return deserializeContainer(responseIterator, arg); + } + + // std::set + template + static bool deserialize( + DBusMessageIter* responseIterator, + std::set* arg) + { + if (dbus_message_iter_get_arg_type(responseIterator) + != DBUS_TYPE_ARRAY) + { + return false; + } + DBusMessageIter subIterator; + dbus_message_iter_recurse(responseIterator, &subIterator); + while (dbus_message_iter_get_arg_type(&subIterator) + != DBUS_TYPE_INVALID) + { + typename std::set::value_type element; + if (!deserialize(&subIterator, &element)) { + return false; + } + arg->insert(element); + dbus_message_iter_next(&subIterator); + } + return true; + } + + // std::pair + template + static bool deserialize( + DBusMessageIter* argsIterator, + const std::pair* arg) + { + if (dbus_message_iter_get_arg_type(argsIterator) + != DBUS_TYPE_DICT_ENTRY) + { + return false; + } + DBusMessageIter dictEntryIterator; + dbus_message_iter_recurse(argsIterator, &dictEntryIterator); + if (!deserialize(dictEntryIterator, &arg->first)) { + return false; + } + dbus_message_iter_next(&dictEntryIterator); + if (!deserialize(dictEntryIterator, &arg->second)) { + return false; + } + return true; + } + + // std::map + template + static bool deserialize( + DBusMessageIter* responseIterator, + const std::map* arg) + { + if (dbus_message_iter_get_arg_type(responseIterator) + != DBUS_TYPE_ARRAY) + { + return false; + } + DBusMessageIter subIterator; + dbus_message_iter_recurse(responseIterator, &subIterator); + while (dbus_message_iter_get_arg_type(&subIterator) + != DBUS_TYPE_INVALID) + { + typename std::pair element; + if (!deserialize(&subIterator, &element)) { + return false; + } + arg->insert(element); + dbus_message_iter_next(&subIterator); + } + return true; + } +}; + +template<> +inline bool Deserialization::deserialize( + DBusMessageIter* responseIterator, + bool* arg) +{ + unsigned int value; + if (dbus_message_iter_get_arg_type(responseIterator) + != SimpleType::value) + { + return false; + } + dbus_message_iter_get_basic(responseIterator, &value); + *arg = static_cast(value); + return true; +} +} // namespace DBus +} // namespace DPL + +#endif // DPL_DBUS_DBUS_DESERIALIZATION_H_ diff --git a/modules/dbus/include/dpl/dbus/dbus_interface_dispatcher.h b/modules/dbus/include/dpl/dbus/dbus_interface_dispatcher.h new file mode 100644 index 0000000..97d7407 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dbus_interface_dispatcher.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file dbus_interface_dispatcher.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file contains definitions of DBus::InterfaceDispatcher + * class. + */ + +#ifndef DPL_DBUS_DBUS_INTERFACE_DISPATCHER_H_ +#define DPL_DBUS_DBUS_INTERFACE_DISPATCHER_H_ + +#include +#include +#include + +namespace DPL { +namespace DBus { +class InterfaceDispatcher : public DBus::Dispatcher +{ + public: + explicit InterfaceDispatcher(const std::string& interfaceName) : + m_interfaceName(interfaceName) + {} + + virtual ~InterfaceDispatcher() + {} + + // Implement it in specific interface with method handling + virtual void onMethodCall(const gchar* /*methodName*/, + GVariant* /*parameters*/, + GDBusMethodInvocation* /*invocation*/) = 0; + + virtual std::string getName() const + { + return m_interfaceName; + } + + virtual std::string getXmlSignature() const + { + return m_xml; + } + virtual void setXmlSignature(const std::string& newSignature) + { + m_xml = newSignature; + } + + virtual void onMethodCall(GDBusConnection* /*connection*/, + const gchar* /*sender*/, + const gchar* /*objectPath*/, + const gchar* interfaceName, + const gchar* methodName, + GVariant* parameters, + GDBusMethodInvocation* invocation) + { + if (g_strcmp0(interfaceName, m_interfaceName.c_str()) == 0) { + onMethodCall(methodName, parameters, invocation); + } else { + LogPedantic("Called invalid interface: " << interfaceName << + " instead of: " << m_interfaceName); + } + } + + virtual GVariant* onPropertyGet(GDBusConnection* /*connection*/, + const gchar* /*sender*/, + const gchar* /*objectPath*/, + const gchar* /*interfaceName*/, + const gchar* propertyName) + { + LogDebug("InterfaceDispatcher onPropertyGet: " << propertyName); + return NULL; + } + + virtual gboolean onPropertySet(GDBusConnection* /*connection*/, + const gchar* /*sender*/, + const gchar* /*objectPath*/, + const gchar* /*interfaceName*/, + const gchar* propertyName, + GVariant* /*value*/) + { + LogDebug("InterfaceDispatcher onPropertySet: " << propertyName); + return false; + } + + private: + std::string m_interfaceName, m_xml; +}; +} // namespace DBus +} // namespace DPL + +#endif // DPL_DBUS_DBUS_INTERFACE_DISPATCHER_H_ diff --git a/modules/dbus/include/dpl/dbus/dbus_serialization.h b/modules/dbus/include/dpl/dbus/dbus_serialization.h new file mode 100644 index 0000000..c0fa338 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dbus_serialization.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dbus_serialization.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Header file for DBus data derialization + */ + +#ifndef DPL_DBUS_DBUS_SERIALIZATION_H_ +#define DPL_DBUS_DBUS_SERIALIZATION_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +struct Serialization +{ + // std::string + static bool serialize( + DBusMessageIter* argsIterator, + const std::string& str) + { + return serialize(argsIterator, str.c_str()); + } + + // float case - send as double + static bool serialize(DBusMessageIter* argsIterator, const float& arg) + { + const double d = static_cast(arg); + return serialize(argsIterator, d); + } + + // char* and all integer types + doubles + template + static bool serialize(DBusMessageIter* argsIterator, const T& arg) + { + return dbus_message_iter_append_basic(argsIterator, + SimpleType::value, + &arg); + } + + // dbus array serialization + template + static bool serializeContainer( + DBusMessageIter* argsIterator, + const T& arg) + { + typename T::const_iterator containerIt; + DBusMessageIter subIterator; + if (!dbus_message_iter_open_container(argsIterator, DBUS_TYPE_ARRAY, + Signature + ::value(), &subIterator)) + { + return false; + } + FOREACH(containerIt, arg) { + if (!serialize(&subIterator, *containerIt)) { + return false; + } + } + return dbus_message_iter_close_container(argsIterator, &subIterator); + } + + // std::vector + template + static bool serialize( + DBusMessageIter* argsIterator, + const std::vector &arg) + { + return serializeContainer(argsIterator, arg); + } + + // std::list + template + static bool serialize( + DBusMessageIter* argsIterator, + const std::list &arg) + { + return serializeContainer(argsIterator, arg); + } + + // std::set + template + static bool serialize( + DBusMessageIter* argsIterator, + const std::set &arg) + { + return serializeContainer(argsIterator, arg); + } + + // std::pair + template + static bool serialize( + DBusMessageIter* argsIterator, + const std::pair &arg) + { + DBusMessageIter dictEntryIterator; + if (!dbus_message_iter_open_container(argsIterator, + DBUS_TYPE_DICT_ENTRY, NULL, + &dictEntryIterator)) + { + return false; + } + if (!serialize(dictEntryIterator, arg.first)) { + return false; + } + if (!serialize(dictEntryIterator, arg.second)) { + return false; + } + return dbus_message_iter_close_container(argsIterator, + &dictEntryIterator); + } + + // std::map + template + static bool serialize( + DBusMessageIter* argsIterator, + const std::map &arg) + { + return serializeContainer(argsIterator, arg); + } +}; + +// char* and all integer types + doubles +template<> +inline bool Serialization::serialize(DBusMessageIter* argsIterator, + const bool& arg) +{ + unsigned int value = static_cast(arg); + return dbus_message_iter_append_basic(argsIterator, + SimpleType::value, + &value); +} +} // namespace DBus +} // namespace DPL + +#endif // DPL_DBUS_DBUS_SERIALIZATION_H_ diff --git a/modules/dbus/include/dpl/dbus/dbus_server_deserialization.h b/modules/dbus/include/dpl/dbus/dbus_server_deserialization.h new file mode 100644 index 0000000..eb09d6d --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dbus_server_deserialization.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dbus_server_deserialization.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Header file for DBus data deserialization from GVariant + */ + +#ifndef DPL_DBUS_DBUS_SERVER_DESERIALIZATION_H_ +#define DPL_DBUS_DBUS_SERVER_DESERIALIZATION_H_ + +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +struct ServerDeserialization { + template + static bool deserialize(GVariant* g, T* arg1, Args ... args) + { + Assert(NULL != g); + Assert(NULL != arg1); + GVariantIter* iterator = g_variant_iter_new(g); + if (NULL == iterator) { + return false; + } + if (!deserializeIterator(iterator, arg1)) { + g_variant_iter_free(iterator); + return false; + } + if (!deserializeIterator(iterator, args ...)) { + g_variant_iter_free(iterator); + return false; + } + g_variant_iter_free(iterator); + return true; + } + + template + static bool deserialize(GVariant* g, T* arg1) + { + Assert(NULL != g); + Assert(NULL != arg1); + GVariantIter* iterator = g_variant_iter_new(g); + if (NULL == iterator) { + return false; + } + if (!deserializeIterator(iterator, arg1)) { + g_variant_iter_free(iterator); + return false; + } + g_variant_iter_free(iterator); + return true; + } + + // deserialization from GVariant tuple iterator + template + static bool deserializeIterator(GVariantIter* g, T* arg1, Args ... args) + { + Assert(NULL != g); + Assert(NULL != arg1); + GVariant* elem = g_variant_iter_next_value(g); + if (NULL == elem) { + return false; + } + if (!deserializeElem(elem, arg1)) { + return false; + } + if (!deserializeIterator(g, args ...)) { + return false; + } + return true; + } + + template + static bool deserializeIterator(GVariantIter* g, T* arg1) + { + Assert(NULL != g); + Assert(NULL != arg1); + GVariant* elem = g_variant_iter_next_value(g); + if (NULL == elem) { + return false; + } + if (!deserializeElem(elem, arg1)) { + return false; + } + g_variant_unref(elem); + return true; + } + + // type specialization + static bool deserializeElem(GVariant* parameters, std::string* outStr) + { + const gchar* arg = g_variant_get_string(parameters, NULL); + *outStr = std::string(arg); + return true; + } + + static bool deserializeElem(GVariant* parameters, int* outInt) + { + gint32 arg = g_variant_get_int32(parameters); + *outInt = arg; + return true; + } + + static bool deserializeElem(GVariant* parameters, unsigned* outInt) + { + guint32 arg = g_variant_get_uint32(parameters); + *outInt = arg; + return true; + } + + static bool deserializeElem(GVariant* parameters, bool* outInt) + { + gboolean arg = g_variant_get_boolean(parameters); + *outInt = arg; + return true; + } + + static bool deserializeElem(GVariant* parameters, float* outInt) + { + gdouble arg = g_variant_get_double(parameters); + *outInt = static_cast(arg); + return true; + } + + static bool deserializeElem(GVariant* parameters, + std::vector* outArray) + { + unsigned int i = 0; + gsize length = 0; + const gchar** args = g_variant_get_strv( + parameters, + &length); + for (i = 0; i < length; ++i) { + outArray->push_back(std::string(args[i])); + } + g_free(args); + return true; + } + + static bool deserializeElem(GVariant* parameters, + std::list* outArray) + { + unsigned int i = 0; + gsize length = 0; + const gchar** args = g_variant_get_strv( + parameters, + &length); + for (i = 0; i < length; ++i) { + outArray->push_back(std::string(args[i])); + } + g_free(args); + return true; + } +}; +} // namespace DBus +} // namespace DPL + +#endif // DPL_DBUS_DBUS_SERVER_DESERIALIZATION_H_ diff --git a/modules/dbus/include/dpl/dbus/dbus_server_serialization.h b/modules/dbus/include/dpl/dbus/dbus_server_serialization.h new file mode 100644 index 0000000..9e47ca6 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dbus_server_serialization.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dbus_server_serialization.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Header file for DBus data serialization to GVariant + */ + +#ifndef DPL_DBUS_DBUS_SERVER_SERIALIZATION_H_ +#define DPL_DBUS_DBUS_SERVER_SERIALIZATION_H_ + +#include +#include + +namespace DPL { +namespace DBus { +struct ServerSerialization { + template + static GVariant* serialize(Args ... args) + { + GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE_TUPLE); + if (NULL == builder) { + return NULL; + } + serializeBuilder(builder, args ...); + return g_variant_builder_end(builder); + } + + // serialization on GVariantBuilder + template + static void serializeBuilder(GVariantBuilder* builder, + const T& arg, + Args ... args) + { + serializeElem(builder, arg); + serializeBuilder(builder, args ...); + } + + template + static void serializeBuilder(GVariantBuilder* builder, const T& arg) + { + serializeElem(builder, arg); + } + + // type specialization + static void serializeElem(GVariantBuilder* builder, int arg) + { + g_variant_builder_add_value(builder, g_variant_new_int32(arg)); + } + + static void serializeElem(GVariantBuilder* builder, unsigned arg) + { + g_variant_builder_add_value(builder, g_variant_new_uint32(arg)); + } + + static void serializeElem(GVariantBuilder* builder, bool arg) + { + g_variant_builder_add_value(builder, g_variant_new_boolean(arg)); + } + + static void serializeElem(GVariantBuilder* builder, float arg) + { + gdouble d = static_cast(arg); + g_variant_builder_add_value(builder, g_variant_new_double(d)); + } + + static void serializeElem(GVariantBuilder* builder, const char* arg) + { + g_variant_builder_add_value(builder, g_variant_new_string(arg)); + } + + static void serializeElem(GVariantBuilder* builder, + const std::string& arg) + { + g_variant_builder_add_value(builder, g_variant_new_string(arg.c_str())); + } +}; +} // namespace DBus +} // namespace DPL + +#endif // DPL_DBUS_DBUS_SERVER_SERIALIZATION_H_ diff --git a/modules/dbus/include/dpl/dbus/dbus_signature.h b/modules/dbus/include/dpl/dbus/dbus_signature.h new file mode 100644 index 0000000..bc99108 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dbus_signature.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dbus_deserialization.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief Header file for DBus data signatures + */ + +#ifndef DPL_DBUS_SIGNATURE_H +#define DPL_DBUS_SIGNATURE_H + +#include +#include + +namespace DPL { +namespace DBus { +template +struct SimpleType; + +template +struct Signature +{ + static inline const char* value() + { + static const char signature[] = + { (char) SimpleType::value, 0 }; + return signature; + } +}; + +// signed integer types +template +struct __SignedIntegerType; + +template<> +struct __SignedIntegerType<1> +{ + static const int value = DBUS_TYPE_INT16; +}; + +template<> +struct __SignedIntegerType<2> +{ + static const int value = DBUS_TYPE_INT16; +}; + +template<> +struct __SignedIntegerType<4> +{ + static const int value = DBUS_TYPE_INT32; +}; + +template<> +struct __SignedIntegerType<8> +{ + static const int value = DBUS_TYPE_INT64; +}; + +// unsigned integer types +template +struct __UnsignedIntegerType; + +template<> +struct __UnsignedIntegerType<1> +{ + static const int value = DBUS_TYPE_BYTE; +}; +template<> +struct __UnsignedIntegerType<2> +{ + static const int value = DBUS_TYPE_UINT16; +}; +template<> +struct __UnsignedIntegerType<4> +{ + static const int value = DBUS_TYPE_UINT32; +}; +template<> +struct __UnsignedIntegerType<8> +{ + static const int value = DBUS_TYPE_UINT64; +}; + +// basic types +template<> +struct SimpleType +{ + static const int value = DBUS_TYPE_BOOLEAN; +}; + +template<> +struct SimpleType +{ + static const int value = __UnsignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = __SignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = + __UnsignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = __SignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = + __UnsignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = __SignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = + __UnsignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = __SignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = + __UnsignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = __SignedIntegerType::value; +}; + +template<> +struct SimpleType +{ + static const int value = __UnsignedIntegerType< + sizeof(unsigned long long)>::value; +}; + +template<> +struct SimpleType +{ + static const int value = DBUS_TYPE_DOUBLE; +}; + +template<> +struct SimpleType +{ + static const int value = DBUS_TYPE_DOUBLE; +}; + +template<> +struct SimpleType +{ + static const int value = DBUS_TYPE_STRING; +}; + +template<> +struct SimpleType +{ + static const int value = DBUS_TYPE_STRING; +}; + +template<> +struct SimpleType +{ + static const int value = DBUS_TYPE_STRING; +}; + +// STL containers signatures + +// generic array +template +struct ArraySignature +{ + static inline const char* value() + { + static const std::string signature = std::string( + DBUS_TYPE_ARRAY_AS_STRING) + Signature::value(); + return signature.c_str(); + } +}; + +// std::vector +template +struct Signature > : public ArraySignature +{}; + +// std::list +template +struct Signature > : public ArraySignature +{}; + +// std::set +template +struct Signature > : public ArraySignature +{}; + +// std::pair +template +struct Signature > +{ + static inline const char* value() + { + static const std::string signature = std::string( + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING) + + Signature::value() + Signature::value() + + DBUS_DICT_ENTRY_END_CHAR_AS_STRING; + return signature.c_str(); + } +}; + +// std::map +template +struct Signature > : public ArraySignature > +{}; +} // namespace DBus +} // namespace DPL + +#endif // DPL_DBUS_SIGNATURE_H diff --git a/modules/dbus/include/dpl/dbus/dispatcher.h b/modules/dbus/include/dpl/dbus/dispatcher.h new file mode 100644 index 0000000..93e62e6 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/dispatcher.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file dispatcher.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_DISPATCHER_H +#define DPL_DBUS_DISPATCHER_H + +#include + +namespace DPL { +namespace DBus { +class Dispatcher +{ + public: + virtual ~Dispatcher() = 0; + + /** + * Called on method invocation. + * + * @param connection + * @param sender + * @param objectPath + * @param interfaceName + * @param methodName + * @param parameters + * @param invocation + * + * @see GLib DBus documentation. + */ + virtual void onMethodCall(GDBusConnection* connection, + const gchar* sender, + const gchar* objectPath, + const gchar* interfaceName, + const gchar* methodName, + GVariant* parameters, + GDBusMethodInvocation* invocation) = 0; + + /** + * Called on property get. + * + * @param connection + * @param sender + * @param objectPath + * @param interfaceName + * @param propertyName + * @return Porperty value. + * + * @see GLib DBus documentation. + */ + virtual GVariant* onPropertyGet(GDBusConnection* connection, + const gchar* sender, + const gchar* objectPath, + const gchar* interfaceName, + const gchar* propertyName, + GError** error); + + /** + * Called on property set. + * + * @param connection + * @param sender + * @param objectPath + * @param interfaceName + * @param propertyName + * @param value + * @return TRUE if successfully set, FALSE otherwise. + * + * @see GLib DBus documentation. + */ + virtual gboolean onPropertySet(GDBusConnection* connection, + const gchar* sender, + const gchar* objectPath, + const gchar* interfaceName, + const gchar* propertyName, + GVariant* value, + GError** error); +}; +} +} + +#endif // DPL_DBUS_DISPATCHER_H diff --git a/modules/dbus/include/dpl/dbus/exception.h b/modules/dbus/include/dpl/dbus/exception.h new file mode 100644 index 0000000..035d16f --- /dev/null +++ b/modules/dbus/include/dpl/dbus/exception.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file exception.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_EXCEPTION_H +#define DPL_DBUS_EXCEPTION_H + +#include + +namespace DPL { +namespace DBus { +/** + * Thrown when none of the following, more specific exception fit. + */ +DECLARE_EXCEPTION_TYPE(DPL::Exception, Exception) + +/** + * Thrown when trying to perform an operation on a closed connection. + */ +DECLARE_EXCEPTION_TYPE(DBus::Exception, ConnectionClosedException) + +/** + * Thrown when passing invalid argument(s). + */ +DECLARE_EXCEPTION_TYPE(DBus::Exception, InvalidArgumentException) +} +} + +#endif diff --git a/modules/dbus/include/dpl/dbus/glib_util.h b/modules/dbus/include/dpl/dbus/glib_util.h new file mode 100644 index 0000000..13206e3 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/glib_util.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file glib_util.h + * @author Iwanek Tomasz (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the definitions of loop controlling utilities + */ +#ifndef GLIB_UTIL_H +#define GLIB_UTIL_H + +//this header wraps glib headers which generates warnings + +#pragma GCC system_header +#include + +#endif // GLIB_UTIL_H diff --git a/modules/dbus/include/dpl/dbus/interface.h b/modules/dbus/include/dpl/dbus/interface.h new file mode 100644 index 0000000..6248dab --- /dev/null +++ b/modules/dbus/include/dpl/dbus/interface.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file interface.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_INTERFACE_H +#define DPL_DBUS_INTERFACE_H + +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +class Interface; +typedef std::shared_ptr InterfacePtr; + +class Interface : private DPL::Noncopyable +{ + public: + /** + * Parses supplied XML string to produce DBus interface descriptions. + * + * @param xmlString XML string to parse. + * @return Interfaces. + * @throw DPL::DBus::Exception If error while parsing occurs. + */ + static std::vector fromXMLString( + const std::string& xmlString); + + public: + ~Interface(); + + /** + * Gets pointers to functions called on method call or property get/set + * request. + * + * @return Pointers to functions. + */ + const GDBusInterfaceVTable* getVTable() const; + + /** + * Gets interface description. + * + * @return Interface description. + */ + GDBusInterfaceInfo* getInfo() const; + + /** + * Sets method/property dispatcher for the interface. + * + * @param dispatcher Method call and property get/set dispatcher. + */ + void setDispatcher(Dispatcher* dispatcher); + + private: + static void onMethodCallFunc(GDBusConnection *connection, + const gchar *sender, + const gchar *objectPath, + const gchar *interfaceName, + const gchar *methodName, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer data); + + static GVariant* onPropertyGetFunc(GDBusConnection *connection, + const gchar *sender, + const gchar *objectPath, + const gchar *interfaceName, + const gchar *propertyName, + GError **error, + gpointer data); + + static gboolean onPropertySetFunc(GDBusConnection *connection, + const gchar *sender, + const gchar *objectPath, + const gchar *interfaceName, + const gchar *propertyName, + GVariant *value, + GError **error, + gpointer data); + + explicit Interface(GDBusInterfaceInfo* info); + + static const GDBusInterfaceVTable m_vTable; + + GDBusInterfaceInfo* m_info; + + Dispatcher* m_dispatcher; +}; +} +} + +#endif // DPL_DBUS_INTERFACE_H diff --git a/modules/dbus/include/dpl/dbus/method_proxy.h b/modules/dbus/include/dpl/dbus/method_proxy.h new file mode 100644 index 0000000..19c3b90 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/method_proxy.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file method_proxy.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_METHOD_PROXY_H +#define DPL_DBUS_METHOD_PROXY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +class ObjectProxy; + +/** + * Represents a remote method. + */ +template +class MethodProxy +{ + public: + ~MethodProxy() + { + g_object_unref(m_connection); + } + + /** + * Invokes remote method. + * + * @param args Input arguments for remote method. + * @return Value returned by remote method. + * @throw DBus::InvalidArgumentException If invalid argument(s) supplied. + * @throw DBus::ConnectionClosedException If connection is closed. + * @throw DBus::Exception If some other error occurs. + */ + Result operator()(const Args& ... args) + { + return invoke(args ...); + } + + private: + friend class ObjectProxy; + + MethodProxy(GDBusConnection* connection, + const std::string& serviceName, + const std::string& objectPath, + const std::string& interfaceName, + const std::string& methodName) : + m_connection(connection), + m_serviceName(serviceName), + m_objectPath(objectPath), + m_interfaceName(interfaceName), + m_methodName(methodName) + { + Assert(m_connection && "Connection is not set."); + + g_object_ref(m_connection); + } + + /** + * @remarks Making it a template with parameter set by default to class + * template parameter to overload on return type by utilizing + * the SFINAE concept. + */ + template + typename std::enable_if::value, R>::type + invoke(const Args& ... args) + { + GVariant* parameters = serialize(args ...); + + GVariant* invokeResult = invokeSync(parameters); + + R result; + + ServerDeserialization::deserialize(invokeResult, &result); + + g_variant_unref(invokeResult); + + return result; + } + + /** + * @remarks Void return type overload. + */ + template + typename std::enable_if::value>::type + invoke(const Args& ... args) + { + GVariant* parameters = serialize(args ...); + + GVariant* invokeResult = invokeSync(parameters); + + g_variant_unref(invokeResult); + } + + /** + * @remarks ArgsM... are the same as Args...; it has been made a template + * to make overloading/specialization possible. + */ + template + GVariant* serialize(ArgsM && ... args) + { + return ServerSerialization::serialize(std::forward(args) ...); + } + + /** + * @remarks Specialization for zero-argument functions. + */ + GVariant* serialize() + { + return NULL; + } + + /** + * Calls remote method over DBus. + * + * @param parameters Input parameters for the remote method. + * @return Result returned by the remote method. + * @throw DBus::InvalidArgumentException If invalid argument(s) supplied. + * @throw DBus::ConnectionClosedException If connection is closed. + * @throw DBus::Exception If some other error occurs. + */ + GVariant* invokeSync(GVariant* parameters) + { + GError* error = NULL; + + LogPedantic( + "Invoking method: " << m_interfaceName << "." << m_methodName); + GVariant* result = g_dbus_connection_call_sync(m_connection, + m_serviceName.c_str(), + m_objectPath.c_str(), + m_interfaceName.c_str(), + m_methodName.c_str(), + parameters, + G_VARIANT_TYPE_TUPLE, + G_DBUS_CALL_FLAGS_NONE, + DBUS_SYNC_CALL_TIMEOUT, + NULL, + &error); + if (NULL == result) { + std::ostringstream oss; + oss << "Error while invoking: " + << m_interfaceName << "." << m_methodName + << " <" << error->message << ">"; + std::string message = oss.str(); + + gint code = error->code; + + g_error_free(error); + + switch (code) { + case G_IO_ERROR_INVALID_ARGUMENT: + ThrowMsg(DBus::InvalidArgumentException, message); + case G_IO_ERROR_CLOSED: + ThrowMsg(DBus::ConnectionClosedException, message); + default: + ThrowMsg(DBus::Exception, message); + } + } + + return result; + } + + /** + * Default timeout for synchronous method call. + * + * @see GIO::GDBusConnection::g_dbus_connection_call_sync() for details. + */ + static const gint DBUS_SYNC_CALL_TIMEOUT = -1; + + GDBusConnection* m_connection; + std::string m_serviceName; + std::string m_objectPath; + std::string m_interfaceName; + std::string m_methodName; +}; + +/** + * Smart pointer for MethodProxy objects. + */ +template +class MethodProxyPtr +{ + public: + explicit MethodProxyPtr(MethodProxy* method = NULL) : + m_method(method) + {} + + Result operator()(const Args& ... args) const + { + Assert(NULL != m_method.get() && "Method not set."); + + return (*m_method)(args ...); + } + + private: + std::shared_ptr > m_method; +}; +} +} + +#endif diff --git a/modules/dbus/include/dpl/dbus/object.h b/modules/dbus/include/dpl/dbus/object.h new file mode 100644 index 0000000..191464c --- /dev/null +++ b/modules/dbus/include/dpl/dbus/object.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file object.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_OBJECT_H +#define DPL_DBUS_OBJECT_H + +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +class Object; +typedef std::shared_ptr ObjectPtr; + +class Object +{ + public: + /** + * Creates an object. + * + * @param path Object's path. + * @param interface Interface the object supports. + * @return Object shared pointer. + */ + static ObjectPtr create(const std::string& path, + const InterfacePtr& interface); + + /** + * Gets object's path. + * + * @return Object's path. + */ + std::string getPath() const; + + /** + * Gets object's interface. + * + * @return Object's interface. + */ + InterfacePtr getInterface() const; + + private: + Object(const std::string& path, const InterfacePtr& interface); + + std::string m_path; + InterfacePtr m_interface; +}; +} +} + +#endif // WRT_SRC_DBUS_OBJECT_H diff --git a/modules/dbus/include/dpl/dbus/object_proxy.h b/modules/dbus/include/dpl/dbus/object_proxy.h new file mode 100644 index 0000000..17764f1 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/object_proxy.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file object_proxy.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_OBJECT_PROXY_H +#define DPL_DBUS_OBJECT_PROXY_H + +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +class Connection; + +/** + * Represents a remote object attached to a DBus service. + */ +class ObjectProxy +{ + public: + ~ObjectProxy(); + + /** + * Creates method proxy object. + * + * The object is used to call remote methods. + * + * @param interface Name of the DBus interface. + * @param name Name of the method to call. + * @return Proxy to remote method. + * @throw DBus::ConnectionClosedException If connection is closed. + */ + template + MethodProxyPtr createMethodProxy( + const std::string& interface, + const std::string& name) + { + if (g_dbus_connection_is_closed(m_connection)) { + ThrowMsg(DBus::ConnectionClosedException, "Connection closed."); + } + + return MethodProxyPtr( + new MethodProxy(m_connection, + m_serviceName, + m_objectPath, + interface, + name)); + } + + private: + friend class Connection; + + ObjectProxy(GDBusConnection* connection, + const std::string& serviceName, + const std::string& objectPath); + + GDBusConnection* m_connection; + std::string m_serviceName; + std::string m_objectPath; +}; +} +} + +#endif diff --git a/modules/dbus/include/dpl/dbus/server.h b/modules/dbus/include/dpl/dbus/server.h new file mode 100644 index 0000000..795a757 --- /dev/null +++ b/modules/dbus/include/dpl/dbus/server.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file server.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_DBUS_SERVER_H +#define DPL_DBUS_SERVER_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +namespace ServerEvents { +/** + * Emitted when new connection is accepted. + * + * Arg0 Accepted connection. + * + * @remarks If this event is processed on separate thread than that thread + * should run GLib main loop if one wants to e.g. register DBus + * objects during this event processing. + */ +DECLARE_GENERIC_EVENT_1(NewConnectionEvent, ConnectionPtr) +} + +class Server; +typedef std::shared_ptr ServerPtr; + +/** + * Class acting as a server for peer to peer connections over DBus. + */ +class Server : public DPL::Event::EventSupport +{ + public: + /** + * Creates server. + * + * @param address Address the server should listen on. + * @return Server. + */ + static ServerPtr create(const std::string& address); + + ~Server(); + + /** + * Starts the server. + */ + void start(); + + /** + * Stops the server. + */ + void stop(); + + protected: + explicit Server(GDBusServer* server); + + private: + static gboolean onNewConnection(GDBusServer* server, + GDBusConnection* connection, + gpointer data); + + GDBusServer* m_server; +}; +} +} + +#endif // DPL_DBUS_SERVER_H diff --git a/modules/dbus/src/connection.cpp b/modules/dbus/src/connection.cpp new file mode 100644 index 0000000..9c3b6ba --- /dev/null +++ b/modules/dbus/src/connection.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file connection.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +ConnectionPtr Connection::sessionBus() +{ + return connectTo(G_BUS_TYPE_SESSION); +} + +ConnectionPtr Connection::systemBus() +{ + return connectTo(G_BUS_TYPE_SYSTEM); +} + +ConnectionPtr Connection::connectTo(GBusType busType) +{ + GError* error = NULL; + + GDBusConnection* connection = g_bus_get_sync(busType, + NULL, + &error); + if (NULL == connection) { + std::string message; + if (NULL != error) { + message = error->message; + g_error_free(error); + } + ThrowMsg(DBus::Exception, + "Couldn't connect to bus: " << message); + } + + g_dbus_connection_set_exit_on_close(connection, FALSE); + + return ConnectionPtr(new Connection(connection)); +} + +ConnectionPtr Connection::connectTo(const std::string& address) +{ + GError* error = NULL; + + GDBusConnection* connection = g_dbus_connection_new_for_address_sync( + address.c_str(), + G_DBUS_CONNECTION_FLAGS_NONE, + NULL, + NULL, + &error); + if (NULL == connection) { + std::string message; + if (NULL != error) { + message = error->message; + g_error_free(error); + } + ThrowMsg(DBus::Exception, + "Couldn't connect to " << address << ": " << message); + } + + return ConnectionPtr(new Connection(connection)); +} + +Connection::Connection(GDBusConnection* connection) : + m_connection(connection) +{ + g_signal_connect(m_connection, + "closed", + G_CALLBACK(onConnectionClosed), + this); +} + +Connection::~Connection() +{ + std::for_each(m_registeredServices.begin(), + m_registeredServices.end(), + [] (const RegisteredServices::value_type & value) + { + g_bus_unown_name(value.second); + }); + + std::for_each(m_registeredObjects.begin(), + m_registeredObjects.end(), + [this] (const RegisteredObjects::value_type & value) + { + g_dbus_connection_unregister_object( + m_connection, + value.second.registrationId); + }); + + if (!g_dbus_connection_is_closed(m_connection)) { + GError* error = NULL; + + if (FALSE == + g_dbus_connection_flush_sync(m_connection, NULL, &error)) + { + LogPedantic("Could not flush the connection" + << " <" << error->message << ">"); + g_error_free(error); + } + } + + g_object_unref(m_connection); +} + +void Connection::registerService(const std::string& serviceName) +{ + guint regId = g_bus_own_name_on_connection(m_connection, + serviceName.c_str(), + G_BUS_NAME_OWNER_FLAGS_NONE, + onServiceNameAcquired, + onServiceNameLost, + this, + NULL); + if (0 >= regId) { + ThrowMsg(DBus::Exception, "Error while registering service."); + } + + m_registeredServices.insert(RegisteredServices::value_type(serviceName, + regId)); +} + +void Connection::unregisterService(const std::string& serviceName) +{ + auto it = m_registeredServices.find(serviceName); + if (m_registeredServices.end() == it) { + ThrowMsg(DBus::Exception, "Service not registered."); + } + + g_bus_unown_name(it->second); + + m_registeredServices.erase(it); +} + +void Connection::registerObject(const ObjectPtr& object) +{ + GError* error = NULL; + + guint regId = g_dbus_connection_register_object( + m_connection, + object->getPath().c_str(), + object->getInterface()->getInfo(), + object->getInterface()->getVTable(), + // TODO This is ugly, fix this! + object->getInterface().get(), + NULL, + &error); + if (0 == regId) { + std::string message; + if (NULL != error) { + message = error->message; + LogPedantic(error->message << " " << error->code); + g_error_free(error); + } + ThrowMsg(DBus::Exception, "Error while registering an object: " + << message); + } + + m_registeredObjects.insert(RegisteredObjects::value_type( + object->getPath(), + ObjectRegistration(regId, object))); +} + +void Connection::unregisterObject(const std::string& objectPath) +{ + auto it = m_registeredObjects.find(objectPath); + if (m_registeredObjects.end() == it) { + ThrowMsg(DBus::Exception, "Object not registered."); + } + + gboolean result = g_dbus_connection_unregister_object( + m_connection, + it->second.registrationId); + if (FALSE == result) { + ThrowMsg(DBus::Exception, "Unregistering object failed."); + } + m_registeredObjects.erase(it); +} + +ObjectProxyPtr Connection::createObjectProxy(const std::string& serviceName, + const std::string& objectPath) +{ + if (g_dbus_connection_is_closed(m_connection)) { + ThrowMsg(DBus::ConnectionClosedException, "Connection closed."); + } + + return ObjectProxyPtr( + new ObjectProxy(m_connection, serviceName, objectPath)); +} + +void Connection::onServiceNameAcquired(GDBusConnection* /*connection*/, + const gchar* serviceName, + gpointer data) +{ + AssertMsg(data, "Connection should not be NULL"); + + Connection* self = static_cast(data); + + LogPedantic("Emitting service name acquired event: " << serviceName); + + ConnectionEvents::ServiceNameAcquiredEvent event(serviceName); + self->DPL::Event::EventSupport + :: + EmitEvent(event, DPL::Event::EmitMode::Queued); +} + +void Connection::onServiceNameLost(GDBusConnection* /*connection*/, + const gchar* serviceName, + gpointer data) +{ + AssertMsg(data, "Connection should not be NULL"); + + Connection* self = static_cast(data); + + LogPedantic("Emitting service name lost event: " << serviceName); + + ConnectionEvents::ServiceNameLostEvent event(serviceName); + self->DPL::Event::EventSupport:: + EmitEvent(event, DPL::Event::EmitMode::Queued); +} + +void Connection::onConnectionClosed(GDBusConnection* /*connection*/, + gboolean peerVanished, + GError* error, + gpointer data) +{ + AssertMsg(NULL != data, "Connection cannot be NULL"); + + Connection* self = static_cast(data); + + if ((NULL == error) && (FALSE == peerVanished)) { + // Connection closed by this. + } else if (NULL != error) { + std::string message = error->message; + + g_error_free(error); + + if (TRUE == peerVanished) { + // Connection closed by remote host. + ConnectionEvents::ConnectionBrokenEvent event(message); + self->DPL::Event::EventSupport:: + EmitEvent(event, DPL::Event::EmitMode::Queued); + } else { + // Invalid or malformed data on connection. + ConnectionEvents::ConnectionInvalidEvent event(message); + self->DPL::Event::EventSupport:: + EmitEvent(event, DPL::Event::EmitMode::Queued); + } + } +} +} +} diff --git a/modules/dbus/src/dispatcher.cpp b/modules/dbus/src/dispatcher.cpp new file mode 100644 index 0000000..d83a22a --- /dev/null +++ b/modules/dbus/src/dispatcher.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file dispatcher.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ +#include +#include + +namespace DPL { +namespace DBus { +Dispatcher::~Dispatcher() { } + +GVariant* Dispatcher::onPropertyGet(GDBusConnection* /*connection*/, + const gchar* /*sender*/, + const gchar* /*objectPath*/, + const gchar* /*interfaceName*/, + const gchar* /*propertyName*/, + GError** /*error*/) +{ + return NULL; +} + +gboolean Dispatcher::onPropertySet(GDBusConnection* /*connection*/, + const gchar* /*sender*/, + const gchar* /*objectPath*/, + const gchar* /*interfaceName*/, + const gchar* /*propertyName*/, + GVariant* /*value*/, + GError** /*error*/) +{ + return false; +} +} +} diff --git a/modules/dbus/src/interface.cpp b/modules/dbus/src/interface.cpp new file mode 100644 index 0000000..b449e7c --- /dev/null +++ b/modules/dbus/src/interface.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file interface.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +const GDBusInterfaceVTable Interface::m_vTable = { + Interface::onMethodCallFunc, + Interface::onPropertyGetFunc, + Interface::onPropertySetFunc, + { 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +std::vector Interface::fromXMLString(const std::string& xmlString) +{ + GError* error = NULL; + + GDBusNodeInfo* nodeInfo = g_dbus_node_info_new_for_xml(xmlString.c_str(), + &error); + if (NULL == nodeInfo) { + std::string message; + if (NULL != error) { + message = error->message; + g_error_free(error); + } + ThrowMsg(DPL::DBus::Exception, + "Error parsing node info <" << message << ">"); + } + + std::vector result; + + GDBusInterfaceInfo** interface = nodeInfo->interfaces; + while (NULL != *interface) { + result.push_back(InterfacePtr(new Interface(*interface))); + ++interface; + } + + g_dbus_node_info_unref(nodeInfo); + + return result; +} + +Interface::Interface(GDBusInterfaceInfo* info) : + m_info(info) +{ + g_dbus_interface_info_ref(m_info); +} + +Interface::~Interface() +{ + g_dbus_interface_info_unref(m_info); +} + +const GDBusInterfaceVTable* Interface::getVTable() const +{ + return &m_vTable; +} + +GDBusInterfaceInfo* Interface::getInfo() const +{ + return m_info; +} + +void Interface::setDispatcher(Dispatcher* dispatcher) +{ + m_dispatcher = dispatcher; +} + +void Interface::onMethodCallFunc(GDBusConnection *connection, + const gchar *sender, + const gchar *objectPath, + const gchar *interfaceName, + const gchar *methodName, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer data) +{ + AssertMsg(NULL != data, "Interface cannot be NULL."); + Interface* self = static_cast(data); + + // TODO Verify interface name. + + if (NULL != self->m_dispatcher) { + try { + self->m_dispatcher->onMethodCall(connection, + sender, + objectPath, + interfaceName, + methodName, + parameters, + invocation); + } catch (const DPL::Exception& /*ex*/) { + // TODO Support for errors. + } + } +} + +GVariant* Interface::onPropertyGetFunc(GDBusConnection *connection, + const gchar *sender, + const gchar *objectPath, + const gchar *interfaceName, + const gchar *propertyName, + GError **error, + gpointer data) +{ + AssertMsg(NULL != data, "Interface cannot be NULL."); + Interface* self = static_cast(data); + + // TODO Verify interface name. + + if (NULL != self->m_dispatcher) { + try { + // TODO Check if NULL is returned, if so set error variable. + return self->m_dispatcher->onPropertyGet(connection, + sender, + objectPath, + interfaceName, + propertyName, + error); + } catch (const DPL::Exception& /*ex*/) { + // TODO Support for errors. + } + } + + // TODO Set error. + + return NULL; +} + +gboolean Interface::onPropertySetFunc(GDBusConnection *connection, + const gchar *sender, + const gchar *objectPath, + const gchar *interfaceName, + const gchar *propertyName, + GVariant *value, + GError **error, + gpointer data) +{ + AssertMsg(NULL != data, "Interface cannot be NULL."); + Interface* self = static_cast(data); + + // TODO Verify interface name. + + if (NULL != self->m_dispatcher) { + try { + return self->m_dispatcher->onPropertySet(connection, + sender, + objectPath, + interfaceName, + propertyName, + value, + error); + } catch (const DPL::Exception& /*ex*/) { + // TODO Support for errors. + } + } + + // TODO Set error. + + return false; +} +} +} diff --git a/modules/dbus/src/object.cpp b/modules/dbus/src/object.cpp new file mode 100644 index 0000000..a66796d --- /dev/null +++ b/modules/dbus/src/object.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file object.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ +#include +#include + +namespace DPL { +namespace DBus { +ObjectPtr Object::create(const std::string& path, const InterfacePtr& interface) +{ + return ObjectPtr(new Object(path, interface)); +} + +std::string Object::getPath() const +{ + return m_path; +} + +InterfacePtr Object::getInterface() const +{ + return m_interface; +} + +Object::Object(const std::string& path, const InterfacePtr& interface) : + m_path(path), + m_interface(interface) +{} +} +} \ No newline at end of file diff --git a/modules/dbus/src/object_proxy.cpp b/modules/dbus/src/object_proxy.cpp new file mode 100644 index 0000000..9b15bb7 --- /dev/null +++ b/modules/dbus/src/object_proxy.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file object_proxy.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ +#include +#include + +namespace DPL { +namespace DBus { +ObjectProxy::ObjectProxy(GDBusConnection* connection, + const std::string& serviceName, + const std::string& objectPath) : + m_connection(connection), + m_serviceName(serviceName), + m_objectPath(objectPath) +{ + g_object_ref(m_connection); +} + +ObjectProxy::~ObjectProxy() +{ + g_object_unref(m_connection); +} +} +} \ No newline at end of file diff --git a/modules/dbus/src/server.cpp b/modules/dbus/src/server.cpp new file mode 100644 index 0000000..41c6962 --- /dev/null +++ b/modules/dbus/src/server.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file server.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief + */ +#include +#include +#include +#include + +namespace DPL { +namespace DBus { +ServerPtr Server::create(const std::string& address) +{ + GError* error = NULL; + + int flags = G_DBUS_SERVER_FLAGS_NONE | + G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS; + + gchar* serverId = g_dbus_generate_guid(); + + GDBusServer* server = g_dbus_server_new_sync( + address.c_str(), + static_cast(flags), + serverId, + NULL, + NULL, + &error); + g_free(serverId); + + if (NULL == server) { + std::string message; + if (NULL != error) { + message = error->message; + g_error_free(error); + } + + ThrowMsg(DPL::Exception, "Error on server creation: " << message); + } + + return ServerPtr(new Server(server)); +} + +Server::Server(GDBusServer* server) : + m_server(server) +{} + +Server::~Server() +{ + if (g_dbus_server_is_active(m_server)) { + stop(); + } + g_object_unref(m_server); +} + +void Server::start() +{ + AssertMsg(!g_dbus_server_is_active(m_server), "Server already started."); + + g_dbus_server_start(m_server); + + g_signal_connect(m_server, + "new-connection", + G_CALLBACK(onNewConnection), + this); + + LogDebug("Server started at: " + << g_dbus_server_get_client_address(m_server)); +} + +void Server::stop() +{ + AssertMsg(g_dbus_server_is_active(m_server), "Server not started."); + + g_dbus_server_stop(m_server); +} + +gboolean Server::onNewConnection(GDBusServer* /*server*/, + GDBusConnection* connection, + gpointer data) +{ + AssertMsg(NULL != data, "User data cannot be NULL."); + + Server* self = static_cast(data); + + ServerEvents::NewConnectionEvent event( + ConnectionPtr(new Connection(connection))); + + LogDebug("Emitting new connection event"); + // TODO Blocking to allow object registration before any DBus messages are + // processed. + self->DPL::Event::EventSupport:: + EmitEvent(event, DPL::Event::EmitMode::Blocking); + + return TRUE; +} +} +} diff --git a/modules/event/config.cmake b/modules/event/config.cmake new file mode 100644 index 0000000..313b6a8 --- /dev/null +++ b/modules/event/config.cmake @@ -0,0 +1,55 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_EVENT_SOURCES + ${PROJECT_SOURCE_DIR}/modules/event/src/abstract_event_call.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/abstract_event_dispatcher.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/controller.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/event_listener.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/event_support.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/generic_event_call.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/main_event_dispatcher.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/thread_event_dispatcher.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/inter_context_delegate.cpp + ${PROJECT_SOURCE_DIR}/modules/event/src/model.cpp + PARENT_SCOPE +) + +SET(DPL_EVENT_HEADERS + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/abstract_event_call.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/abstract_event_dispatcher.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/controller.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/event_listener.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/event_support.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/generic_event_call.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/main_event_dispatcher.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/thread_event_dispatcher.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/inter_context_delegate.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/model.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/property.h + ${PROJECT_SOURCE_DIR}/modules/event/include/dpl/event/model_bind_to_dao.h + PARENT_SCOPE +) + +SET(DPL_EVENT_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/event/include/ + PARENT_SCOPE +) diff --git a/modules/event/include/dpl/event/abstract_event_call.h b/modules/event/include/dpl/event/abstract_event_call.h new file mode 100644 index 0000000..db1bea4 --- /dev/null +++ b/modules/event/include/dpl/event/abstract_event_call.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_event_call.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract event call + */ +#ifndef DPL_ABSTRACT_EVENT_CALL_H +#define DPL_ABSTRACT_EVENT_CALL_H + +#include + +namespace DPL { +namespace Event { +class AbstractEventCall : + private Noncopyable +{ + public: + /** + * Constructor + */ + explicit AbstractEventCall(); + + /** + * Destructor + */ + virtual ~AbstractEventCall(); + + /** + * Call abstract event call + */ + virtual void Call() = 0; +}; +} +} // namespace DPL + +#endif // DPL_ABSTRACT_EVENT_CALL_H diff --git a/modules/event/include/dpl/event/abstract_event_dispatcher.h b/modules/event/include/dpl/event/abstract_event_dispatcher.h new file mode 100644 index 0000000..f5caa56 --- /dev/null +++ b/modules/event/include/dpl/event/abstract_event_dispatcher.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_event_dispatcher.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract event + * dispatcher + */ +#ifndef DPL_ABSTRACT_EVENT_DISPATCHER_H +#define DPL_ABSTRACT_EVENT_DISPATCHER_H + +#include +#include + +namespace DPL { +namespace Event { +class AbstractEventDispatcher : + private Noncopyable +{ + public: + /** + * Constructor + */ + explicit AbstractEventDispatcher(); + + /** + * Destructor + */ + virtual ~AbstractEventDispatcher(); + + /** + * Add abstract event call to abstract event dispatcher + * + * @param[in] abstractEventCall Pointer to abstract event call to add + * @return none + */ + virtual void AddEventCall(AbstractEventCall *abstractEventCall) = 0; + + /** + * Add abstract timed event call to abstract event dispatcher + * + * @param[in] abstractEventCall Pointer to abstract event call to add + * @param[in] dueTime Due time for timed event in seconds + * @return none + */ + virtual void AddTimedEventCall(AbstractEventCall *abstractEventCall, + double dueTime) = 0; +}; +} +} // namespace DPL + +#endif // DPL_ABSTRACT_EVENT_DISPATCHER_H diff --git a/modules/event/include/dpl/event/controller.h b/modules/event/include/dpl/event/controller.h new file mode 100644 index 0000000..1b14632 --- /dev/null +++ b/modules/event/include/dpl/event/controller.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file controller.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC controller + */ +#ifndef DPL_CONTROLLER_H +#define DPL_CONTROLLER_H + +#include +#include +#include +#include +#include + +namespace DPL { +namespace Event { +template +class ControllerEventHandler : + public EventListener, + private EventSupport +{ + private: + bool m_touched; + + public: + ControllerEventHandler() : + m_touched(false) + { + EventSupport::AddListener(this); + } + + virtual ~ControllerEventHandler() + { + EventSupport::RemoveListener(this); + } + + void PostEvent(const EventType &event) + { + Assert( + m_touched && + "Default context not inherited. Call Touch() to inherit one."); + EventSupport::EmitEvent(event, EmitMode::Queued); + } + + void PostTimedEvent(const EventType &event, double dueTime) + { + Assert( + m_touched && + "Default context not inherited. Call Touch() to inherit one."); + EventSupport::EmitEvent(event, EmitMode::Deffered, dueTime); + } + + void PostSyncEvent(const EventType &event) + { + Assert( + m_touched && + "Default context not inherited. Call Touch() to inherit one."); + + // Check calling context + EventSupport::EmitEvent(event, EmitMode::Blocking); + } + + void SwitchToThread(Thread *thread) + { + Assert( + m_touched && + "Default context not inherited. Call Touch() to inherit one."); + EventSupport::SwitchListenerToThread(this, thread); + } + + void Touch() + { + m_touched = true; + EventSupport::SwitchListenerToThread( + this, + Thread:: + GetCurrentThread()); + } +}; + +template +class Controller : + public Controller, + public ControllerEventHandler +{ + public: + typedef typename EventTypeList::Head EventType; + + public: + Controller() + {} + + virtual ~Controller() + {} + + virtual void SwitchToThread(Thread *thread) + { + ControllerEventHandler::SwitchToThread(thread); + Controller::SwitchToThread(thread); + } + + virtual void Touch() + { + ControllerEventHandler::Touch(); + Controller::Touch(); + } +}; + +template<> +class Controller::Type> +{ + public: + Controller() + {} + + virtual ~Controller() + {} + + virtual void SwitchToThread(Thread *thread) + { + (void)thread; + } + + virtual void Touch() + {} +}; +} +} // namespace DPL + +// Utilities +#define CONTROLLER_POST_EVENT(Name, \ + EventArg) Name##Singleton::Instance().DPL::Event \ + ::ControllerEventHandler< \ + __typeof__ EventArg>::PostEvent(EventArg) +#define CONTROLLER_POST_TIMED_EVENT(Name, EventArg, \ + DueTime) Name##Singleton::Instance().DPL:: \ + Event::ControllerEventHandler< \ + __typeof__ EventArg>::PostTimedEvent(EventArg, DueTime) +#define CONTROLLER_POST_SYNC_EVENT(Name, \ + EventArg) Name##Singleton::Instance().DPL:: \ + Event::ControllerEventHandler< \ + __typeof__ EventArg>::PostSyncEvent(EventArg) + +#endif // DPL_CONTROLLER_H diff --git a/modules/event/include/dpl/event/event_listener.h b/modules/event/include/dpl/event/event_listener.h new file mode 100644 index 0000000..27fdbec --- /dev/null +++ b/modules/event/include/dpl/event/event_listener.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file event_listener.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC event listener + */ +#ifndef DPL_EVENT_LISTENER_H +#define DPL_EVENT_LISTENER_H + +#include + +namespace DPL { +namespace Event { +template +class EventListener : + private Noncopyable +{ + public: + EventListener() + {} + + virtual ~EventListener() + {} + + virtual void OnEventReceived(const EventType &event) = 0; +}; +} +} // namespace DPL + +#endif // DPL_EVENT_LISTENER_H diff --git a/modules/event/include/dpl/event/event_support.h b/modules/event/include/dpl/event/event_support.h new file mode 100644 index 0000000..e7fcaef --- /dev/null +++ b/modules/event/include/dpl/event/event_support.h @@ -0,0 +1,721 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file event_support.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC event support + */ +#ifndef DPL_EVENT_SUPPORT_H +#define DPL_EVENT_SUPPORT_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Event { +namespace EmitMode { +enum Type +{ + Auto, ///< If calling thread is the same as receiver's use + ///< direct call, otherwise call is queued + + Queued, ///< Call is always queued + + Blocking, ///< If calling thread is the same as receiver's use + ///< direct call, otherwise call is queued and blocking + + Deffered ///< Call is always queued for a period of time +}; +} // namespace EmitMode + +template +class EventSupport : + private Noncopyable +{ + public: + typedef EventSupport EventSupportType; + + typedef EventListener EventListenerType; + + typedef void DelegateSignature(const EventType&); + typedef std::function DelegateType; + + class EventSupportData; // Forward declaration + typedef EventSupportData *EventSupportDataPtr; + + private: + typedef typename GenericEventCall:: + template Rebind:: + Other GenericEventCallType; + + // Event listener list + typedef std::map EventListenerList; + EventListenerList m_eventListenerList; + + struct DelegateCompare + { + typedef typename std::add_pointer::type + DelegateSignaturePtr; + + bool operator()(const DelegateType& a, const DelegateType& b) const + { + return comparer(a.template target(), + b.template target()); + } + + const std::less comparer; + }; + + // Delegate list + typedef std::map DelegateList; + DelegateList m_delegateList; + + // Event support operation mutex + Mutex m_listenerDelegateMutex; + + // Dedicated instance of thread event dispatcher + ThreadEventDispatcher m_threadEventDispatcher; + + // Guard destruction of event support in event handler + Atomic m_guardedCallInProgress; + + // Events created by this support + typedef std::list EventCallList; + EventCallList m_eventsList; + + // Events list mutex + Mutex m_eventListMutex; + + public: + class EventSupportData + { + private: + typedef void (EventSupportType::*ReceiveAbstractEventCallMethod)( + const EventType &event, + EventListenerType *eventListener, + DelegateType delegate, + WaitableEvent *synchronization); + + EventSupportType *m_eventSupport; + ReceiveAbstractEventCallMethod m_method; + typename EventCallList::iterator m_iterator; + + //TODO: Add dispatcher iterator to remove events from + // framework/thread's event queue + WaitableEvent *m_synchronization; + + Mutex m_dataMutex; + + public: + EventSupportData(EventSupportType *support, + ReceiveAbstractEventCallMethod method, + WaitableEvent *synchronization) : + m_eventSupport(support), + m_method(method), + m_synchronization(synchronization) + {} + + ~EventSupportData() + { + Mutex::ScopedLock lock(&m_dataMutex); + + if (!m_eventSupport) { + LogPedantic("EventSupport for this call does not exist"); + return; + } + + m_eventSupport->RemoveEventCall(m_iterator); + } + + // TODO: Make private and make EventSupport friend + void SetIterator(typename EventCallList::iterator iter) + { + m_iterator = iter; + } + + // This method at the end destroys this as it will not be used anymore + void CallAndDestroy(const EventType &event, + EventListenerType *listener, + DelegateType delegate) + { + { + Mutex::ScopedLock lock(&m_dataMutex); + + if (m_eventSupport != NULL) { + (*m_eventSupport.*m_method)(event, + listener, + delegate, + m_synchronization); + } else { + LogPedantic("EventSupport for this call does not " + "exist anymore. Ignored."); + } + + // releasing mutex lock + } + + // EventSupportData object is no more used. + // It can be safely destroyed now. + delete this; + } + + void Reset() + { + Mutex::ScopedLock lock(&m_dataMutex); + m_eventSupport = NULL; + } + }; + + private: + GenericEventCallType *RegisterEventCall(const EventType &event, + EventListenerType *eventListener, + DelegateType delegate, + WaitableEvent *waitableEvent) + { + Mutex::ScopedLock lock(&m_eventListMutex); + + EventSupportDataPtr supportData = + new EventSupportData( + this, + &EventSupportType::ReceiveAbstractEventCall, + waitableEvent); + + GenericEventCallType *eventCall = + new GenericEventCallType(supportData, eventListener, + delegate, event); + + typename EventCallList::iterator eventCallIter = + m_eventsList.insert(m_eventsList.end(), eventCall); + + supportData->SetIterator(eventCallIter); + + return eventCall; + } + + void RemoveEventCall(typename EventCallList::iterator eventIterator) + { + Mutex::ScopedLock lock(&m_eventListMutex); + + m_eventsList.erase(eventIterator); + } + + // Note: Reentrant metod + void GuardedEventCall(const EventType &event, + EventListenerType *eventListener) + { + ++m_guardedCallInProgress; + + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + eventListener->OnEventReceived(event); + } + UNHANDLED_EXCEPTION_HANDLER_END + + -- m_guardedCallInProgress; + } + + // Note: Reentrant metod + void GuardedEventCall(const EventType &event, + DelegateType delegate) + { + ++m_guardedCallInProgress; + + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + delegate(event); + } + UNHANDLED_EXCEPTION_HANDLER_END + + -- m_guardedCallInProgress; + } + + void ReceiveAbstractEventCall(const EventType &event, + EventListenerType *eventListener, + DelegateType delegate, + WaitableEvent *synchronization) + { + Thread *targetThread; + + // Listener might have been removed, ensure that it still exits + if (eventListener != NULL) { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + typename EventListenerList::iterator iterator = + m_eventListenerList.find(eventListener); + + if (iterator == m_eventListenerList.end()) { + LogPedantic("Abstract event call listener disappeared." + "Event ignored."); + + // Even though, synchronize caller if needed + if (synchronization != NULL) { + synchronization->Signal(); + } + + return; + } + + // Get target thread id + targetThread = iterator->second; + } else { + // Delegate might have been removed, ensure that it still exits + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + typename DelegateList::iterator iterator = + m_delegateList.find(delegate); + + if (iterator == m_delegateList.end()) { + LogPedantic("Abstract event call delegate disappeared." + "Event ignored."); + + // Even though, synchronize caller if needed + if (synchronization != NULL) { + synchronization->Signal(); + } + + return; + } + + // Get target thread id + targetThread = iterator->second; + } + + // Ensure that we are now in proper thread now + if (targetThread != Thread::GetCurrentThread()) { + LogPedantic("Detected event dispatching ping-pong scenario"); + + // Retry if it was not synchronized + if (synchronization == NULL) { + // Cheat with event delivery + EmitEvent(event, EmitMode::Queued); + + LogPedantic("Ping-Pong: Resent as queued event"); + } else { + // There is a problem + // Developer did something nasty, and we will not clean up his + // mess + synchronization->Signal(); + + LogPedantic("### Ping-Pong: Failed to deliver synchronized" + "event in ping-pong scenario!"); + } + + return; + } + + // Guard listener code for exceptions + if (eventListener != NULL) { + GuardedEventCall(event, eventListener); + } else { + GuardedEventCall(event, delegate); + } + + // Release caller if synchronizing + if (synchronization != NULL) { + synchronization->Signal(); + } + } + + protected: + void EmitEvent(const EventType &event, + EmitMode::Type mode = EmitMode::Queued, + double dueTime = 0.0) + { + // Emit event, and retrieve later in current context to dispatch + std::unique_ptr lock( + new Mutex::ScopedLock(&m_listenerDelegateMutex)); + + // Show some info + switch (mode) { + case EmitMode::Auto: + break; + + case EmitMode::Queued: + break; + + case EmitMode::Blocking: + break; + + case EmitMode::Deffered: + break; + + default: + break; + } + + // In some configurations there is a barrier + std::vector synchronizationBarrier; + + // Emit to all listeners + FOREACH(iterator, m_eventListenerList) + { + // Switch to proper dispatcher and emit event + AbstractEventDispatcher *dispatcher = NULL; + + if (iterator->second == NULL) { + // Send to main thread + dispatcher = &GetMainEventDispatcherInstance(); + } else { + // Setup thread dispatcher, and send to proper thread + m_threadEventDispatcher.SetThread(iterator->second); + dispatcher = &m_threadEventDispatcher; + } + + // Dispatch event to abstract dispatcher + WaitableEvent *synchronization; + + // TODO: Pool synchronization objects + switch (mode) { + case EmitMode::Auto: + // Check thread + if (iterator->second == Thread::GetCurrentThread()) { + // Guard listener code for exceptions + GuardedEventCall(event, iterator->first); + } else { + // Handle non-synchronized event + dispatcher->AddEventCall( + RegisterEventCall(event, iterator->first, + DelegateType(), NULL)); + } + break; + + case EmitMode::Queued: + // Handle non-synchronized event + dispatcher->AddEventCall( + RegisterEventCall(event, iterator->first, + DelegateType(), NULL)); + + break; + + case EmitMode::Blocking: + // Check thread + if (iterator->second == Thread::GetCurrentThread()) { + // Guard listener code for exceptions + GuardedEventCall(event, iterator->first); + } else { + // New synchronization object is needed + synchronization = new WaitableEvent(); + + // Handle synchronized event + dispatcher->AddEventCall( + RegisterEventCall(event, iterator->first, + DelegateType(), synchronization)); + + // Add to barrier + synchronizationBarrier.push_back(synchronization); + } + break; + + case EmitMode::Deffered: + // Handle deffered events + Assert(dueTime >= 0.0 && "Due time must be non-negative"); + + dispatcher->AddTimedEventCall( + RegisterEventCall(event, iterator->first, + DelegateType(), NULL), dueTime); + + break; + + default: + Assert("Invalid emit mode"); + } + } + + // Emit to all delegates + FOREACH(iterator, m_delegateList) + { + // Switch to proper dispatcher and emit event + AbstractEventDispatcher *dispatcher = NULL; + + if (iterator->second == NULL) { + // Send to main thread + dispatcher = &GetMainEventDispatcherInstance(); + } else { + // Setup thread dispatcher, and send to proper thread + m_threadEventDispatcher.SetThread(iterator->second); + dispatcher = &m_threadEventDispatcher; + } + + // Dispatch event to abstract dispatcher + WaitableEvent *synchronization; + + // TODO: Pool synchronization objects + switch (mode) { + case EmitMode::Auto: + // Check thread + if (iterator->second == Thread::GetCurrentThread()) { + // Guard listener code for exceptions + GuardedEventCall(event, iterator->first); + } else { + // Handle non-synchronized event + dispatcher->AddEventCall( + RegisterEventCall(event, + NULL, + iterator->first, + NULL)); + } + break; + + case EmitMode::Queued: + // Handle non-synchronized event + dispatcher->AddEventCall( + RegisterEventCall(event, + NULL, + iterator->first, + NULL)); + + break; + + case EmitMode::Blocking: + // Check thread + if (iterator->second == Thread::GetCurrentThread()) { + // Guard listener code for exceptions + GuardedEventCall(event, iterator->first); + } else { + // New synchronization object is needed + synchronization = new WaitableEvent(); + + // Handle synchronized event + dispatcher->AddEventCall( + RegisterEventCall(event, + NULL, + iterator->first, + synchronization)); + + // Add to barrier + synchronizationBarrier.push_back(synchronization); + } + break; + + case EmitMode::Deffered: + // Handle deffered events + Assert(dueTime >= 0.0 && "Due time must be non-negative"); + + dispatcher->AddTimedEventCall( + RegisterEventCall(event, + NULL, + iterator->first, + NULL), dueTime); + + break; + + default: + Assert("Invalid emit mode"); + } + } + + // Leave listeners lock in case of blocking call + if (!synchronizationBarrier.empty()) { + LogPedantic("Leaving lock due to existing barrier"); + lock.reset(); + } + + // Synchronize with barrier + // TODO: Implement generic WaitForAllMultipleHandles call + while (!synchronizationBarrier.empty()) { + // Get barrier waitable handles + WaitableHandleList barrierHandles; + + FOREACH(iterator, synchronizationBarrier) + barrierHandles.push_back((*iterator)->GetHandle()); + + // Await more events + WaitableHandleIndexList indexList = + WaitForMultipleHandles(barrierHandles); + + // Remove all awaited handles + // TODO: Return handles to pool + FOREACH(iterator, indexList) + { + // Delete object + delete synchronizationBarrier[*iterator]; + + // Zero out place + synchronizationBarrier[*iterator] = NULL; + } + + // Now clean up + std::vector clearedSynchronizationBarrier; + + FOREACH(iterator, synchronizationBarrier) + { + if (*iterator == NULL) { + continue; + } + + clearedSynchronizationBarrier.push_back(*iterator); + } + + synchronizationBarrier.swap(clearedSynchronizationBarrier); + } + } + + public: + EventSupport() : + m_guardedCallInProgress(false) + {} + + virtual ~EventSupport() + { + if( m_guardedCallInProgress != 0 ){ + LogError("The object will terminate, but guardCall is in progress, it could cause segmentation fault"); + } + + m_eventListenerList.clear(); + m_delegateList.clear(); + + Mutex::ScopedLock lock(&m_eventListMutex); + + FOREACH(iterator, m_eventsList) + (*iterator)->DisableEvent(); + } + + void AddListener(EventListenerType *eventListener) + { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + // Listener must not be NULL + Assert(eventListener != NULL); + + // Listener must not already exists + Assert(m_eventListenerList.find(eventListener) + == m_eventListenerList.end()); + + // Add new listener, inherit dispatcher from current context + m_eventListenerList.insert( + std::make_pair(eventListener, Thread::GetCurrentThread())); + } + + void AddListener(DelegateType delegate) + { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + // Delegate must not be empty + Assert(delegate); + + // Delegate must not already exists + Assert(m_delegateList.find(delegate) == m_delegateList.end()); + + // Add new delegate, inherit dispatcher from current context + m_delegateList.insert( + std::make_pair(delegate, Thread::GetCurrentThread())); + } + + void RemoveListener(EventListenerType *eventListener) + { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + // Listener must not be NULL + Assert(eventListener != NULL); + + // Listener must exist + typename EventListenerList::iterator iterator = + m_eventListenerList.find(eventListener); + + Assert(iterator != m_eventListenerList.end()); + + // Remove listener from list + m_eventListenerList.erase(iterator); + } + + void RemoveListener(DelegateType delegate) + { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + // Delegate must not be empty + Assert(delegate); + + // Delegate must exist + typename DelegateList::iterator iterator = + m_delegateList.find(delegate); + + Assert(iterator != m_delegateList.end()); + + // Remove delegate from list + m_delegateList.erase(iterator); + } + + void SwitchListenerToThread(EventListenerType *eventListener, + Thread *thread) + { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + // Listener must not be NULL + Assert(eventListener != NULL); + + // Listener must exist + typename EventListenerList::iterator iterator = + m_eventListenerList.find(eventListener); + + Assert(iterator != m_eventListenerList.end()); + + // Set listener thread + iterator->second = thread; + } + + void SwitchListenerToThread(DelegateType delegate, + Thread *thread) + { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + // Delegate must not be empty + Assert(!delegate.empty()); + + // Delegate must exist + typename EventListenerList::iterator iterator = + m_delegateList.find(delegate); + + Assert(iterator != m_delegateList.end()); + + // Set delegate thread + iterator->second = thread; + } + + void SwitchAllListenersToThread(Thread *thread) + { + Mutex::ScopedLock lock(&m_listenerDelegateMutex); + + // Switch all listeners and delegates + FOREACH(iterator, m_eventListenerList) + iterator->second = thread; + + FOREACH(iterator, m_delegateList) + iterator->second = thread; + } +}; +} +} // namespace DPL + +#endif // DPL_EVENT_SUPPORT_H diff --git a/modules/event/include/dpl/event/generic_event_call.h b/modules/event/include/dpl/event/generic_event_call.h new file mode 100644 index 0000000..2cdf026 --- /dev/null +++ b/modules/event/include/dpl/event/generic_event_call.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_event_call.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of generic event call + */ +#ifndef DPL_GENERIC_EVENT_CALL_H +#define DPL_GENERIC_EVENT_CALL_H + +#include + +#include +#include +#include +#include +#include + +namespace DPL { +namespace Event { +template +class GenericEventCall : + public AbstractEventCall +{ + public: + typedef EventListener EventListenerType; + typedef std::function DelegateType; + + protected: + SupportDataType m_supportData; + EventListenerType *m_eventListener; + DelegateType m_delegate; + EventType m_event; + + public: + template + struct Rebind + { + typedef GenericEventCall Other; + }; + + GenericEventCall(SupportDataType supportData, + EventListenerType *eventListener, + DelegateType delegate, + const EventType &event) : + m_supportData(supportData), + m_eventListener(eventListener), + m_delegate(delegate), + m_event(event) + {} + + virtual ~GenericEventCall() + { + Assert(m_supportData == NULL && + "Call method hasn't been called" + " (support data wasn't destroyed)"); + } + + virtual void Call() + { + LogPedantic("Calling generic event call"); + + m_supportData->CallAndDestroy(m_event, m_eventListener, m_delegate); + + // Now m_supportData points to invalid object. Marking it as NULL. + m_supportData = NULL; + + LogPedantic("Generic event called"); + } + + virtual void DisableEvent() + { + LogPedantic("Disabling this EventCall"); + m_supportData->Reset(); + + // TODO: In the future, event should be completely removed + // from the event queue (not just marked "disabled") + } +}; +} +} // namespace DPL + +#endif // DPL_GENERIC_EVENT_CALL_H diff --git a/modules/event/include/dpl/event/inter_context_delegate.h b/modules/event/include/dpl/event/inter_context_delegate.h new file mode 100644 index 0000000..2d711fe --- /dev/null +++ b/modules/event/include/dpl/event/inter_context_delegate.h @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file inter_context_delegate.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the header file of inter context delegate + */ + +#ifndef DPL_INTER_CONTEXT_DELEGATE_H_ +#define DPL_INTER_CONTEXT_DELEGATE_H_ + +#ifndef __GXX_EXPERIMENTAL_CXX0X__ // C++11 compatibility check +# include +#else + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * - Created ICDelegate can be passed freely to other threads. + * - ICDelegate can be called just once. All following calls will be + * silently ignored. + * - When ICDelegateSupport is destroyed, all its ICDelegates + * are invalidated and safetly removed. + * - ICDelegate can be invalidated by call to disable method on it. + * - To use ICDelegate you have to do two steps: + * + * 1. Class that will be used to create delegate have to derive from templated + * class ICDelegateSupport + * + * 2. Create instance of ICDelegate by calling + * makeICDelegate and passing to it pointer to method + * + * class A : ICDelegateSupport + * { + * void methodA(int) {} + * void createDelegate() { + * ICDelegate dlg; + * dlg = makeICDelegate(&A::MethodA); + * }; + */ + +namespace DPL { +namespace Event { +//forward declaration +template +class ICDelegate; + +namespace ICD { +// This Type defines whether ICDelegate should be destroyed after the call, or +// could be reused later. +enum class Reuse +{ + Yes, No +}; +} + +namespace ICDPrivate { +// Base for all ICDSharedDatas. Needed for auto disabling and deleting of +// ICDSharedDatas. +// If ICDSharedData is disabled, delegate won't be called anymore. +class ICDSharedDataBase +{ + public: + typedef std::shared_ptr ICDSharedDataBasePtr; + typedef std::list ICDSharedDataBaseList; + + class ScopedLock : DPL::Noncopyable + { + public: + explicit ScopedLock(ICDSharedDataBasePtr helperBase) : + m_scopedLock(&helperBase->m_mutex) + {} + + private: + DPL::RecursiveMutex::ScopedLock m_scopedLock; + }; + + ICDSharedDataBase() : m_disabled(false) + {} + virtual ~ICDSharedDataBase() + {} + + bool isDisabled() const + { + return m_disabled; + } + virtual void disable() + { + m_disabled = true; + } + + void setIterator(ICDSharedDataBaseList::iterator pos) + { + m_position = pos; + } + + ICDSharedDataBaseList::iterator getIterator() const + { + return m_position; + } + + private: + bool m_disabled; + DPL::RecursiveMutex m_mutex; + ICDSharedDataBaseList::iterator m_position; +}; + +// Pure Event to remove ICDSharedData. +class DeleteICDSharedDataBaseEventCall : public DPL::Event::AbstractEventCall +{ + public: + DeleteICDSharedDataBaseEventCall( + ICDSharedDataBase::ICDSharedDataBasePtr helperBase) : + m_helperBase(helperBase) + {} + virtual void Call() + { + m_helperBase.reset(); + } + + private: + ICDSharedDataBase::ICDSharedDataBasePtr m_helperBase; +}; + +class ICDelegateSupportInterface +{ + protected: + virtual ~ICDelegateSupportInterface() + {} + virtual void unregisterICDSharedData( + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) = 0; + virtual void registerICDSharedData( + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) = 0; + + private: + template + friend class DPL::Event::ICDelegate; +}; +} //ICDPrivate + +template +std::function +makeDelegate(ThisType* This, + void (ThisType::*Func)(ArgTypesList ...)) +{ + return DPL::Bind(Func, This); +} + +// ICDelegate class represents delegate that can be called from +// any context (thread). The actual calling context (thread) is allways the same +// as the context in which it was created. +template +class ICDelegate +{ + public: + ICDelegate() + {} + ICDelegate(ICDPrivate::ICDelegateSupportInterface* base, + std::function outerDelegate, + ICD::Reuse reuse) + { + ICDSharedData* hlp = new ICDSharedData(base, outerDelegate, reuse); + m_helper.reset(hlp); + } + + // Calling operator will pass all args passed to it to correct context and + // will call apropriate method that was registered with. + void operator()(ArgTypesList ... args) + { + Assert(m_helper); + ICDPrivate::ICDSharedDataBase::ScopedLock lock( + std::static_pointer_cast(m_helper)); + m_helper->CallDelegate(args ...); + } + + //Disable delegate (it won't be called anymore) + void disable() + { + Assert(m_helper); + ICDPrivate::ICDSharedDataBase::ScopedLock lock( + std::static_pointer_cast(m_helper)); + m_helper->disable(); + } + + protected: + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr + getRelatedICDSharedData() const + { + return std::static_pointer_cast(m_helper); + } + + private: + template + friend class ICDelegateSupport; + class ICDSharedData; + typedef std::shared_ptr ICDSharedDataPtr; + + struct PrivateEvent + { + PrivateEvent(ICDSharedDataPtr a_helper, + ArgTypesList ... arguments) : + helper(a_helper), + args(std::make_tuple(arguments ...)) + {} + + ICDSharedDataPtr helper; + std::tuple args; + }; + + typedef std::function + ICDSharedDataDelegateType; + class ICDSharedData : private DPL::Event::EventSupport, + public std::enable_shared_from_this, + public ICDPrivate::ICDSharedDataBase + { + public: + ICDSharedData( + ICDPrivate::ICDelegateSupportInterface *base, + std::function outerDelegate, + ICD::Reuse reuse) : + m_base(base), + m_outerDelegate(outerDelegate), + m_reuse(reuse) + { + Assert(m_base); + // lock is not needed: this object is not shared at that moment + m_subDelegate = + DPL::Event::makeDelegate(this, + &ICDSharedData::delegateForwarder); + EventSupport::AddListener(m_subDelegate); + } + + void CallDelegate(ArgTypesList ... args) + { + ICDPrivate::ICDSharedDataBase::ScopedLock lock( + std::static_pointer_cast( + this->shared_from_this())); + if (!isDisabled()) { + EmitEvent(PrivateEvent(this->shared_from_this(), + args ...)); + } + } + + virtual void disable() + { + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr ptr( + std::static_pointer_cast( + this->shared_from_this())); + ICDPrivate::ICDSharedDataBase::ScopedLock lock(ptr); + if (!isDisabled()) { + ICDPrivate::ICDSharedDataBase::disable(); + EventSupport::RemoveListener(m_subDelegate); + m_base->unregisterICDSharedData(ptr); + } + } + + private: + friend class std::shared_ptr; + ICDSharedDataDelegateType m_subDelegate; + ICDPrivate::ICDelegateSupportInterface* m_base; + std::function m_outerDelegate; + ICD::Reuse m_reuse; + + void delegateForwarder(const PrivateEvent& event) + { + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr ptr( + std::static_pointer_cast(event.helper)); + ICDPrivate::ICDSharedDataBase::ScopedLock lock(ptr); + + Assert(m_outerDelegate); + if (ptr->isDisabled()) { + LogPedantic("ICDSharedData has been disabled - call is ignored"); + } else { + DPL::Apply(m_outerDelegate, event.args); + + if (m_reuse == ICD::Reuse::Yes) { + return; + } + + disable(); + deleteICDSharedDataBase(ptr); + } + } + }; + + // Schedules helper removal. + static void deleteICDSharedDataBase( + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) + { + using namespace ICDPrivate; + ICDSharedDataBase::ScopedLock lock(helper); + DeleteICDSharedDataBaseEventCall* event = + new DeleteICDSharedDataBaseEventCall(helper); + if (DPL::Thread::GetCurrentThread() == NULL) { + DPL::Event::GetMainEventDispatcherInstance().AddEventCall(event); + } else { + DPL::Event::ThreadEventDispatcher dispatcher; + dispatcher.SetThread(DPL::Thread::GetCurrentThread()); + dispatcher.AddEventCall(event); + } + } + + ICDSharedDataPtr m_helper; +}; + +template +class ICDelegateSupport : public ICDPrivate::ICDelegateSupportInterface +{ + protected: + template + ICDelegate makeICDelegate( + void (ThisType::*Func)(ArgTypesList ...), + ICD::Reuse reuse = ICD::Reuse::No) + { + ThisType* This = static_cast(this); + ICDelegate icdelegate( + This, + makeDelegate(This, Func), + reuse); + this->registerICDSharedData(icdelegate.getRelatedICDSharedData()); + return icdelegate; + } + + ICDelegateSupport() + {} + + ~ICDelegateSupport() + { + ICDPrivate::ICDSharedDataBase::ICDSharedDataBaseList list = + m_ICDSharedDatas; + FOREACH(helper, list) { + ICDPrivate::ICDSharedDataBase::ScopedLock lock( + std::static_pointer_cast(*helper)); + (*helper)->disable(); + } + m_ICDSharedDatas.clear(); + } + + private: + virtual void unregisterICDSharedData( + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) + { + m_ICDSharedDatas.erase(helper->getIterator()); + } + + virtual void registerICDSharedData( + ICDPrivate::ICDSharedDataBase::ICDSharedDataBasePtr helper) + { + helper->setIterator( + m_ICDSharedDatas.insert(m_ICDSharedDatas.begin(), + helper)); + } + + private: + ICDPrivate::ICDSharedDataBase::ICDSharedDataBaseList m_ICDSharedDatas; +}; +} +} //namespace + +#endif // __GXX_EXPERIMENTAL_CXX0X__ + +#endif //DPL_INTER_CONTEXT_DELEGATE_H_ diff --git a/modules/event/include/dpl/event/main_event_dispatcher.h b/modules/event/include/dpl/event/main_event_dispatcher.h new file mode 100644 index 0000000..db86b1f --- /dev/null +++ b/modules/event/include/dpl/event/main_event_dispatcher.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main_event_dispatcher.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main event dispatcher + * for EFL + */ +#ifndef DPL_MAIN_EVENT_DISPATCHER_H +#define DPL_MAIN_EVENT_DISPATCHER_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Event { +class MainEventDispatcher : + public AbstractEventDispatcher +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + DECLARE_EXCEPTION_TYPE(Base, AddEventFailed) + DECLARE_EXCEPTION_TYPE(Base, AddTimedEventFailed) + }; + + protected: + struct WrappedEventCall + { + AbstractEventCall *abstractEventCall; + bool timed; + double dueTime; + + WrappedEventCall(AbstractEventCall *abstractEventCallArg, + bool timedArg, + double dueTimeArg) : + abstractEventCall(abstractEventCallArg), + timed(timedArg), + dueTime(dueTimeArg) + {} + }; + + typedef std::list WrappedEventCallList; + + // Cross thread send support + WrappedEventCallList m_wrappedCrossEventCallList; + Mutex m_crossEventCallMutex; + WaitableEvent* m_crossEventCallInvoker; + + Ecore_Event_Handler *m_eventCallHandler; + Ecore_Fd_Handler *m_crossEventCallHandler; + + int m_eventId; + + // Timed event support + struct TimedEventStruct + { + AbstractEventCall *abstractEventCall; + MainEventDispatcher *This; + + TimedEventStruct(AbstractEventCall *abstractEventCallArg, + MainEventDispatcher *ThisArg) : + abstractEventCall(abstractEventCallArg), + This(ThisArg) + {} + }; + + void InternalAddEvent(AbstractEventCall *abstractEventCall, + bool timed, + double dueTime); + + static void StaticDeleteEvent(void *data, void *event); + static Eina_Bool StaticDispatchEvent(void *data, int type, void *event); + static Eina_Bool StaticDispatchTimedEvent(void *event); + static Eina_Bool StaticDispatchCrossInvoker(void *data, + Ecore_Fd_Handler *fd_handler); + + void DeleteEvent(AbstractEventCall *abstractEventCall); + void DispatchEvent(AbstractEventCall *abstractEventCall); + void DispatchTimedEvent(AbstractEventCall *abstractEventCall); + void DispatchCrossInvoker(); + + public: + explicit MainEventDispatcher(); + virtual ~MainEventDispatcher(); + + virtual void AddEventCall(AbstractEventCall *abstractEventCall); + virtual void AddTimedEventCall(AbstractEventCall *abstractEventCall, + double dueTime); + virtual void ResetCrossEventCallHandler(); +}; + +MainEventDispatcher& GetMainEventDispatcherInstance(); +} +} // namespace DPL + +#endif // DPL_MAIN_EVENT_DISPATCHER_H diff --git a/modules/event/include/dpl/event/model.h b/modules/event/include/dpl/event/model.h new file mode 100644 index 0000000..b149eee --- /dev/null +++ b/modules/event/include/dpl/event/model.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file model.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for model + */ +#ifndef DPL_MODEL_H +#define DPL_MODEL_H + +#include +#include + +namespace DPL { +namespace Event { +class Model : + public Noncopyable +{ + protected: + mutable DPL::ReadWriteMutex m_mutex; + + template + friend class PropertyBase; + + template + friend class Property; + + public: + virtual ~Model() = 0; +}; +} +} // namespace DPL + +#endif // DPL_MODEL_H diff --git a/modules/event/include/dpl/event/model_bind_to_dao.h b/modules/event/include/dpl/event/model_bind_to_dao.h new file mode 100644 index 0000000..2ed7e0e --- /dev/null +++ b/modules/event/include/dpl/event/model_bind_to_dao.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file model_bind_to_dao.h + * @author Grzegorz Krawczyk (g.krawczyk@samsung.com) + * @version 1.0 + * @brief + */ + +#ifndef DPL_MODEL_BIND_TO_DAO_H_ +#define DPL_MODEL_BIND_TO_DAO_H_ + +namespace DPL { +namespace Event { +/** + * @param ObjectType type of object used as delegate argument + * @param RetType Type returned from the external function + * @param ExtArg Type of argument required by external fun + * @param getterFun Object Type method which returns value of type ExtArg + * used as argument for external function + * */ +//STATIC FUNCTION +template < + typename ObjectType, + typename ValueType, + typename ExtArg, + ExtArg(ObjectType::*argGetter) () const, + ValueType(*externalGetter) (ExtArg) + > +struct BindToDAO_Static +{ + static ValueType Get(DPL::Event::Model* obj) + { + ObjectType* instance = static_cast(obj); + + return externalGetter((instance->*argGetter)()); + } +}; + +template < + typename ObjectType, + typename ValueType, + typename ExtArg, + typename ExtObject, + ExtArg(ObjectType::*argGetter) () const, + ValueType(ExtObject::*externalGetter) () const + > +struct BindToDAO +{ + static ValueType Get(DPL::Event::Model* obj) + { + ObjectType* instance = static_cast(obj); + ExtObject extObject((instance->*argGetter)()); + return (extObject.*externalGetter)(); + } +}; +} +} + +#endif diff --git a/modules/event/include/dpl/event/property.h b/modules/event/include/dpl/event/property.h new file mode 100644 index 0000000..ce2e5c7 --- /dev/null +++ b/modules/event/include/dpl/event/property.h @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file property.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for property + */ +#ifndef DPL_PROPERTY_H +#define DPL_PROPERTY_H + +#include + +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Event { +/** + * Property is a class that encapsulates model's property fields. + * Its main purpose is to automate things related to model's properties + * such as: data storage, synchronization and event emitting. + * + * Property is a template of the following schema: + * + * template class Property + * + * Type is an internal type that property is encapsulating. It is required + * that the type is default-constructible and copyable. + * + * Property access rights control which operations are allowed to be + * executed on property. + * + * Property storage mode is a mode describing where and how internal data should + * be stored. + * + * Property modifiers: + * + * PropertyStorageCached: The data is stored internally as one copy. It can + * never be changed from external. + * + * PropertyStorageDynamic: The data is stored remotely and is accessed via + * provided delegates. It can change at any time + * if external mechanism changes its value. + * + * PropertyStorageDynamicCached: The data is stored internally, but only after + * it has been retrieved by delegates. The + * changed data is stored internally and also set + * remotely with delegate. After the value has + * been received from external source, it will + * never be updated externally. + * + * Property access modes: + * + * PropertyReadOnly: Property is a read-only property. + * It doesn't have Set() method. + * + * PropertyReadWrite: Property is a read-write property. It have both Get() + * and Set() methods. + * + * Examples: + * + * Note: All properties, if not specified otherwise in template arguments, + * have read-write access rights and cached data storage. + * + * Simple property with int: + * @code DPL::Property Number; + * + * A property with string: + * @code DPL::Property Name; + * + * A read-only float property: + * @code DPL::Property Gravity; + * + * A read-write string property: + * @code DPL::Property Caption; + * + * A read-write string property which is stored internally: + * @code DPL::Property Name; + * + * A read-write string property which is stored externally: + * @code DPL::Property RemoteName; + * + * A read-write string property which is stored externally, but also cached: + * @code DPL::Property CachedName; + * + * A model is an agregation of many properties. Whenever some of them change, + * an event with this change is emmited along with model handle which + * contains this property. These changes can be listened to. To achieve this, + * one have to add a delegate which contains changed property value and + * a pointer to the model. + * + * Example of a model with a property: + * + * @code + * class MyModel: public DPL::Model + * { + * public: + * DPL::Property Number1; + * DPL::Property Number2; + * DPL::Property Number3; + * + * // Read write property delegate method can be static + * static int ReadCustomValue(Model *model); + * + * // Read write property delegate method can also be method + * void WriteCustomValue(const int &value, Model *model); + * + * MyModel() + * : // Initialize property with default value and this model + * Number1(this), + * + * // Initialize property with 123 and this model + * Number2(this, 123), + * + * // Initialize property with 0 and custom read delegate and this model + * Number3(this, 0, &ReadCustomValue), + * + * // Initialize property with 7 and custom read-write delegates + * // and this model + * Number4(this, 7, &ReadCustomValue, + * std::bind(&WriteCustomValue, this) + * { + * } + * }; + * + * DPL's delegate mechanism is a general solution, which is capable of + * binding various types of functions and method as a delegate and + * using them in unified way. + * + * Example of registering and unregistering for model's property changes: + * + * @code + * class SomeModel : public DPL::Model + * { + * public: + * DPL::Property Value; + * + * SomeModel() + * : Value(this) + * { + * } + * }; + * + * void ValueChanged(const int &value, Model *model) + * { + * std::cout << "Value changed to: " << value << std::endl; + * } + * + * int main() + * { + * SomeModel model; + * + * // Register a global function as property changed listener + * model.AddListener(&ValueChanged); + * [...] + * model.RemoveListener(&ValueChanged); + * + * // Register a class method as property changed listener + * class Receiver + * { + * public: + * void OnValueChanged(const int &value, Model *model) + * { + * [...] + * } + * } receiver; + * + * model.AddListener( + * std::bind(&Receiver::OnValueChanged, &receiver)); + * [...] + * model.RemoveListener( + * std::bind(&Receiver::OnValueChanged, &receiver)); + * } + */ +struct PropertyStorageCached {}; ///< Always use cached +struct PropertyStorageDynamic {}; ///< Always use dynamic +struct PropertyStorageDynamicCached {}; ///< Use dynamic then cache + +struct PropertyReadOnly {}; ///< Read only, not setter available +struct PropertyReadWrite {}; ///< Read and write + +template +struct PropertyEvent +{ + PropertyEvent(const Type &v, Model *s) : + value(v), + sender(s) + {} + + Type value; + Model *sender; +}; + +template +class PropertyStorageMethodDynamicBase +{ + protected: + ReadDelegateType m_readValue; + WriteDelegateType m_writeValue; + + PropertyStorageMethodDynamicBase(ReadDelegateType readValue, + WriteDelegateType writeValue) : + m_readValue(readValue), + m_writeValue(writeValue) + {} +}; + +template +class PropertyStorageMethodCachedBase +{ + protected: + mutable Type m_value; + + PropertyStorageMethodCachedBase() + {} +}; + +class PropertyStorageMethodBase +{ + protected: + explicit PropertyStorageMethodBase(Model *model) : + m_model(model) + {} + + Model *m_model; +}; + +template +class PropertyStorageMethod; + +template +class PropertyStorageMethod: + protected PropertyStorageMethodBase, + protected PropertyStorageMethodCachedBase +{ + public: + PropertyStorageMethod(Model *model, + ReadDelegateType /*readValue*/, + WriteDelegateType /*writeValue*/) : + PropertyStorageMethodBase(model) + {} + + Type Get() const + { + return this->m_value; + } + + void Set(const Type &value) + { + this->m_value = value; + } +}; + +template +class PropertyStorageMethod: + protected PropertyStorageMethodBase, + protected PropertyStorageMethodDynamicBase +{ + public: + PropertyStorageMethod(Model *model, + ReadDelegateType readValue, + WriteDelegateType writeValue) : + PropertyStorageMethodBase(model), + PropertyStorageMethodDynamicBase( + readValue, + writeValue) + {} + + Type Get() const + { + Assert(this->m_readValue); + return this->m_readValue(m_model); + } + + void Set(const Type &value) + { + Assert(this->m_writeValue); + this->m_writeValue(value, m_model); + } +}; + +template +class PropertyStorageMethod: + protected PropertyStorageMethodBase, + protected PropertyStorageMethodDynamicBase, + protected PropertyStorageMethodCachedBase +{ + private: + typedef PropertyStorageMethod ThisType; + + // These two are mutable + void OnceEnsure() const + { + this->m_value = this->m_readValue(m_model); + } + + void OnceDisable() const + {} + + protected: + mutable Once m_once; + + public: + PropertyStorageMethod(Model *model, + ReadDelegateType readValue, + WriteDelegateType writeValue) : + PropertyStorageMethodBase(model), + PropertyStorageMethodDynamicBase( + readValue, writeValue) + {} + + Type Get() const + { + Assert(this->m_readValue); + m_once.Call(std::bind(&ThisType::OnceEnsure, this)); + return this->m_value; + } + + void Set(const Type &value) + { + Assert(this->m_writeValue); + + this->m_writeValue(value, m_model); + this->m_value = value; + m_once.Call(std::bind(&ThisType::OnceDisable, this)); + } +}; + +template +class PropertyBase : + protected EventSupport > +{ + public: + typedef typename EventSupport >::EventListenerType + EventListenerType; + + typedef typename EventSupport >::DelegateType + DelegateType; + + typedef std::function + ReadDelegateType; + + typedef std::function + WriteDelegateType; + + protected: + PropertyStorageMethod m_storage; + Model *m_model; + + PropertyBase(Model *model, + ReadDelegateType readValue, + WriteDelegateType writeValue) : + m_storage(model, readValue, writeValue), + m_model(model) + {} + + public: + virtual Type Get() const + { + ReadWriteMutex::ScopedReadLock lock(&m_model->m_mutex); + return m_storage.Get(); + } + + void AddListener(DelegateType delegate) + { + EventSupport >::AddListener(delegate); + } + + void RemoveListener(DelegateType delegate) + { + EventSupport >::RemoveListener(delegate); + } +}; + +template +class Property; + +template +class Property: + public PropertyBase +{ + public: + typedef typename PropertyBase::EventListenerType + EventListenerType; + + typedef typename PropertyBase::DelegateType + DelegateType; + + typedef typename PropertyBase::ReadDelegateType + ReadDelegateType; + + typedef typename PropertyBase::WriteDelegateType + WriteDelegateType; + + public: + explicit Property(Model *model, + ReadDelegateType readValue = NULL) : + PropertyBase(model, readValue, NULL) + {} + + Property(Model *model, + const Type &value, + ReadDelegateType readValue = NULL) : + PropertyBase(model, readValue, NULL) + { + this->m_storage.Set(value); + } +}; + +template +class Property: + public PropertyBase +{ + public: + typedef typename PropertyBase::EventListenerType + EventListenerType; + + typedef typename PropertyBase::DelegateType + DelegateType; + + typedef typename PropertyBase::ReadDelegateType + ReadDelegateType; + + typedef typename PropertyBase::WriteDelegateType + WriteDelegateType; + + public: + explicit Property(Model *model, + ReadDelegateType readValue = NULL, + WriteDelegateType writeValue = NULL) : + PropertyBase(model, readValue, writeValue) + {} + + Property(Model *model, + const Type &value, + ReadDelegateType readValue = NULL, + WriteDelegateType writeValue = NULL) : + PropertyBase(model, readValue, writeValue) + { + this->m_storage.Set(value); + } + + virtual void Set(const Type &value) + { + ReadWriteMutex::ScopedWriteLock lock(&this->m_model->m_mutex); + + if (this->m_storage.Get() == value) { + return; + } + + this->m_storage.Set(value); + + this->EmitEvent(PropertyEvent(value, this->m_model), + EmitMode::Auto); + } + + void SetWithoutLock(const Type &value) + { + if (this->m_storage.Get() == value) { + return; + } + + this->m_storage.Set(value); + } +}; +} +} // namespace DPL + +#endif // DPL_PROPERTY_H diff --git a/modules/event/include/dpl/event/thread_event_dispatcher.h b/modules/event/include/dpl/event/thread_event_dispatcher.h new file mode 100644 index 0000000..f3846a6 --- /dev/null +++ b/modules/event/include/dpl/event/thread_event_dispatcher.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread_event_dispatcher.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of thread event dispatcher + */ +#ifndef DPL_THREAD_EVENT_DISPATCHER_H +#define DPL_THREAD_EVENT_DISPATCHER_H + +#include +#include +#include + +namespace DPL { +namespace Event { +class ThreadEventDispatcher : + public AbstractEventDispatcher +{ + protected: + Thread *m_thread; + + static void StaticEventDelete(void *event, void *userParam); + static void StaticEventDispatch(void *event, void *userParam); + + void EventDelete(AbstractEventCall *abstractEventCall); + void EventDispatch(AbstractEventCall *abstractEventCall); + + public: + explicit ThreadEventDispatcher(); + virtual ~ThreadEventDispatcher(); + + void SetThread(Thread *thread); + + virtual void AddEventCall(AbstractEventCall *abstractEventCall); + virtual void AddTimedEventCall(AbstractEventCall *abstractEventCall, + double dueTime); +}; +} +} // namespace DPL + +#endif // DPL_THREAD_EVENT_DISPATCHER_H diff --git a/modules/event/src/abstract_event_call.cpp b/modules/event/src/abstract_event_call.cpp new file mode 100644 index 0000000..748b6da --- /dev/null +++ b/modules/event/src/abstract_event_call.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_event_call.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract event call + */ +#include +#include + +namespace DPL { +namespace Event { +AbstractEventCall::AbstractEventCall() +{} + +AbstractEventCall::~AbstractEventCall() +{} +} +} // namespace DPL diff --git a/modules/event/src/abstract_event_dispatcher.cpp b/modules/event/src/abstract_event_dispatcher.cpp new file mode 100644 index 0000000..7c385a4 --- /dev/null +++ b/modules/event/src/abstract_event_dispatcher.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_event_dispatcher.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract event + * dispatcher + */ +#include +#include + +namespace DPL { +namespace Event { +AbstractEventDispatcher::AbstractEventDispatcher() +{} + +AbstractEventDispatcher::~AbstractEventDispatcher() +{} +} +} // namespace DPL diff --git a/modules/event/src/controller.cpp b/modules/event/src/controller.cpp new file mode 100644 index 0000000..337a39f --- /dev/null +++ b/modules/event/src/controller.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file controller.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC controller + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/event/src/event_listener.cpp b/modules/event/src/event_listener.cpp new file mode 100644 index 0000000..5d0d382 --- /dev/null +++ b/modules/event/src/event_listener.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file event_listener.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC event listener + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/event/src/event_support.cpp b/modules/event/src/event_support.cpp new file mode 100644 index 0000000..d2e643c --- /dev/null +++ b/modules/event/src/event_support.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file event_support.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of MVC event support + */ +#include +#include + +namespace DPL { +namespace Event { +namespace // anonymous +{ +int dummyInitializerProc() +{ + GetMainEventDispatcherInstance(); + return 0; +} + +int g_dummyInitializer = dummyInitializerProc(); +} // namespace anonymous +} +} // namespace DPL + diff --git a/modules/event/src/generic_event_call.cpp b/modules/event/src/generic_event_call.cpp new file mode 100644 index 0000000..d0d6886 --- /dev/null +++ b/modules/event/src/generic_event_call.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_event_call.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of generic event call + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/event/src/inter_context_delegate.cpp b/modules/event/src/inter_context_delegate.cpp new file mode 100644 index 0000000..07e3885 --- /dev/null +++ b/modules/event/src/inter_context_delegate.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file inter_context_delegate.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of ICDelegate functionality + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/event/src/main_event_dispatcher.cpp b/modules/event/src/main_event_dispatcher.cpp new file mode 100644 index 0000000..c860398 --- /dev/null +++ b/modules/event/src/main_event_dispatcher.cpp @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main_event_dispatcher.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main event dispatcher + * for EFL + */ +#include +#include +#include +#include +#include + +namespace DPL { +IMPLEMENT_SINGLETON(Event::MainEventDispatcher) + +namespace Event { +typedef Singleton MainEventDispatcherSingleton; + +namespace // anonymous +{ +static const pthread_t g_threadMain = pthread_self(); + +// Late EFL event handling +MainEventDispatcher *g_lateMainEventDispatcher = NULL; +} // namespace anonymous + +MainEventDispatcher::MainEventDispatcher() +{ + // Late EFL event handling + Assert(g_lateMainEventDispatcher == NULL); + g_lateMainEventDispatcher = this; + + // Increment ECORE init count to ensure we have all + // subsystems correctly set-up until main dispatcher dtor + // This is especially important when MainEventDispatcher + // is a global object destroyed no earlier than crt destroy routine + ecore_init(); + + // Add new global ECORE event + m_eventId = ecore_event_type_new(); + + LogPedantic("ECORE event class registered: " << m_eventId); + + // Register event class handler + if ((m_eventCallHandler = + ecore_event_handler_add(m_eventId, &StaticDispatchEvent, + this)) == NULL) + { + ThrowMsg(Exception::CreateFailed, "Failed to register event handler!"); + } + + // Allocate WaitableEvent + m_crossEventCallInvoker = new WaitableEvent(); + + // Register cross event handler + m_crossEventCallHandler = ecore_main_fd_handler_add( + m_crossEventCallInvoker->GetHandle(), + ECORE_FD_READ, + &StaticDispatchCrossInvoker, + this, + NULL, + NULL); + + if (m_crossEventCallHandler == NULL) { + ThrowMsg(Exception::CreateFailed, + "Failed to register cross event handler!"); + } + + LogPedantic("ECORE cross-event handler registered"); +} + +MainEventDispatcher::~MainEventDispatcher() +{ + // Remove cross event handler + ecore_main_fd_handler_del(m_crossEventCallHandler); + m_crossEventCallHandler = NULL; + LogPedantic("ECORE cross-event handler unregistered"); + + // Remove m_crossEventCallInvoker + delete m_crossEventCallInvoker; + m_crossEventCallInvoker = NULL; + + // Remove event class handler + ecore_event_handler_del(m_eventCallHandler); + m_eventCallHandler = NULL; + + // Decrement ECORE init count + // We do not need ecore routines any more + ecore_shutdown(); + + // Late EFL event handling + Assert(g_lateMainEventDispatcher == this); + g_lateMainEventDispatcher = NULL; +} + +void MainEventDispatcher::ResetCrossEventCallHandler() +{ + // Remove cross event handler + ecore_main_fd_handler_del(m_crossEventCallHandler); + m_crossEventCallHandler = NULL; + LogPedantic("ECORE cross-event handler unregistered"); + + // Re-allocate WaitableEvent + delete m_crossEventCallInvoker; + m_crossEventCallInvoker = new WaitableEvent(); + + // Register cross event handler + m_crossEventCallHandler = + ecore_main_fd_handler_add(m_crossEventCallInvoker->GetHandle(), + ECORE_FD_READ, + &StaticDispatchCrossInvoker, + this, + NULL, + NULL); + + if (m_crossEventCallHandler == NULL) { + ThrowMsg(Exception::CreateFailed, + "Failed to register cross event handler!"); + } + + LogPedantic("ECORE cross-event handler re-registered"); +} + +void MainEventDispatcher::StaticDeleteEvent(void *data, void *event) +{ + LogPedantic("Static ECORE delete event handler"); + + MainEventDispatcher *This = static_cast(data); + AbstractEventCall *abstractEventCall = + static_cast(event); + + Assert(This != NULL); + Assert(abstractEventCall != NULL); + + // Late EFL event handling + if (g_lateMainEventDispatcher == NULL) { + LogPedantic("WARNING: Late EFL event delete!"); + delete abstractEventCall; + } else { + This->DeleteEvent(abstractEventCall); + } +} + +Eina_Bool MainEventDispatcher::StaticDispatchEvent(void *data, + int type, + void *event) +{ + LogPedantic("Static ECORE dispatch event"); + + MainEventDispatcher *This = static_cast(data); + AbstractEventCall *abstractEventCall = + static_cast(event); + (void)type; + + Assert(This != NULL); + Assert(abstractEventCall != NULL); + + // Late EFL event handling + if (g_lateMainEventDispatcher == NULL) { + LogPedantic("WARNING: Late EFL event dispatch!"); + } else { + This->DispatchEvent(abstractEventCall); + } + + // Continue to handler other ECORE events + return ECORE_CALLBACK_RENEW; +} + +Eina_Bool MainEventDispatcher::StaticDispatchTimedEvent(void *data) +{ + LogPedantic("Static ECORE dispatch timed event"); + + TimedEventStruct *timedEventStruct = static_cast(data); + MainEventDispatcher *This = timedEventStruct->This; + AbstractEventCall *abstractEventCall = timedEventStruct->abstractEventCall; + delete timedEventStruct; + + Assert(This != NULL); + Assert(abstractEventCall != NULL); + + // Late EFL event handling + if (g_lateMainEventDispatcher == NULL) { + LogPedantic("WARNING: Late EFL timed event dispatch!"); + } else { + // Dispatch timed event + This->DispatchEvent(abstractEventCall); + } + + // And delete manually event, because ECORE does not + // use delete handler for timers + StaticDeleteEvent(static_cast(This), + static_cast(abstractEventCall)); + + // Do not continue timed event handlers + // This also releases ECORE timer + return ECORE_CALLBACK_CANCEL; +} + +Eina_Bool MainEventDispatcher::StaticDispatchCrossInvoker( + void *data, + Ecore_Fd_Handler * + fd_handler) +{ + LogPedantic("Static ECORE dispatch cross invoker"); + + MainEventDispatcher *This = static_cast(data); + (void)fd_handler; + + Assert(This != NULL); + + // Late EFL event handling + if (g_lateMainEventDispatcher == NULL) { + LogPedantic("WARNING: Late EFL cross invoker dispatch!"); + } else { + This->DispatchCrossInvoker(); + } + + return ECORE_CALLBACK_RENEW; +} + +void MainEventDispatcher::DeleteEvent(AbstractEventCall *abstractEventCall) +{ + LogPedantic("ECORE delete event"); + delete abstractEventCall; +} + +void MainEventDispatcher::DispatchEvent(AbstractEventCall *abstractEventCall) +{ + LogPedantic("ECORE dispatch event"); + + // Call event handler + abstractEventCall->Call(); +} + +void MainEventDispatcher::DispatchTimedEvent( + AbstractEventCall *abstractEventCall) +{ + LogPedantic("ECORE dispatch timed event"); + + // Call event handler + abstractEventCall->Call(); +} + +void MainEventDispatcher::DispatchCrossInvoker() +{ + LogPedantic("ECORE dispatch cross invoker"); + + // Steal cross events list + WrappedEventCallList stolenCrossEvents; + + // Critical section + { + m_crossEventCallInvoker->Reset(); + Mutex::ScopedLock lock(&m_crossEventCallMutex); + m_wrappedCrossEventCallList.swap(stolenCrossEvents); + } + + LogPedantic( + "Cross-thread event list stolen. Number of events: " << + stolenCrossEvents.size()); + + // Repush all stolen events + WrappedEventCallList::const_iterator eventIterator; + + for (eventIterator = stolenCrossEvents.begin(); + eventIterator != stolenCrossEvents.end(); + ++eventIterator) + { + // Unwrap events + LogPedantic("Dispatching event from invoker"); + InternalAddEvent(eventIterator->abstractEventCall, + eventIterator->timed, + eventIterator->dueTime); + } + + LogPedantic("Cross-thread events dispatched"); +} + +void MainEventDispatcher::AddEventCall(AbstractEventCall *abstractEventCall) +{ + if (pthread_equal(pthread_self(), g_threadMain)) { + LogPedantic("Main thread ECORE event push"); + InternalAddEvent(abstractEventCall, false, 0.0); + } else { + LogPedantic("Cross-thread ECORE event push"); + + // Push event to cross event list + { + Mutex::ScopedLock lock(&m_crossEventCallMutex); + m_wrappedCrossEventCallList.push_back(WrappedEventCall( + abstractEventCall, false, + 0.0)); + m_crossEventCallInvoker->Signal(); + } + + LogPedantic("Event pushed to cross-thread event list"); + } +} + +void MainEventDispatcher::AddTimedEventCall( + AbstractEventCall *abstractEventCall, + double dueTime) +{ + if (pthread_equal(pthread_self(), g_threadMain)) { + LogPedantic("Main thread timed ECORE event push"); + InternalAddEvent(abstractEventCall, true, dueTime); + } else { + LogPedantic("Cross-thread timed ECORE event push"); + + // Push event to cross event list + { + Mutex::ScopedLock lock(&m_crossEventCallMutex); + m_wrappedCrossEventCallList.push_back(WrappedEventCall( + abstractEventCall, true, + dueTime)); + m_crossEventCallInvoker->Signal(); + } + + LogPedantic("Event pushed to cross-thread event list"); + } +} + +void MainEventDispatcher::InternalAddEvent(AbstractEventCall *abstractEventCall, + bool timed, + double dueTime) +{ + LogPedantic("Adding base event"); + + if (timed == true) { + // Push timed event onto ecore stack + TimedEventStruct* eventData = new TimedEventStruct(abstractEventCall, + this); + Ecore_Timer *timedEvent = ecore_timer_add(dueTime, + &StaticDispatchTimedEvent, + eventData); + + if (timedEvent == NULL) { + delete eventData; + delete abstractEventCall; + ThrowMsg(Exception::AddTimedEventFailed, + "Failed to add ECORE timed event"); + } + + LogPedantic("Timed wrapped event added"); + } else { + // Push immediate event onto ecore stack + Ecore_Event *event = ecore_event_add(m_eventId, + abstractEventCall, + &StaticDeleteEvent, + this); + + if (event == NULL) { + delete abstractEventCall; + ThrowMsg(Exception::AddEventFailed, "Failed to add ECORE event"); + } + + LogPedantic("Wrapped event added"); + } +} + +MainEventDispatcher& GetMainEventDispatcherInstance() +{ + return MainEventDispatcherSingleton::Instance(); +} +} +} // namespace DPL diff --git a/modules/event/src/model.cpp b/modules/event/src/model.cpp new file mode 100644 index 0000000..58e9a1b --- /dev/null +++ b/modules/event/src/model.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file model.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of model + */ +#include +#include + +namespace DPL { +namespace Event { +Model::~Model() +{} +} +} // namespace DPL diff --git a/modules/event/src/thread_event_dispatcher.cpp b/modules/event/src/thread_event_dispatcher.cpp new file mode 100644 index 0000000..7da99a2 --- /dev/null +++ b/modules/event/src/thread_event_dispatcher.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file thread_event_dispatcher.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of thread event dispatcher + */ +#include +#include +#include +#include + +namespace DPL { +namespace Event { +ThreadEventDispatcher::ThreadEventDispatcher() : + m_thread(NULL) +{} + +ThreadEventDispatcher::~ThreadEventDispatcher() +{} + +void ThreadEventDispatcher::SetThread(Thread *thread) +{ + m_thread = thread; +} + +void ThreadEventDispatcher::StaticEventDelete(void *event, void *userParam) +{ + AbstractEventCall *abstractEventCall = + static_cast(event); + ThreadEventDispatcher *This = + static_cast(userParam); + + LogPedantic("Received static event delete from thread"); + + Assert(abstractEventCall != NULL); + Assert(This != NULL); + + This->EventDelete(abstractEventCall); +} + +void ThreadEventDispatcher::StaticEventDispatch(void *event, void *userParam) +{ + AbstractEventCall *abstractEventCall = + static_cast(event); + ThreadEventDispatcher *This = + static_cast(userParam); + + LogPedantic("Received static event dispatch from thread"); + + Assert(abstractEventCall != NULL); + Assert(This != NULL); + + This->EventDispatch(abstractEventCall); +} + +void ThreadEventDispatcher::EventDelete(AbstractEventCall *abstractEventCall) +{ + LogPedantic("Deleting event"); + delete abstractEventCall; +} + +void ThreadEventDispatcher::EventDispatch(AbstractEventCall *abstractEventCall) +{ + LogPedantic("Dispatching event to event support"); + abstractEventCall->Call(); +} + +void ThreadEventDispatcher::AddEventCall(AbstractEventCall *abstractEventCall) +{ + // Thread must be set prior to call + Assert(m_thread != NULL); + + LogPedantic("Adding event to thread event loop"); + + // Call abstract event call in dedicated thread + m_thread->PushEvent(abstractEventCall, + &StaticEventDispatch, + &StaticEventDelete, + this); +} + +void ThreadEventDispatcher::AddTimedEventCall( + AbstractEventCall *abstractEventCall, + double dueTime) +{ + // Thread must be set prior to call + Assert(m_thread != NULL); + + LogPedantic("Adding timed event to thread event loop"); + + // Call abstract event call in dedicated thread + m_thread->PushTimedEvent(abstractEventCall, + dueTime, + &StaticEventDispatch, + &StaticEventDelete, + this); +} +} +} // namespace DPL diff --git a/modules/i18n/CMakeLists.txt b/modules/i18n/CMakeLists.txt new file mode 100644 index 0000000..9b1b175 --- /dev/null +++ b/modules/i18n/CMakeLists.txt @@ -0,0 +1 @@ +ADD_SUBDIRECTORY(dao) diff --git a/modules/i18n/dao/CMakeLists.txt b/modules/i18n/dao/CMakeLists.txt new file mode 100644 index 0000000..ae2d630 --- /dev/null +++ b/modules/i18n/dao/CMakeLists.txt @@ -0,0 +1,65 @@ +SET(TARGET_I18N_DAO_DB "Sqlite3DbI18n") + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_BINARY_DIR}/modules/i18n/dao/database_checksum_i18n.h + COMMAND ${CMAKE_SOURCE_DIR}/modules/i18n/dao/orm/gen_db_md5.sh + ARGS ${CMAKE_BINARY_DIR}/modules/i18n/dao/database_checksum_i18n.h + ${CMAKE_SOURCE_DIR}/modules/i18n/dao/orm/iana_db + DEPENDS ${CMAKE_SOURCE_DIR}/modules/i18n/dao/orm/iana_db + ${CMAKE_SOURCE_DIR}/modules/i18n/dao/orm/gen_db_md5.sh + COMMENT "Generating WRT i18n database checksum" + ) + +ADD_CUSTOM_COMMAND( OUTPUT .wrt_i18n.db + COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/.wrt_i18n.db + COMMAND gcc -Wall -include ${CMAKE_BINARY_DIR}/modules/i18n/dao/database_checksum_i18n.h -I${PROJECT_SOURCE_DIR}/modules/db/include -I${PROJECT_SOURCE_DIR}/modules/i18n/dao/orm -E ${PROJECT_SOURCE_DIR}/modules/i18n/dao/orm/i18n_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_BINARY_DIR}/wrt_i18n_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_BINARY_DIR}/.wrt_i18n.db ".read ${CMAKE_CURRENT_BINARY_DIR}/wrt_i18n_db.sql" || rm -f ${CMAKE_CURRENT_BINARY_DIR}/.wrt_i18n.db + DEPENDS ${CMAKE_BINARY_DIR}/modules/i18n/dao/database_checksum_i18n.h ${PROJECT_SOURCE_DIR}/modules/i18n/dao/orm/i18n_db_sql_generator.h ${PROJECT_SOURCE_DIR}/modules/i18n/dao/orm/iana_db + ) + +ADD_CUSTOM_COMMAND( OUTPUT .wrt_i18n.db-journal + COMMAND touch + ARGS ${CMAKE_CURRENT_BINARY_DIR}/.wrt_i18n.db-journal + ) + +ADD_CUSTOM_TARGET(${TARGET_I18N_DAO_DB} ALL DEPENDS .wrt_i18n.db .wrt_i18n.db-journal) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/wrt_i18n_db.sql DESTINATION share/wrt-engine/) + +############################################################################### + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(I18N_DAO_DEPS + dlog + REQUIRED) + +SET(I18N_DAO_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/modules/i18n/dao/include + ${PROJECT_SOURCE_DIR}/modules/i18n/dao/orm + ${PROJECT_SOURCE_DIR}/modules/core/include + ${PROJECT_SOURCE_DIR}/modules/db/include + ${PROJECT_SOURCE_DIR}/modules/log/include +) + + +SET(I18N_DAO_RO_SOURCES + src/i18n_database.cpp + src/i18n_dao_read_only.cpp +) + +INCLUDE_DIRECTORIES(${I18N_DAO_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${I18N_DAO_DEPS_INCLUDE_DIRS}) + +ADD_LIBRARY(${TARGET_I18N_DAO_RO_LIB} SHARED ${I18N_DAO_RO_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_I18N_DAO_RO_LIB} PROPERTIES SOVERSION ${API_VERSION} VERSION ${VERSION}) +SET_TARGET_PROPERTIES(${TARGET_I18N_DAO_RO_LIB} PROPERTIES COMPILE_FLAGS "-include ${CMAKE_BINARY_DIR}/modules/i18n/dao/database_checksum_i18n.h") +TARGET_LINK_LIBRARIES(${TARGET_I18N_DAO_RO_LIB} ${TARGET_DPL_DB_EFL}) +ADD_DEPENDENCIES(${TARGET_I18N_DAO_RO_LIB} ${TARGET_I18N_DAO_DB}) + +INSTALL(TARGETS ${TARGET_I18N_DAO_RO_LIB} DESTINATION lib) + +INSTALL(FILES + include/wrt-commons/i18n-dao-ro/i18n_database.h + include/wrt-commons/i18n-dao-ro/i18n_dao_read_only.h + DESTINATION include/dpl-efl/wrt-commons/i18n-dao-ro +) diff --git a/modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_dao_read_only.h b/modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_dao_read_only.h new file mode 100644 index 0000000..7e8ef9d --- /dev/null +++ b/modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_dao_read_only.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of i18n dao namespace. + * + * @file i18n_dao_read_only.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of i18n dao. + */ + +#ifndef _I18N_DAO_READ_ONLY_H_ +#define _I18N_DAO_READ_ONLY_H_ + +#include + +namespace I18n { +namespace DB { +namespace I18nDAOReadOnly { +bool IsValidSubTag(const DPL::String& tag, int type); +} // namespace I18nDAOReadOnly +} // namespace DB +} // namespace I18n + +#endif // _I18N_DAO_READ_ONLY_H_ + diff --git a/modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_database.h b/modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_database.h new file mode 100644 index 0000000..3492f63 --- /dev/null +++ b/modules/i18n/dao/include/wrt-commons/i18n-dao-ro/i18n_database.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _I18N_DATABASE_H_ +#define _I18N_DATABASE_H_ + +#include +#include +#include + +namespace I18n { +namespace DB { +namespace Interface { +void attachDatabaseRO(); +void detachDatabase(); + +extern DPL::Mutex g_dbQueriesMutex; +extern DPL::DB::ThreadDatabaseSupport g_dbInterface; +} // namespace Interface +} // namespace DB +} // namespace I18n + +#define I18N_DB_INTERNAL(tlsCommand, InternalType) \ + static DPL::ThreadLocalVariable *tlsCommand##Ptr = NULL; \ + { \ + DPL::Mutex::ScopedLock lock( \ + &I18n::DB::Interface::g_dbQueriesMutex); \ + if (!tlsCommand##Ptr) { \ + static DPL::ThreadLocalVariable tmp; \ + tlsCommand##Ptr = &tmp; \ + } \ + } \ + DPL::ThreadLocalVariable &tlsCommand = *tlsCommand##Ptr; \ + if (tlsCommand.IsNull()) \ + { \ + tlsCommand = InternalType(&I18n::DB::Interface::g_dbInterface); \ + } + +#define I18N_DB_SELECT(name, type) \ + I18N_DB_INTERNAL(name, type::Select) + +#endif /* _I18N_DATABASE_H_ */ + diff --git a/modules/i18n/dao/orm/gen_db_md5.sh b/modules/i18n/dao/orm/gen_db_md5.sh new file mode 100755 index 0000000..22c2530 --- /dev/null +++ b/modules/i18n/dao/orm/gen_db_md5.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +CHECKSUM=`cat ${2} ${3} 2>/dev/null | md5sum 2>/dev/null | cut -d\ -f1 2>/dev/null` +echo "#define DB_CHECKSUM DB_VERSION_${CHECKSUM}" > ${1} +echo "#define DB_CHECKSUM_STR \"DB_VERSION_${CHECKSUM}\"" >> ${1} + diff --git a/modules/i18n/dao/orm/i18n_db_definitions b/modules/i18n/dao/orm/i18n_db_definitions new file mode 100644 index 0000000..ee94c0a --- /dev/null +++ b/modules/i18n/dao/orm/i18n_db_definitions @@ -0,0 +1,6 @@ +DATABASE_START(i18n) + +#include "iana_db" +#include "version_db" + +DATABASE_END() diff --git a/modules/i18n/dao/orm/i18n_db_sql_generator.h b/modules/i18n/dao/orm/i18n_db_sql_generator.h new file mode 100644 index 0000000..d8f326d --- /dev/null +++ b/modules/i18n/dao/orm/i18n_db_sql_generator.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file i18n_db_sql_generator.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL + * input file from database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. +#include + +#include "i18n_db_definitions" diff --git a/modules/i18n/dao/orm/iana_db b/modules/i18n/dao/orm/iana_db new file mode 100644 index 0000000..ffd41ea --- /dev/null +++ b/modules/i18n/dao/orm/iana_db @@ -0,0 +1,8957 @@ +SQL(BEGIN IMMEDIATE TRANSACTION;) +CREATE_TABLE(iana_records) + COLUMN_NOT_NULL(REC_ID, INT,) + COLUMN_NOT_NULL(TYPE, INT,) + COLUMN(TAG, VARCHAR(256),) + COLUMN(SUBTAG, VARCHAR(256),) + COLUMN(DESCRIPTION, VARCHAR(256),) + COLUMN(ADDED, VARCHAR(256),) + COLUMN(DEPRECATED, INT,) + COLUMN(PREFERRED_VALUE, INT,) + COLUMN(PREFIX, VARCHAR(256),) + COLUMN(SUPPRESS_SCRIPT, VARCHAR(256),) + COLUMN(MACRO_LANGUAGE, VARCHAR(256),) + COLUMN(SCOPE, VARCHAR(256),) + COLUMN(COMMENTS, VARCHAR(256),) +CREATE_TABLE_END() +SQL( +INSERT INTO "iana_records" VALUES(0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1,0,NULL,'aa','afar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2,0,NULL,'ab','abkhazian','1129420800',NULL,NULL,NULL,'cyrl',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3,0,NULL,'ae','avestan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4,0,NULL,'af','afrikaans','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5,0,NULL,'ak','akan','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(6,0,NULL,'am','amharic','1129420800',NULL,NULL,NULL,'ethi',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7,0,NULL,'an','aragonese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8,0,NULL,'ar','arabic','1129420800',NULL,NULL,NULL,'arab',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(9,0,NULL,'as','assamese','1129420800',NULL,NULL,NULL,'beng',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(10,0,NULL,'av','avaric','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(11,0,NULL,'ay','aymara','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(12,0,NULL,'az','azerbaijani','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(13,0,NULL,'ba','bashkir','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(14,0,NULL,'be','belarusian','1129420800',NULL,NULL,NULL,'cyrl',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(15,0,NULL,'bg','bulgarian','1129420800',NULL,NULL,NULL,'cyrl',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(16,0,NULL,'bh','bihari languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(17,0,NULL,'bi','bislama','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(18,0,NULL,'bm','bambara','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(19,0,NULL,'bn','bengali','1129420800',NULL,NULL,NULL,'beng',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(20,0,NULL,'bo','tibetan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(21,0,NULL,'br','breton','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(22,0,NULL,'bs','bosnian','1129420800',NULL,NULL,NULL,'latn','sh',NULL,NULL); +INSERT INTO "iana_records" VALUES(23,0,NULL,'ca','catalan','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(23,0,NULL,'ca','valencian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(24,0,NULL,'ce','chechen','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(25,0,NULL,'ch','chamorro','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(26,0,NULL,'co','corsican','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(27,0,NULL,'cr','cree','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(28,0,NULL,'cs','czech','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(29,0,NULL,'cu','church slavic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(29,0,NULL,'cu','church slavonic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(29,0,NULL,'cu','old bulgarian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(29,0,NULL,'cu','old church slavonic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(29,0,NULL,'cu','old slavonic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(30,0,NULL,'cv','chuvash','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(31,0,NULL,'cy','welsh','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(32,0,NULL,'da','danish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(33,0,NULL,'de','german','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(34,0,NULL,'dv','dhivehi','1129420800',NULL,NULL,NULL,'thaa',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(34,0,NULL,'dv','divehi','1129420800',NULL,NULL,NULL,'thaa',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(34,0,NULL,'dv','maldivian','1129420800',NULL,NULL,NULL,'thaa',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(35,0,NULL,'dz','dzongkha','1129420800',NULL,NULL,NULL,'tibt',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(36,0,NULL,'ee','ewe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(37,0,NULL,'el','modern greek (1453-)','1129420800',NULL,NULL,NULL,'grek',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(38,0,NULL,'en','english','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(39,0,NULL,'eo','esperanto','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(40,0,NULL,'es','castilian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(40,0,NULL,'es','spanish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(41,0,NULL,'et','estonian','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(42,0,NULL,'eu','basque','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(43,0,NULL,'fa','persian','1129420800',NULL,NULL,NULL,'arab',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(44,0,NULL,'ff','fulah','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(45,0,NULL,'fi','finnish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(46,0,NULL,'fj','fijian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(47,0,NULL,'fo','faroese','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(48,0,NULL,'fr','french','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(49,0,NULL,'fy','western frisian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(50,0,NULL,'ga','irish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(51,0,NULL,'gd','gaelic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(51,0,NULL,'gd','scottish gaelic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(52,0,NULL,'gl','galician','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(53,0,NULL,'gn','guarani','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(54,0,NULL,'gu','gujarati','1129420800',NULL,NULL,NULL,'gujr',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(55,0,NULL,'gv','manx','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(56,0,NULL,'ha','hausa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(57,0,NULL,'he','hebrew','1129420800',NULL,NULL,NULL,'hebr',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(58,0,NULL,'hi','hindi','1129420800',NULL,NULL,NULL,'deva',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(59,0,NULL,'ho','hiri motu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(60,0,NULL,'hr','croatian','1129420800',NULL,NULL,NULL,'latn','sh',NULL,NULL); +INSERT INTO "iana_records" VALUES(61,0,NULL,'ht','haitian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(61,0,NULL,'ht','haitian creole','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(62,0,NULL,'hu','hungarian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(63,0,NULL,'hy','armenian','1129420800',NULL,NULL,NULL,'armn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(64,0,NULL,'hz','herero','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(65,0,NULL,'ia','interlingua (international auxiliary language association)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(66,0,NULL,'id','indonesian','1129420800',NULL,NULL,NULL,'latn','ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(67,0,NULL,'ie','interlingue','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(67,0,NULL,'ie','occidental','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(68,0,NULL,'ig','igbo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(69,0,NULL,'ii','nuosu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(69,0,NULL,'ii','sichuan yi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(70,0,NULL,'ik','inupiaq','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(71,0,NULL,'in','indonesian','1129420800',599616000,'id',NULL,'latn','ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(72,0,NULL,'io','ido','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(73,0,NULL,'is','icelandic','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(74,0,NULL,'it','italian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(75,0,NULL,'iu','inuktitut','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(76,0,NULL,'iw','hebrew','1129420800',599616000,'he',NULL,'hebr',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(77,0,NULL,'ja','japanese','1129420800',NULL,NULL,NULL,'jpan',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(78,0,NULL,'ji','yiddish','1129420800',599616000,'yi',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(79,0,NULL,'jv','javanese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(80,0,NULL,'jw','javanese','1129420800',997660800,'jv',NULL,NULL,NULL,NULL,'published by error in table 1 of iso 639:1988'); +INSERT INTO "iana_records" VALUES(81,0,NULL,'ka','georgian','1129420800',NULL,NULL,NULL,'geor',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(82,0,NULL,'kg','kongo','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(83,0,NULL,'ki','gikuyu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(83,0,NULL,'ki','kikuyu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(84,0,NULL,'kj','kuanyama','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(84,0,NULL,'kj','kwanyama','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(85,0,NULL,'kk','kazakh','1129420800',NULL,NULL,NULL,'cyrl',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(86,0,NULL,'kl','greenlandic','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(86,0,NULL,'kl','kalaallisut','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(87,0,NULL,'km','central khmer','1129420800',NULL,NULL,NULL,'khmr',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(88,0,NULL,'kn','kannada','1129420800',NULL,NULL,NULL,'knda',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(89,0,NULL,'ko','korean','1129420800',NULL,NULL,NULL,'kore',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(90,0,NULL,'kr','kanuri','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(91,0,NULL,'ks','kashmiri','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(92,0,NULL,'ku','kurdish','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(93,0,NULL,'kv','komi','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(94,0,NULL,'kw','cornish','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(95,0,NULL,'ky','kirghiz','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(95,0,NULL,'ky','kyrgyz','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(96,0,NULL,'la','latin','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(97,0,NULL,'lb','letzeburgesch','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(97,0,NULL,'lb','luxembourgish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(98,0,NULL,'lg','ganda','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(99,0,NULL,'li','limburgan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(99,0,NULL,'li','limburger','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(99,0,NULL,'li','limburgish','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(100,0,NULL,'ln','lingala','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(101,0,NULL,'lo','lao','1129420800',NULL,NULL,NULL,'laoo',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(102,0,NULL,'lt','lithuanian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(103,0,NULL,'lu','luba-katanga','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(104,0,NULL,'lv','latvian','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(105,0,NULL,'mg','malagasy','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(106,0,NULL,'mh','marshallese','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(107,0,NULL,'mi','maori','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(108,0,NULL,'mk','macedonian','1129420800',NULL,NULL,NULL,'cyrl',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(109,0,NULL,'ml','malayalam','1129420800',NULL,NULL,NULL,'mlym',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(110,0,NULL,'mn','mongolian','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(111,0,NULL,'mo','moldavian','1129420800',1227312000,'ro',NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(111,0,NULL,'mo','moldovan','1129420800',1227312000,'ro',NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(112,0,NULL,'mr','marathi','1129420800',NULL,NULL,NULL,'deva',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(113,0,NULL,'ms','malay (macrolanguage)','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(114,0,NULL,'mt','maltese','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(115,0,NULL,'my','burmese','1129420800',NULL,NULL,NULL,'mymr',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(116,0,NULL,'na','nauru','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(117,0,NULL,'nb','norwegian bokmål','1129420800',NULL,NULL,NULL,'latn','no',NULL,NULL); +INSERT INTO "iana_records" VALUES(118,0,NULL,'nd','north ndebele','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(119,0,NULL,'ne','nepali','1129420800',NULL,NULL,NULL,'deva',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(120,0,NULL,'ng','ndonga','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(121,0,NULL,'nl','dutch','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(121,0,NULL,'nl','flemish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(122,0,NULL,'nn','norwegian nynorsk','1129420800',NULL,NULL,NULL,'latn','no',NULL,NULL); +INSERT INTO "iana_records" VALUES(123,0,NULL,'no','norwegian','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(124,0,NULL,'nr','south ndebele','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(125,0,NULL,'nv','navaho','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(125,0,NULL,'nv','navajo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(126,0,NULL,'ny','chewa','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(126,0,NULL,'ny','chichewa','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(126,0,NULL,'ny','nyanja','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(127,0,NULL,'oc','occitan (post 1500)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(128,0,NULL,'oj','ojibwa','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(129,0,NULL,'om','oromo','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(130,0,NULL,'or','oriya','1129420800',NULL,NULL,NULL,'orya',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(131,0,NULL,'os','ossetian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(131,0,NULL,'os','ossetic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(132,0,NULL,'pa','panjabi','1129420800',NULL,NULL,NULL,'guru',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(132,0,NULL,'pa','punjabi','1129420800',NULL,NULL,NULL,'guru',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(133,0,NULL,'pi','pali','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(134,0,NULL,'pl','polish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(135,0,NULL,'ps','pashto','1129420800',NULL,NULL,NULL,'arab',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(135,0,NULL,'ps','pushto','1129420800',NULL,NULL,NULL,'arab',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(136,0,NULL,'pt','portuguese','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(137,0,NULL,'qu','quechua','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(138,0,NULL,'rm','romansh','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(139,0,NULL,'rn','rundi','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(140,0,NULL,'ro','moldavian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(140,0,NULL,'ro','moldovan','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(140,0,NULL,'ro','romanian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(141,0,NULL,'ru','russian','1129420800',NULL,NULL,NULL,'cyrl',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(142,0,NULL,'rw','kinyarwanda','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(143,0,NULL,'sa','sanskrit','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(144,0,NULL,'sc','sardinian','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(145,0,NULL,'sd','sindhi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(146,0,NULL,'se','northern sami','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(147,0,NULL,'sg','sango','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(148,0,NULL,'sh','serbo-croatian','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage','sr, hr, bs are preferred for most modern uses'); +INSERT INTO "iana_records" VALUES(149,0,NULL,'si','sinhala','1129420800',NULL,NULL,NULL,'sinh',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(149,0,NULL,'si','sinhalese','1129420800',NULL,NULL,NULL,'sinh',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(150,0,NULL,'sk','slovak','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(151,0,NULL,'sl','slovenian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(152,0,NULL,'sm','samoan','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(153,0,NULL,'sn','shona','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(154,0,NULL,'so','somali','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(155,0,NULL,'sq','albanian','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(156,0,NULL,'sr','serbian','1129420800',NULL,NULL,NULL,NULL,'sh',NULL,NULL); +INSERT INTO "iana_records" VALUES(157,0,NULL,'ss','swati','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(158,0,NULL,'st','southern sotho','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(159,0,NULL,'su','sundanese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(160,0,NULL,'sv','swedish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(161,0,NULL,'sw','swahili (macrolanguage)','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(162,0,NULL,'ta','tamil','1129420800',NULL,NULL,NULL,'taml',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(163,0,NULL,'te','telugu','1129420800',NULL,NULL,NULL,'telu',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(164,0,NULL,'tg','tajik','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(165,0,NULL,'th','thai','1129420800',NULL,NULL,NULL,'thai',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(166,0,NULL,'ti','tigrinya','1129420800',NULL,NULL,NULL,'ethi',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(167,0,NULL,'tk','turkmen','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(168,0,NULL,'tl','tagalog','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(169,0,NULL,'tn','tswana','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(170,0,NULL,'to','tonga (tonga islands)','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(171,0,NULL,'tr','turkish','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(172,0,NULL,'ts','tsonga','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(173,0,NULL,'tt','tatar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(174,0,NULL,'tw','twi','1129420800',NULL,NULL,NULL,NULL,'ak',NULL,NULL); +INSERT INTO "iana_records" VALUES(175,0,NULL,'ty','tahitian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(176,0,NULL,'ug','uighur','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(176,0,NULL,'ug','uyghur','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(177,0,NULL,'uk','ukrainian','1129420800',NULL,NULL,NULL,'cyrl',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(178,0,NULL,'ur','urdu','1129420800',NULL,NULL,NULL,'arab',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(179,0,NULL,'uz','uzbek','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(180,0,NULL,'ve','venda','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(181,0,NULL,'vi','vietnamese','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(182,0,NULL,'vo','volapük','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(183,0,NULL,'wa','walloon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(184,0,NULL,'wo','wolof','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(185,0,NULL,'xh','xhosa','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(186,0,NULL,'yi','yiddish','1129420800',NULL,NULL,NULL,'hebr',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(187,0,NULL,'yo','yoruba','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(188,0,NULL,'za','chuang','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(188,0,NULL,'za','zhuang','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(189,0,NULL,'zh','chinese','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(190,0,NULL,'zu','zulu','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(191,0,NULL,'aaa','ghotuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(192,0,NULL,'aab','alumu-tesu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(193,0,NULL,'aac','ari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(194,0,NULL,'aad','amal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(195,0,NULL,'aae','arbëreshë albanian','1248825600',NULL,NULL,NULL,NULL,'sq',NULL,NULL); +INSERT INTO "iana_records" VALUES(196,0,NULL,'aaf','aranadan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(197,0,NULL,'aag','ambrak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(198,0,NULL,'aah','abu'' arapesh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(199,0,NULL,'aai','arifama-miniafia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(200,0,NULL,'aak','ankave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(201,0,NULL,'aal','afade','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(202,0,NULL,'aam','aramanik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(203,0,NULL,'aan','anambé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(204,0,NULL,'aao','algerian saharan arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(205,0,NULL,'aap','pará arára','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(206,0,NULL,'aaq','eastern abnaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(207,0,NULL,'aas','aasáx','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(208,0,NULL,'aat','arvanitika albanian','1248825600',NULL,NULL,NULL,NULL,'sq',NULL,NULL); +INSERT INTO "iana_records" VALUES(209,0,NULL,'aau','abau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(210,0,NULL,'aav','austro-asiatic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(211,0,NULL,'aaw','solong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(212,0,NULL,'aax','mandobo atas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(213,0,NULL,'aaz','amarasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(214,0,NULL,'aba','abé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(215,0,NULL,'abb','bankon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(216,0,NULL,'abc','ambala ayta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(217,0,NULL,'abd','manide','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(218,0,NULL,'abe','western abnaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(219,0,NULL,'abf','abai sungai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(220,0,NULL,'abg','abaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(221,0,NULL,'abh','tajiki arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(222,0,NULL,'abi','abidji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(223,0,NULL,'abj','aka-bea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(224,0,NULL,'abl','lampung nyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(225,0,NULL,'abm','abanyom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(226,0,NULL,'abn','abua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(227,0,NULL,'abo','abon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(228,0,NULL,'abp','abellen ayta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(229,0,NULL,'abq','abaza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(230,0,NULL,'abr','abron','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(231,0,NULL,'abs','ambonese malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(232,0,NULL,'abt','ambulas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(233,0,NULL,'abu','abure','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(234,0,NULL,'abv','baharna arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(235,0,NULL,'abw','pal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(236,0,NULL,'abx','inabaknon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(237,0,NULL,'aby','aneme wake','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(238,0,NULL,'abz','abui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(239,0,NULL,'aca','achagua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(240,0,NULL,'acb','Áncá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(241,0,NULL,'acd','gikyode','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(242,0,NULL,'ace','achinese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(243,0,NULL,'acf','saint lucian creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(244,0,NULL,'ach','acoli','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(245,0,NULL,'aci','aka-cari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(246,0,NULL,'ack','aka-kora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(247,0,NULL,'acl','akar-bale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(248,0,NULL,'acm','mesopotamian arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(249,0,NULL,'acn','achang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(250,0,NULL,'acp','eastern acipa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(251,0,NULL,'acq','ta''izzi-adeni arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(252,0,NULL,'acr','achi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(253,0,NULL,'acs','acroá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(254,0,NULL,'act','achterhoeks','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(255,0,NULL,'acu','achuar-shiwiar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(256,0,NULL,'acv','achumawi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(257,0,NULL,'acw','hijazi arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(258,0,NULL,'acx','omani arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(259,0,NULL,'acy','cypriot arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(260,0,NULL,'acz','acheron','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(261,0,NULL,'ada','adangme','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(262,0,NULL,'adb','adabe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(263,0,NULL,'add','dzodinka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(264,0,NULL,'ade','adele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(265,0,NULL,'adf','dhofari arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(266,0,NULL,'adg','andegerebinha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(267,0,NULL,'adh','adhola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(268,0,NULL,'adi','adi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(269,0,NULL,'adj','adioukrou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(270,0,NULL,'adl','galo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(271,0,NULL,'adn','adang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(272,0,NULL,'ado','abu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(273,0,NULL,'adp','adap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(274,0,NULL,'adq','adangbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(275,0,NULL,'adr','adonara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(276,0,NULL,'ads','adamorobe sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(277,0,NULL,'adt','adnyamathanha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(278,0,NULL,'adu','aduge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(279,0,NULL,'adw','amundava','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(280,0,NULL,'adx','amdo tibetan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(281,0,NULL,'ady','adygei','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(281,0,NULL,'ady','adyghe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(282,0,NULL,'adz','adzera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(283,0,NULL,'aea','areba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(284,0,NULL,'aeb','tunisian arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(285,0,NULL,'aec','saidi arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(286,0,NULL,'aed','argentine sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(287,0,NULL,'aee','northeast pashayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(288,0,NULL,'aek','haeke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(289,0,NULL,'ael','ambele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(290,0,NULL,'aem','arem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(291,0,NULL,'aen','armenian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(292,0,NULL,'aeq','aer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(293,0,NULL,'aer','eastern arrernte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(294,0,NULL,'aes','alsea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(295,0,NULL,'aeu','akeu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(296,0,NULL,'aew','ambakich','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(297,0,NULL,'aey','amele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(298,0,NULL,'aez','aeka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(299,0,NULL,'afa','afro-asiatic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(300,0,NULL,'afb','gulf arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(301,0,NULL,'afd','andai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(302,0,NULL,'afe','putukwam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(303,0,NULL,'afg','afghan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(304,0,NULL,'afh','afrihili','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(305,0,NULL,'afi','akrukay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(306,0,NULL,'afk','nanubae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(307,0,NULL,'afn','defaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(308,0,NULL,'afo','eloyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(309,0,NULL,'afp','tapei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(310,0,NULL,'afs','afro-seminole creole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(311,0,NULL,'aft','afitti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(312,0,NULL,'afu','awutu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(313,0,NULL,'afz','obokuitai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(314,0,NULL,'aga','aguano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(315,0,NULL,'agb','legbo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(316,0,NULL,'agc','agatu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(317,0,NULL,'agd','agarabi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(318,0,NULL,'age','angal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(319,0,NULL,'agf','arguni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(320,0,NULL,'agg','angor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(321,0,NULL,'agh','ngelima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(322,0,NULL,'agi','agariya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(323,0,NULL,'agj','argobba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(324,0,NULL,'agk','isarog agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(325,0,NULL,'agl','fembe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(326,0,NULL,'agm','angaataha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(327,0,NULL,'agn','agutaynen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(328,0,NULL,'ago','tainae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(329,0,NULL,'agp','paranan','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see apf, prf'); +INSERT INTO "iana_records" VALUES(330,0,NULL,'agq','aghem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(331,0,NULL,'agr','aguaruna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(332,0,NULL,'ags','esimbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(333,0,NULL,'agt','central cagayan agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(334,0,NULL,'agu','aguacateco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(335,0,NULL,'agv','remontado dumagat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(336,0,NULL,'agw','kahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(337,0,NULL,'agx','aghul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(338,0,NULL,'agy','southern alta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(339,0,NULL,'agz','mt. iriga agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(340,0,NULL,'aha','ahanta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(341,0,NULL,'ahb','axamb','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(342,0,NULL,'ahg','qimant','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(343,0,NULL,'ahh','aghu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(344,0,NULL,'ahi','tiagbamrin aizi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(345,0,NULL,'ahk','akha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(346,0,NULL,'ahl','igo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(347,0,NULL,'ahm','mobumrin aizi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(348,0,NULL,'ahn','Àhàn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(349,0,NULL,'aho','ahom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(350,0,NULL,'ahp','aproumu aizi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(351,0,NULL,'ahr','ahirani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(352,0,NULL,'ahs','ashe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(353,0,NULL,'aht','ahtena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(354,0,NULL,'aia','arosi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(355,0,NULL,'aib','ainu (china)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(356,0,NULL,'aic','ainbai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(357,0,NULL,'aid','alngith','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(358,0,NULL,'aie','amara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(359,0,NULL,'aif','agi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(360,0,NULL,'aig','antigua and barbuda creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(361,0,NULL,'aih','ai-cham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(362,0,NULL,'aii','assyrian neo-aramaic','1248825600',NULL,NULL,NULL,NULL,'syr',NULL,NULL); +INSERT INTO "iana_records" VALUES(363,0,NULL,'aij','lishanid noshan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(364,0,NULL,'aik','ake','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(365,0,NULL,'ail','aimele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(366,0,NULL,'aim','aimol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(367,0,NULL,'ain','ainu (japan)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(368,0,NULL,'aio','aiton','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(369,0,NULL,'aip','burumakok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(370,0,NULL,'aiq','aimaq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(371,0,NULL,'air','airoran','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(372,0,NULL,'ais','nataoran amis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(373,0,NULL,'ait','arikem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(374,0,NULL,'aiw','aari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(375,0,NULL,'aix','aighon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(376,0,NULL,'aiy','ali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(377,0,NULL,'aja','aja (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(378,0,NULL,'ajg','aja (benin)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(379,0,NULL,'aji','ajië','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(380,0,NULL,'ajp','south levantine arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(381,0,NULL,'ajt','judeo-tunisian arabic','1248825600',NULL,NULL,NULL,NULL,'jrb',NULL,NULL); +INSERT INTO "iana_records" VALUES(382,0,NULL,'aju','judeo-moroccan arabic','1248825600',NULL,NULL,NULL,NULL,'jrb',NULL,NULL); +INSERT INTO "iana_records" VALUES(383,0,NULL,'ajw','ajawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(384,0,NULL,'ajz','amri karbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(385,0,NULL,'akb','batak angkola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(386,0,NULL,'akc','mpur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(387,0,NULL,'akd','ukpet-ehom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(388,0,NULL,'ake','akawaio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(389,0,NULL,'akf','akpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(390,0,NULL,'akg','anakalangu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(391,0,NULL,'akh','angal heneng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(392,0,NULL,'aki','aiome','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(393,0,NULL,'akj','aka-jeru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(394,0,NULL,'akk','akkadian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(395,0,NULL,'akl','aklanon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(396,0,NULL,'akm','aka-bo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(397,0,NULL,'ako','akurio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(398,0,NULL,'akp','siwu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(399,0,NULL,'akq','ak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(400,0,NULL,'akr','araki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(401,0,NULL,'aks','akaselem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(402,0,NULL,'akt','akolet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(403,0,NULL,'aku','akum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(404,0,NULL,'akv','akhvakh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(405,0,NULL,'akw','akwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(406,0,NULL,'akx','aka-kede','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(407,0,NULL,'aky','aka-kol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(408,0,NULL,'akz','alabama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(409,0,NULL,'ala','alago','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(410,0,NULL,'alc','qawasqar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(411,0,NULL,'ald','alladian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(412,0,NULL,'ale','aleut','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(413,0,NULL,'alf','alege','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(414,0,NULL,'alg','algonquian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(415,0,NULL,'alh','alawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(416,0,NULL,'ali','amaimon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(417,0,NULL,'alj','alangan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(418,0,NULL,'alk','alak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(419,0,NULL,'all','allar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(420,0,NULL,'alm','amblong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(421,0,NULL,'aln','gheg albanian','1248825600',NULL,NULL,NULL,NULL,'sq',NULL,NULL); +INSERT INTO "iana_records" VALUES(422,0,NULL,'alo','larike-wakasihu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(423,0,NULL,'alp','alune','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(424,0,NULL,'alq','algonquin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(425,0,NULL,'alr','alutor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(426,0,NULL,'als','tosk albanian','1248825600',NULL,NULL,NULL,NULL,'sq',NULL,NULL); +INSERT INTO "iana_records" VALUES(427,0,NULL,'alt','southern altai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(428,0,NULL,'alu','''are''are','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(429,0,NULL,'alv','atlantic-congo languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(430,0,NULL,'alw','alaba-k’abeena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(430,0,NULL,'alw','wanbasana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(431,0,NULL,'alx','amol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(432,0,NULL,'aly','alyawarr','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(433,0,NULL,'alz','alur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(434,0,NULL,'ama','amanayé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(435,0,NULL,'amb','ambo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(436,0,NULL,'amc','amahuaca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(437,0,NULL,'ame','yanesha''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(438,0,NULL,'amf','hamer-banna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(439,0,NULL,'amg','amarag','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(440,0,NULL,'ami','amis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(441,0,NULL,'amj','amdang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(442,0,NULL,'amk','ambai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(443,0,NULL,'aml','war-jaintia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(444,0,NULL,'amm','ama (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(445,0,NULL,'amn','amanab','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(446,0,NULL,'amo','amo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(447,0,NULL,'amp','alamblak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(448,0,NULL,'amq','amahai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(449,0,NULL,'amr','amarakaeri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(450,0,NULL,'ams','southern amami-oshima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(451,0,NULL,'amt','amto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(452,0,NULL,'amu','guerrero amuzgo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(453,0,NULL,'amv','ambelau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(454,0,NULL,'amw','western neo-aramaic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(455,0,NULL,'amx','anmatyerre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(456,0,NULL,'amy','ami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(457,0,NULL,'amz','atampaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(458,0,NULL,'ana','andaqui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(459,0,NULL,'anb','andoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(460,0,NULL,'anc','ngas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(461,0,NULL,'and','ansus','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(462,0,NULL,'ane','xârâcùù','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(463,0,NULL,'anf','animere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(464,0,NULL,'ang','old english (ca. 450-1100)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(465,0,NULL,'anh','nend','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(466,0,NULL,'ani','andi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(467,0,NULL,'anj','anor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(468,0,NULL,'ank','goemai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(469,0,NULL,'anl','anu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(470,0,NULL,'anm','anal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(471,0,NULL,'ann','obolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(472,0,NULL,'ano','andoque','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(473,0,NULL,'anp','angika','1141776000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(474,0,NULL,'anq','jarawa (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(475,0,NULL,'anr','andh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(476,0,NULL,'ans','anserma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(477,0,NULL,'ant','antakarinya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(478,0,NULL,'anu','anuak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(479,0,NULL,'anv','denya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(480,0,NULL,'anw','anaang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(481,0,NULL,'anx','andra-hus','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(482,0,NULL,'any','anyin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(483,0,NULL,'anz','anem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(484,0,NULL,'aoa','angolar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(485,0,NULL,'aob','abom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(486,0,NULL,'aoc','pemon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(487,0,NULL,'aod','andarum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(488,0,NULL,'aoe','angal enen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(489,0,NULL,'aof','bragat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(490,0,NULL,'aog','angoram','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(491,0,NULL,'aoh','arma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(492,0,NULL,'aoi','anindilyakwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(493,0,NULL,'aoj','mufian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(494,0,NULL,'aok','arhö','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(495,0,NULL,'aol','alor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(496,0,NULL,'aom','Ömie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(497,0,NULL,'aon','bumbita arapesh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(498,0,NULL,'aor','aore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(499,0,NULL,'aos','taikat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(500,0,NULL,'aot','a''tong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(501,0,NULL,'aox','atorada','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(502,0,NULL,'aoz','uab meto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(503,0,NULL,'apa','apache languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(504,0,NULL,'apb','sa''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(505,0,NULL,'apc','north levantine arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(506,0,NULL,'apd','sudanese arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(507,0,NULL,'ape','bukiyip','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(508,0,NULL,'apf','pahanan agta','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(509,0,NULL,'apg','ampanang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(510,0,NULL,'aph','athpariya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(511,0,NULL,'api','apiaká','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(512,0,NULL,'apj','jicarilla apache','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(513,0,NULL,'apk','kiowa apache','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(514,0,NULL,'apl','lipan apache','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(515,0,NULL,'apm','mescalero-chiricahua apache','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(516,0,NULL,'apn','apinayé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(517,0,NULL,'apo','apalik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(518,0,NULL,'app','apma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(519,0,NULL,'apq','a-pucikwar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(520,0,NULL,'apr','arop-lokep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(521,0,NULL,'aps','arop-sissano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(522,0,NULL,'apt','apatani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(523,0,NULL,'apu','apurinã','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(524,0,NULL,'apv','alapmunte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(525,0,NULL,'apw','western apache','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(526,0,NULL,'apx','aputai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(527,0,NULL,'apy','apalaí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(528,0,NULL,'apz','safeyoka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(529,0,NULL,'aqa','alacalufan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(530,0,NULL,'aqc','archi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(531,0,NULL,'aqg','arigidi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(532,0,NULL,'aql','algic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(533,0,NULL,'aqm','atohwaim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(534,0,NULL,'aqn','northern alta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(535,0,NULL,'aqp','atakapa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(536,0,NULL,'aqr','arhâ','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(537,0,NULL,'aqz','akuntsu','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(538,0,NULL,'arb','standard arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(539,0,NULL,'arc','imperial aramaic (700-300 bce)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(539,0,NULL,'arc','official aramaic (700-300 bce)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(540,0,NULL,'ard','arabana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(541,0,NULL,'are','western arrarnta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(542,0,NULL,'arh','arhuaco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(543,0,NULL,'ari','arikara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(544,0,NULL,'arj','arapaso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(545,0,NULL,'ark','arikapú','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(546,0,NULL,'arl','arabela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(547,0,NULL,'arn','mapuche','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(547,0,NULL,'arn','mapudungun','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(548,0,NULL,'aro','araona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(549,0,NULL,'arp','arapaho','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(550,0,NULL,'arq','algerian arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(551,0,NULL,'arr','karo (brazil)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(552,0,NULL,'ars','najdi arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(553,0,NULL,'art','artificial languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(554,0,NULL,'aru','arawá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(554,0,NULL,'aru','aruá (amazonas state)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(555,0,NULL,'arv','arbore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(556,0,NULL,'arw','arawak','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(557,0,NULL,'arx','aruá (rodonia state)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(558,0,NULL,'ary','moroccan arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(559,0,NULL,'arz','egyptian arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(560,0,NULL,'asa','asu (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(561,0,NULL,'asb','assiniboine','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(562,0,NULL,'asc','casuarina coast asmat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(563,0,NULL,'asd','asas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(564,0,NULL,'ase','american sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(565,0,NULL,'asf','australian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(566,0,NULL,'asg','cishingini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(567,0,NULL,'ash','abishira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(568,0,NULL,'asi','buruwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(569,0,NULL,'asj','nsari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(570,0,NULL,'ask','ashkun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(571,0,NULL,'asl','asilulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(572,0,NULL,'asn','xingú asuriní','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(573,0,NULL,'aso','dano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(574,0,NULL,'asp','algerian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(575,0,NULL,'asq','austrian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(576,0,NULL,'asr','asuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(577,0,NULL,'ass','ipulo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(578,0,NULL,'ast','asturian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(578,0,NULL,'ast','asturleonese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(578,0,NULL,'ast','bable','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(578,0,NULL,'ast','leonese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(579,0,NULL,'asu','tocantins asurini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(580,0,NULL,'asv','asoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(581,0,NULL,'asw','australian aborigines sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(582,0,NULL,'asx','muratayak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(583,0,NULL,'asy','yaosakor asmat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(584,0,NULL,'asz','as','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(585,0,NULL,'ata','pele-ata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(586,0,NULL,'atb','zaiwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(587,0,NULL,'atc','atsahuaca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(588,0,NULL,'atd','ata manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(589,0,NULL,'ate','atemble','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(590,0,NULL,'atg','ivbie north-okpela-arhe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(591,0,NULL,'ath','athapascan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(592,0,NULL,'ati','attié','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(593,0,NULL,'atj','atikamekw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(594,0,NULL,'atk','ati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(595,0,NULL,'atl','mt. iraya agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(596,0,NULL,'atm','ata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(597,0,NULL,'atn','ashtiani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(598,0,NULL,'ato','atong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(599,0,NULL,'atp','pudtol atta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(600,0,NULL,'atq','aralle-tabulahan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(601,0,NULL,'atr','waimiri-atroari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(602,0,NULL,'ats','gros ventre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(603,0,NULL,'att','pamplona atta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(604,0,NULL,'atu','reel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(605,0,NULL,'atv','northern altai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(606,0,NULL,'atw','atsugewi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(607,0,NULL,'atx','arutani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(608,0,NULL,'aty','aneityum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(609,0,NULL,'atz','arta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(610,0,NULL,'aua','asumboa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(611,0,NULL,'aub','alugu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(612,0,NULL,'auc','waorani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(613,0,NULL,'aud','anuta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(614,0,NULL,'aue','=/kx''au//''ein','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(615,0,NULL,'auf','arauan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(616,0,NULL,'aug','aguna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(617,0,NULL,'auh','aushi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(618,0,NULL,'aui','anuki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(619,0,NULL,'auj','awjilah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(620,0,NULL,'auk','heyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(621,0,NULL,'aul','aulua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(622,0,NULL,'aum','asu (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(623,0,NULL,'aun','molmo one','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(624,0,NULL,'auo','auyokawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(625,0,NULL,'aup','makayam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(626,0,NULL,'auq','anus','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(626,0,NULL,'auq','korur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(627,0,NULL,'aur','aruek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(628,0,NULL,'aus','australian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(629,0,NULL,'aut','austral','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(630,0,NULL,'auu','auye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(631,0,NULL,'auw','awyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(632,0,NULL,'aux','aurá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(633,0,NULL,'auy','awiyaana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(634,0,NULL,'auz','uzbeki arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(635,0,NULL,'avb','avau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(636,0,NULL,'avd','alviri-vidari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(637,0,NULL,'avi','avikam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(638,0,NULL,'avk','kotava','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(639,0,NULL,'avl','eastern egyptian bedawi arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(640,0,NULL,'avn','avatime','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(641,0,NULL,'avo','agavotaguerra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(642,0,NULL,'avs','aushiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(643,0,NULL,'avt','au','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(644,0,NULL,'avu','avokaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(645,0,NULL,'avv','avá-canoeiro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(646,0,NULL,'awa','awadhi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(647,0,NULL,'awb','awa (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(648,0,NULL,'awc','cicipu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(649,0,NULL,'awd','arawakan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(650,0,NULL,'awe','awetí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(651,0,NULL,'awh','awbono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(652,0,NULL,'awi','aekyom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(653,0,NULL,'awk','awabakal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(654,0,NULL,'awm','arawum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(655,0,NULL,'awn','awngi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(656,0,NULL,'awo','awak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(657,0,NULL,'awr','awera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(658,0,NULL,'aws','south awyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(659,0,NULL,'awt','araweté','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(660,0,NULL,'awu','central awyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(661,0,NULL,'awv','jair awyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(662,0,NULL,'aww','awun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(663,0,NULL,'awx','awara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(664,0,NULL,'awy','edera awyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(665,0,NULL,'axb','abipon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(666,0,NULL,'axg','mato grosso arára','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(667,0,NULL,'axk','yaka (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(668,0,NULL,'axm','middle armenian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(669,0,NULL,'axx','xaragure','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(670,0,NULL,'aya','awar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(671,0,NULL,'ayb','ayizo gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(672,0,NULL,'ayc','southern aymara','1248825600',NULL,NULL,NULL,NULL,'ay',NULL,NULL); +INSERT INTO "iana_records" VALUES(673,0,NULL,'ayd','ayabadhu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(674,0,NULL,'aye','ayere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(675,0,NULL,'ayg','ginyanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(676,0,NULL,'ayh','hadrami arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(677,0,NULL,'ayi','leyigha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(678,0,NULL,'ayk','akuku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(679,0,NULL,'ayl','libyan arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(680,0,NULL,'ayn','sanaani arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(681,0,NULL,'ayo','ayoreo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(682,0,NULL,'ayp','north mesopotamian arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(683,0,NULL,'ayq','ayi (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(684,0,NULL,'ayr','central aymara','1248825600',NULL,NULL,NULL,NULL,'ay',NULL,NULL); +INSERT INTO "iana_records" VALUES(685,0,NULL,'ays','sorsogon ayta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(686,0,NULL,'ayt','magbukun ayta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(687,0,NULL,'ayu','ayu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(688,0,NULL,'ayx','ayi (china)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(689,0,NULL,'ayy','tayabas ayta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(690,0,NULL,'ayz','mai brat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(691,0,NULL,'aza','azha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(692,0,NULL,'azb','south azerbaijani','1248825600',NULL,NULL,NULL,NULL,'az',NULL,NULL); +INSERT INTO "iana_records" VALUES(693,0,NULL,'azc','uto-aztecan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(694,0,NULL,'azg','san pedro amuzgos amuzgo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(695,0,NULL,'azj','north azerbaijani','1248825600',NULL,NULL,NULL,NULL,'az',NULL,NULL); +INSERT INTO "iana_records" VALUES(696,0,NULL,'azm','ipalapa amuzgo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(697,0,NULL,'azo','awing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(698,0,NULL,'azt','faire atta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(699,0,NULL,'azz','highland puebla nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(700,0,NULL,'baa','babatana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(701,0,NULL,'bab','bainouk-gunyuño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(702,0,NULL,'bac','badui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(703,0,NULL,'bad','banda languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(704,0,NULL,'bae','baré','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(705,0,NULL,'baf','nubaca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(706,0,NULL,'bag','tuki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(707,0,NULL,'bah','bahamas creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(708,0,NULL,'bai','bamileke languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(709,0,NULL,'baj','barakai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(710,0,NULL,'bal','baluchi','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(711,0,NULL,'ban','balinese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(712,0,NULL,'bao','waimaha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(713,0,NULL,'bap','bantawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(714,0,NULL,'bar','bavarian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(715,0,NULL,'bas','basa (cameroon)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(716,0,NULL,'bat','baltic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(717,0,NULL,'bau','bada (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(718,0,NULL,'bav','vengo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(719,0,NULL,'baw','bambili-bambui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(720,0,NULL,'bax','bamun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(721,0,NULL,'bay','batuley','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(722,0,NULL,'baz','tunen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(723,0,NULL,'bba','baatonum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(724,0,NULL,'bbb','barai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(725,0,NULL,'bbc','batak toba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(726,0,NULL,'bbd','bau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(727,0,NULL,'bbe','bangba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(728,0,NULL,'bbf','baibai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(729,0,NULL,'bbg','barama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(730,0,NULL,'bbh','bugan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(731,0,NULL,'bbi','barombi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(732,0,NULL,'bbj','ghomálá''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(733,0,NULL,'bbk','babanki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(734,0,NULL,'bbl','bats','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(735,0,NULL,'bbm','babango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(736,0,NULL,'bbn','uneapa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(737,0,NULL,'bbo','konabéré','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(737,0,NULL,'bbo','northern bobo madaré','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(738,0,NULL,'bbp','west central banda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(739,0,NULL,'bbq','bamali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(740,0,NULL,'bbr','girawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(741,0,NULL,'bbs','bakpinka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(742,0,NULL,'bbt','mburku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(743,0,NULL,'bbu','kulung (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(744,0,NULL,'bbv','karnai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(745,0,NULL,'bbw','baba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(746,0,NULL,'bbx','bubia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(747,0,NULL,'bby','befang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(748,0,NULL,'bbz','babalia creole arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(749,0,NULL,'bca','central bai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(750,0,NULL,'bcb','bainouk-samik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(751,0,NULL,'bcc','southern balochi','1248825600',NULL,NULL,NULL,NULL,'bal',NULL,NULL); +INSERT INTO "iana_records" VALUES(752,0,NULL,'bcd','north babar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(753,0,NULL,'bce','bamenyam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(754,0,NULL,'bcf','bamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(755,0,NULL,'bcg','baga binari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(756,0,NULL,'bch','bariai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(757,0,NULL,'bci','baoulé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(758,0,NULL,'bcj','bardi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(759,0,NULL,'bck','bunaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(760,0,NULL,'bcl','central bicolano','1248825600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(761,0,NULL,'bcm','bannoni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(762,0,NULL,'bcn','bali (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(763,0,NULL,'bco','kaluli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(764,0,NULL,'bcp','bali (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(765,0,NULL,'bcq','bench','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(766,0,NULL,'bcr','babine','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(767,0,NULL,'bcs','kohumono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(768,0,NULL,'bct','bendi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(769,0,NULL,'bcu','awad bing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(770,0,NULL,'bcv','shoo-minda-nye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(771,0,NULL,'bcw','bana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(772,0,NULL,'bcy','bacama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(773,0,NULL,'bcz','bainouk-gunyaamolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(774,0,NULL,'bda','bayot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(775,0,NULL,'bdb','basap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(776,0,NULL,'bdc','emberá-baudó','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(777,0,NULL,'bdd','bunama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(778,0,NULL,'bde','bade','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(779,0,NULL,'bdf','biage','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(780,0,NULL,'bdg','bonggi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(781,0,NULL,'bdh','baka (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(782,0,NULL,'bdi','burun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(783,0,NULL,'bdj','bai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(784,0,NULL,'bdk','budukh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(785,0,NULL,'bdl','indonesian bajau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(786,0,NULL,'bdm','buduma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(787,0,NULL,'bdn','baldemu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(788,0,NULL,'bdo','morom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(789,0,NULL,'bdp','bende','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(790,0,NULL,'bdq','bahnar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(791,0,NULL,'bdr','west coast bajau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(792,0,NULL,'bds','burunge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(793,0,NULL,'bdt','bokoto','1248825600',NULL,NULL,NULL,NULL,'gba',NULL,NULL); +INSERT INTO "iana_records" VALUES(794,0,NULL,'bdu','oroko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(795,0,NULL,'bdv','bodo parja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(796,0,NULL,'bdw','baham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(797,0,NULL,'bdx','budong-budong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(798,0,NULL,'bdy','bandjalang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(799,0,NULL,'bdz','badeshi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(800,0,NULL,'bea','beaver','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(801,0,NULL,'beb','bebele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(802,0,NULL,'bec','iceve-maci','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(803,0,NULL,'bed','bedoanas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(804,0,NULL,'bee','byangsi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(805,0,NULL,'bef','benabena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(806,0,NULL,'beg','belait','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(807,0,NULL,'beh','biali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(808,0,NULL,'bei','bekati''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(809,0,NULL,'bej','bedawiyet','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(809,0,NULL,'bej','beja','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(810,0,NULL,'bek','bebeli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(811,0,NULL,'bem','bemba (zambia)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(812,0,NULL,'beo','beami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(813,0,NULL,'bep','besoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(814,0,NULL,'beq','beembe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(815,0,NULL,'ber','berber languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(816,0,NULL,'bes','besme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(817,0,NULL,'bet','guiberoua béte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(818,0,NULL,'beu','blagar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(819,0,NULL,'bev','daloa bété','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(820,0,NULL,'bew','betawi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(821,0,NULL,'bex','jur modo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(822,0,NULL,'bey','beli (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(823,0,NULL,'bez','bena (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(824,0,NULL,'bfa','bari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(825,0,NULL,'bfb','pauri bareli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(826,0,NULL,'bfc','northern bai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(827,0,NULL,'bfd','bafut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(828,0,NULL,'bfe','betaf','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(828,0,NULL,'bfe','tena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(829,0,NULL,'bff','bofi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(830,0,NULL,'bfg','busang kayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(831,0,NULL,'bfh','blafe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(832,0,NULL,'bfi','british sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(833,0,NULL,'bfj','bafanji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(834,0,NULL,'bfk','ban khor sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(835,0,NULL,'bfl','banda-ndélé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(836,0,NULL,'bfm','mmen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(837,0,NULL,'bfn','bunak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(838,0,NULL,'bfo','malba birifor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(839,0,NULL,'bfp','beba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(840,0,NULL,'bfq','badaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(841,0,NULL,'bfr','bazigar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(842,0,NULL,'bfs','southern bai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(843,0,NULL,'bft','balti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(844,0,NULL,'bfu','gahri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(845,0,NULL,'bfw','bondo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(846,0,NULL,'bfx','bantayanon','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(847,0,NULL,'bfy','bagheli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(848,0,NULL,'bfz','mahasu pahari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(849,0,NULL,'bga','gwamhi-wuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(850,0,NULL,'bgb','bobongko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(851,0,NULL,'bgc','haryanvi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(852,0,NULL,'bgd','rathwi bareli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(853,0,NULL,'bge','bauria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(854,0,NULL,'bgf','bangandu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(855,0,NULL,'bgg','bugun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(856,0,NULL,'bgi','giangan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(857,0,NULL,'bgj','bangolan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(858,0,NULL,'bgk','bit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(858,0,NULL,'bgk','buxinhua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(859,0,NULL,'bgl','bo (laos)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(860,0,NULL,'bgm','baga mboteni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(861,0,NULL,'bgn','western balochi','1248825600',NULL,NULL,NULL,NULL,'bal',NULL,NULL); +INSERT INTO "iana_records" VALUES(862,0,NULL,'bgo','baga koga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(863,0,NULL,'bgp','eastern balochi','1248825600',NULL,NULL,NULL,NULL,'bal',NULL,NULL); +INSERT INTO "iana_records" VALUES(864,0,NULL,'bgq','bagri','1248825600',NULL,NULL,NULL,NULL,'raj',NULL,NULL); +INSERT INTO "iana_records" VALUES(865,0,NULL,'bgr','bawm chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(866,0,NULL,'bgs','tagabawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(867,0,NULL,'bgt','bughotu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(868,0,NULL,'bgu','mbongno','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(869,0,NULL,'bgv','warkay-bipim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(870,0,NULL,'bgw','bhatri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(871,0,NULL,'bgx','balkan gagauz turkish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(872,0,NULL,'bgy','benggoi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(873,0,NULL,'bgz','banggai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(874,0,NULL,'bha','bharia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(875,0,NULL,'bhb','bhili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(876,0,NULL,'bhc','biga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(877,0,NULL,'bhd','bhadrawahi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(878,0,NULL,'bhe','bhaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(879,0,NULL,'bhf','odiai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(880,0,NULL,'bhg','binandere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(881,0,NULL,'bhh','bukharic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(882,0,NULL,'bhi','bhilali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(883,0,NULL,'bhj','bahing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(884,0,NULL,'bhk','albay bicolano','1248825600',1268265600,NULL,NULL,NULL,'bik',NULL,'see fbl, lbl, rbl, ubl'); +INSERT INTO "iana_records" VALUES(885,0,NULL,'bhl','bimin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(886,0,NULL,'bhm','bathari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(887,0,NULL,'bhn','bohtan neo-aramaic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(888,0,NULL,'bho','bhojpuri','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(889,0,NULL,'bhp','bima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(890,0,NULL,'bhq','tukang besi south','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(891,0,NULL,'bhr','bara malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(892,0,NULL,'bhs','buwal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(893,0,NULL,'bht','bhattiyali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(894,0,NULL,'bhu','bhunjia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(895,0,NULL,'bhv','bahau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(896,0,NULL,'bhw','biak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(897,0,NULL,'bhx','bhalay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(898,0,NULL,'bhy','bhele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(899,0,NULL,'bhz','bada (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(900,0,NULL,'bia','badimaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(901,0,NULL,'bib','bissa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(902,0,NULL,'bic','bikaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(903,0,NULL,'bid','bidiyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(904,0,NULL,'bie','bepour','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(905,0,NULL,'bif','biafada','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(906,0,NULL,'big','biangai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(907,0,NULL,'bij','vaghat-ya-bijim-legeri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(908,0,NULL,'bik','bikol','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(909,0,NULL,'bil','bile','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(910,0,NULL,'bim','bimoba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(911,0,NULL,'bin','bini','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(911,0,NULL,'bin','edo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(912,0,NULL,'bio','nai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(913,0,NULL,'bip','bila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(914,0,NULL,'biq','bipi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(915,0,NULL,'bir','bisorio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(916,0,NULL,'bit','berinomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(917,0,NULL,'biu','biete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(918,0,NULL,'biv','southern birifor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(919,0,NULL,'biw','kol (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(920,0,NULL,'bix','bijori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(921,0,NULL,'biy','birhor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(922,0,NULL,'biz','baloi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(923,0,NULL,'bja','budza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(924,0,NULL,'bjb','banggarla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(925,0,NULL,'bjc','bariji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(926,0,NULL,'bjd','bandjigali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(927,0,NULL,'bje','biao-jiao mien','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(928,0,NULL,'bjf','barzani jewish neo-aramaic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(929,0,NULL,'bjg','bidyogo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(930,0,NULL,'bjh','bahinemo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(931,0,NULL,'bji','burji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(932,0,NULL,'bjj','kanauji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(933,0,NULL,'bjk','barok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(934,0,NULL,'bjl','bulu (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(935,0,NULL,'bjm','bajelani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(936,0,NULL,'bjn','banjar','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(937,0,NULL,'bjo','mid-southern banda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(938,0,NULL,'bjq','southern betsimisaraka malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(939,0,NULL,'bjr','binumarien','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(940,0,NULL,'bjs','bajan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(941,0,NULL,'bjt','balanta-ganja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(942,0,NULL,'bju','busuu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(943,0,NULL,'bjv','bedjond','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(944,0,NULL,'bjw','bakwé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(945,0,NULL,'bjx','banao itneg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(946,0,NULL,'bjy','bayali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(947,0,NULL,'bjz','baruga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(948,0,NULL,'bka','kyak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(949,0,NULL,'bkb','finallig','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see ebk, obk'); +INSERT INTO "iana_records" VALUES(950,0,NULL,'bkc','baka (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(951,0,NULL,'bkd','binukid','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(951,0,NULL,'bkd','talaandig','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(952,0,NULL,'bkf','beeke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(953,0,NULL,'bkg','buraka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(954,0,NULL,'bkh','bakoko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(955,0,NULL,'bki','baki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(956,0,NULL,'bkj','pande','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(957,0,NULL,'bkk','brokskat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(958,0,NULL,'bkl','berik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(959,0,NULL,'bkm','kom (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(960,0,NULL,'bkn','bukitan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(961,0,NULL,'bko','kwa''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(962,0,NULL,'bkp','boko (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(963,0,NULL,'bkq','bakairí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(964,0,NULL,'bkr','bakumpai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(965,0,NULL,'bks','northern sorsoganon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(966,0,NULL,'bkt','boloki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(967,0,NULL,'bku','buhid','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(968,0,NULL,'bkv','bekwarra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(969,0,NULL,'bkw','bekwil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(970,0,NULL,'bkx','baikeno','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(971,0,NULL,'bky','bokyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(972,0,NULL,'bkz','bungku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(973,0,NULL,'bla','siksika','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(974,0,NULL,'blb','bilua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(975,0,NULL,'blc','bella coola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(976,0,NULL,'bld','bolango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(977,0,NULL,'ble','balanta-kentohe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(978,0,NULL,'blf','buol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(979,0,NULL,'blg','balau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(980,0,NULL,'blh','kuwaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(981,0,NULL,'bli','bolia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(982,0,NULL,'blj','bolongan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(983,0,NULL,'blk','pa''o karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(984,0,NULL,'bll','biloxi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(985,0,NULL,'blm','beli (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(986,0,NULL,'bln','southern catanduanes bicolano','1248825600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(987,0,NULL,'blo','anii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(988,0,NULL,'blp','blablanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(989,0,NULL,'blq','baluan-pam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(990,0,NULL,'blr','blang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(991,0,NULL,'bls','balaesang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(992,0,NULL,'blt','tai dam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(993,0,NULL,'blv','bolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(994,0,NULL,'blw','balangao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(995,0,NULL,'blx','mag-indi ayta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(996,0,NULL,'bly','notre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(997,0,NULL,'blz','balantak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(998,0,NULL,'bma','lame','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(999,0,NULL,'bmb','bembe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1000,0,NULL,'bmc','biem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1001,0,NULL,'bmd','baga manduri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1002,0,NULL,'bme','limassa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1003,0,NULL,'bmf','bom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1004,0,NULL,'bmg','bamwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1005,0,NULL,'bmh','kein','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1006,0,NULL,'bmi','bagirmi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1007,0,NULL,'bmj','bote-majhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1008,0,NULL,'bmk','ghayavi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1009,0,NULL,'bml','bomboli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1010,0,NULL,'bmm','northern betsimisaraka malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(1011,0,NULL,'bmn','bina (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1012,0,NULL,'bmo','bambalang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1013,0,NULL,'bmp','bulgebi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1014,0,NULL,'bmq','bomu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1015,0,NULL,'bmr','muinane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1016,0,NULL,'bms','bilma kanuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1017,0,NULL,'bmt','biao mon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1018,0,NULL,'bmu','burum-mindik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1019,0,NULL,'bmv','bum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1020,0,NULL,'bmw','bomwali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1021,0,NULL,'bmx','baimak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1022,0,NULL,'bmy','bemba (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1023,0,NULL,'bmz','baramu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1024,0,NULL,'bna','bonerate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1025,0,NULL,'bnb','bookan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1026,0,NULL,'bnc','bontok','1248825600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(1027,0,NULL,'bnd','banda (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1028,0,NULL,'bne','bintauna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1029,0,NULL,'bnf','masiwang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1030,0,NULL,'bng','benga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1031,0,NULL,'bni','bangi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1032,0,NULL,'bnj','eastern tawbuid','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1033,0,NULL,'bnk','bierebo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1034,0,NULL,'bnl','boon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1035,0,NULL,'bnm','batanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1036,0,NULL,'bnn','bunun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1037,0,NULL,'bno','bantoanon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1038,0,NULL,'bnp','bola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1039,0,NULL,'bnq','bantik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1040,0,NULL,'bnr','butmas-tur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1041,0,NULL,'bns','bundeli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1042,0,NULL,'bnt','bantu languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1043,0,NULL,'bnu','bentong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1044,0,NULL,'bnv','beneraf','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1044,0,NULL,'bnv','bonerif','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1044,0,NULL,'bnv','edwas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1045,0,NULL,'bnw','bisis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1046,0,NULL,'bnx','bangubangu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1047,0,NULL,'bny','bintulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1048,0,NULL,'bnz','beezen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1049,0,NULL,'boa','bora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1050,0,NULL,'bob','aweer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1051,0,NULL,'boe','mundabli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1052,0,NULL,'bof','bolon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1053,0,NULL,'bog','bamako sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1054,0,NULL,'boh','boma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1055,0,NULL,'boi','barbareño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1056,0,NULL,'boj','anjam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1057,0,NULL,'bok','bonjo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1058,0,NULL,'bol','bole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1059,0,NULL,'bom','berom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1060,0,NULL,'bon','bine','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1061,0,NULL,'boo','tiemacèwè bozo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1062,0,NULL,'bop','bonkiman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1063,0,NULL,'boq','bogaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1064,0,NULL,'bor','borôro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1065,0,NULL,'bot','bongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1066,0,NULL,'bou','bondei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1067,0,NULL,'bov','tuwuli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1068,0,NULL,'bow','rema','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1069,0,NULL,'box','buamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1070,0,NULL,'boy','bodo (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1071,0,NULL,'boz','tiéyaxo bozo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1072,0,NULL,'bpa','dakaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1073,0,NULL,'bpb','barbacoas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1074,0,NULL,'bpd','banda-banda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1075,0,NULL,'bpg','bonggo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1076,0,NULL,'bph','botlikh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1077,0,NULL,'bpi','bagupi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1078,0,NULL,'bpj','binji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1079,0,NULL,'bpk','orowe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1080,0,NULL,'bpl','broome pearling lugger pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1081,0,NULL,'bpm','biyom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1082,0,NULL,'bpn','dzao min','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1083,0,NULL,'bpo','anasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1084,0,NULL,'bpp','kaure','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1085,0,NULL,'bpq','banda malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1086,0,NULL,'bpr','koronadal blaan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1087,0,NULL,'bps','sarangani blaan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1088,0,NULL,'bpt','barrow point','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1089,0,NULL,'bpu','bongu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1090,0,NULL,'bpv','bian marind','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1091,0,NULL,'bpw','bo (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1092,0,NULL,'bpx','palya bareli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1093,0,NULL,'bpy','bishnupriya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1094,0,NULL,'bpz','bilba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1095,0,NULL,'bqa','tchumbuli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1096,0,NULL,'bqb','bagusa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1097,0,NULL,'bqc','boko (benin)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1098,0,NULL,'bqd','bung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1099,0,NULL,'bqf','baga kaloum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1100,0,NULL,'bqg','bago-kusuntu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1101,0,NULL,'bqh','baima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1102,0,NULL,'bqi','bakhtiari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1103,0,NULL,'bqj','bandial','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1104,0,NULL,'bqk','banda-mbrès','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1105,0,NULL,'bql','bilakura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1106,0,NULL,'bqm','wumboko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1107,0,NULL,'bqn','bulgarian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1108,0,NULL,'bqo','balo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1109,0,NULL,'bqp','busa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1110,0,NULL,'bqq','biritai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1111,0,NULL,'bqr','burusu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1112,0,NULL,'bqs','bosngun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1113,0,NULL,'bqt','bamukumbit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1114,0,NULL,'bqu','boguru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1115,0,NULL,'bqv','begbere-ejar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1116,0,NULL,'bqw','buru (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1117,0,NULL,'bqx','baangi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1118,0,NULL,'bqy','bengkala sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1119,0,NULL,'bqz','bakaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1120,0,NULL,'bra','braj','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1121,0,NULL,'brb','lave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1122,0,NULL,'brc','berbice creole dutch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1123,0,NULL,'brd','baraamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1124,0,NULL,'brf','bera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1125,0,NULL,'brg','baure','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1126,0,NULL,'brh','brahui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1127,0,NULL,'bri','mokpwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1128,0,NULL,'brj','bieria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1129,0,NULL,'brk','birked','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1130,0,NULL,'brl','birwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1131,0,NULL,'brm','barambu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1132,0,NULL,'brn','boruca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1133,0,NULL,'bro','brokkat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1134,0,NULL,'brp','barapasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1135,0,NULL,'brq','breri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1136,0,NULL,'brr','birao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1137,0,NULL,'brs','baras','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1138,0,NULL,'brt','bitare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1139,0,NULL,'bru','eastern bru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1140,0,NULL,'brv','western bru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1141,0,NULL,'brw','bellari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1142,0,NULL,'brx','bodo (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1143,0,NULL,'bry','burui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1144,0,NULL,'brz','bilbil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1145,0,NULL,'bsa','abinomn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1146,0,NULL,'bsb','brunei bisaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1147,0,NULL,'bsc','bassari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1147,0,NULL,'bsc','oniyan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1148,0,NULL,'bse','wushi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1149,0,NULL,'bsf','bauchi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1150,0,NULL,'bsg','bashkardi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1151,0,NULL,'bsh','kati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1152,0,NULL,'bsi','bassossi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1153,0,NULL,'bsj','bangwinji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1154,0,NULL,'bsk','burushaski','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1155,0,NULL,'bsl','basa-gumna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1156,0,NULL,'bsm','busami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1157,0,NULL,'bsn','barasana-eduria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1158,0,NULL,'bso','buso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1159,0,NULL,'bsp','baga sitemu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1160,0,NULL,'bsq','bassa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1161,0,NULL,'bsr','bassa-kontagora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1162,0,NULL,'bss','akoose','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1163,0,NULL,'bst','basketo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1164,0,NULL,'bsu','bahonsuai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1165,0,NULL,'bsv','baga sobané','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1166,0,NULL,'bsw','baiso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1167,0,NULL,'bsx','yangkam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1168,0,NULL,'bsy','sabah bisaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1169,0,NULL,'bta','bata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1170,0,NULL,'btb','beti (cameroon)','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see beb, bum, bxp, eto, ewo, fan, mct'); +INSERT INTO "iana_records" VALUES(1171,0,NULL,'btc','bati (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1172,0,NULL,'btd','batak dairi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1173,0,NULL,'bte','gamo-ningi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1174,0,NULL,'btf','birgit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1175,0,NULL,'btg','gagnoa bété','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1176,0,NULL,'bth','biatah bidayuh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1177,0,NULL,'bti','burate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1178,0,NULL,'btj','bacanese malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(1179,0,NULL,'btk','batak languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1180,0,NULL,'btl','bhatola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1181,0,NULL,'btm','batak mandailing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1182,0,NULL,'btn','ratagnon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1183,0,NULL,'bto','rinconada bikol','1248825600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(1184,0,NULL,'btp','budibud','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1185,0,NULL,'btq','batek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1186,0,NULL,'btr','baetora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1187,0,NULL,'bts','batak simalungun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1188,0,NULL,'btt','bete-bendi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1189,0,NULL,'btu','batu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1190,0,NULL,'btv','bateri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1191,0,NULL,'btw','butuanon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1192,0,NULL,'btx','batak karo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1193,0,NULL,'bty','bobot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1194,0,NULL,'btz','batak alas-kluet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1195,0,NULL,'bua','buriat','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(1196,0,NULL,'bub','bua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1197,0,NULL,'buc','bushi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1198,0,NULL,'bud','ntcham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1199,0,NULL,'bue','beothuk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1200,0,NULL,'buf','bushoong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1201,0,NULL,'bug','buginese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1202,0,NULL,'buh','younuo bunu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1203,0,NULL,'bui','bongili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1204,0,NULL,'buj','basa-gurmana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1205,0,NULL,'buk','bugawac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1206,0,NULL,'bum','bulu (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1207,0,NULL,'bun','sherbro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1208,0,NULL,'buo','terei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1209,0,NULL,'bup','busoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1210,0,NULL,'buq','brem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1211,0,NULL,'bus','bokobaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1212,0,NULL,'but','bungain','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1213,0,NULL,'buu','budu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1214,0,NULL,'buv','bun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1215,0,NULL,'buw','bubi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1216,0,NULL,'bux','boghom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1217,0,NULL,'buy','bullom so','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1218,0,NULL,'buz','bukwen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1219,0,NULL,'bva','barein','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1220,0,NULL,'bvb','bube','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1221,0,NULL,'bvc','baelelea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1222,0,NULL,'bvd','baeggu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1223,0,NULL,'bve','berau malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(1224,0,NULL,'bvf','boor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1225,0,NULL,'bvg','bonkeng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1226,0,NULL,'bvh','bure','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1227,0,NULL,'bvi','belanda viri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1228,0,NULL,'bvj','baan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1229,0,NULL,'bvk','bukat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1230,0,NULL,'bvl','bolivian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1231,0,NULL,'bvm','bamunka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1232,0,NULL,'bvn','buna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1233,0,NULL,'bvo','bolgo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1234,0,NULL,'bvq','birri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1235,0,NULL,'bvr','burarra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1236,0,NULL,'bvt','bati (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1237,0,NULL,'bvu','bukit malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(1238,0,NULL,'bvv','baniva','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1239,0,NULL,'bvw','boga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1240,0,NULL,'bvx','dibole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1241,0,NULL,'bvy','baybayanon','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1242,0,NULL,'bvz','bauzi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1243,0,NULL,'bwa','bwatoo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1244,0,NULL,'bwb','namosi-naitasiri-serua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1245,0,NULL,'bwc','bwile','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1246,0,NULL,'bwd','bwaidoka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1247,0,NULL,'bwe','bwe karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1248,0,NULL,'bwf','boselewa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1249,0,NULL,'bwg','barwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1250,0,NULL,'bwh','bishuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1251,0,NULL,'bwi','baniwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1252,0,NULL,'bwj','láá láá bwamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1253,0,NULL,'bwk','bauwaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1254,0,NULL,'bwl','bwela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1255,0,NULL,'bwm','biwat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1256,0,NULL,'bwn','wunai bunu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1257,0,NULL,'bwo','borna (ethiopia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1257,0,NULL,'bwo','boro (ethiopia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1258,0,NULL,'bwp','mandobo bawah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1259,0,NULL,'bwq','southern bobo madaré','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1260,0,NULL,'bwr','bura-pabir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1261,0,NULL,'bws','bomboma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1262,0,NULL,'bwt','bafaw-balong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1263,0,NULL,'bwu','buli (ghana)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1264,0,NULL,'bww','bwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1265,0,NULL,'bwx','bu-nao bunu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1266,0,NULL,'bwy','cwi bwamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1267,0,NULL,'bwz','bwisi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1268,0,NULL,'bxa','bauro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1269,0,NULL,'bxb','belanda bor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1270,0,NULL,'bxc','molengue','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1271,0,NULL,'bxd','pela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1272,0,NULL,'bxe','birale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1273,0,NULL,'bxf','bilur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1274,0,NULL,'bxg','bangala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1275,0,NULL,'bxh','buhutu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1276,0,NULL,'bxi','pirlatapa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1277,0,NULL,'bxj','bayungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1278,0,NULL,'bxk','bukusu','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(1278,0,NULL,'bxk','lubukusu','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(1279,0,NULL,'bxl','jalkunan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1280,0,NULL,'bxm','mongolia buriat','1248825600',NULL,NULL,NULL,NULL,'bua',NULL,NULL); +INSERT INTO "iana_records" VALUES(1281,0,NULL,'bxn','burduna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1282,0,NULL,'bxo','barikanchi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1283,0,NULL,'bxp','bebil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1284,0,NULL,'bxq','beele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1285,0,NULL,'bxr','russia buriat','1248825600',NULL,NULL,NULL,NULL,'bua',NULL,NULL); +INSERT INTO "iana_records" VALUES(1286,0,NULL,'bxs','busam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1287,0,NULL,'bxu','china buriat','1248825600',NULL,NULL,NULL,NULL,'bua',NULL,NULL); +INSERT INTO "iana_records" VALUES(1288,0,NULL,'bxv','berakou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1289,0,NULL,'bxw','bankagooma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1290,0,NULL,'bxx','borna (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1291,0,NULL,'bxz','binahari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1292,0,NULL,'bya','batak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1293,0,NULL,'byb','bikya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1294,0,NULL,'byc','ubaghara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1295,0,NULL,'byd','benyadu''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1296,0,NULL,'bye','pouye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1297,0,NULL,'byf','bete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1298,0,NULL,'byg','baygo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1299,0,NULL,'byh','bhujel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1300,0,NULL,'byi','buyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1301,0,NULL,'byj','bina (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1302,0,NULL,'byk','biao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1303,0,NULL,'byl','bayono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1304,0,NULL,'bym','bidyara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1305,0,NULL,'byn','bilin','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1305,0,NULL,'byn','blin','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1306,0,NULL,'byo','biyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1307,0,NULL,'byp','bumaji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1308,0,NULL,'byq','basay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1309,0,NULL,'byr','baruya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1310,0,NULL,'bys','burak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1311,0,NULL,'byt','berti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1312,0,NULL,'byv','medumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1313,0,NULL,'byw','belhariya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1314,0,NULL,'byx','qaqet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1315,0,NULL,'byy','buya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1316,0,NULL,'byz','banaro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1317,0,NULL,'bza','bandi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1318,0,NULL,'bzb','andio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1319,0,NULL,'bzd','bribri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1320,0,NULL,'bze','jenaama bozo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1321,0,NULL,'bzf','boikin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1322,0,NULL,'bzg','babuza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1323,0,NULL,'bzh','mapos buang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1324,0,NULL,'bzi','bisu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1325,0,NULL,'bzj','belize kriol english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1326,0,NULL,'bzk','nicaragua creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1327,0,NULL,'bzl','boano (sulawesi)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1328,0,NULL,'bzm','bolondo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1329,0,NULL,'bzn','boano (maluku)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1330,0,NULL,'bzo','bozaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1331,0,NULL,'bzp','kemberano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1332,0,NULL,'bzq','buli (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1333,0,NULL,'bzr','biri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1334,0,NULL,'bzs','brazilian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1335,0,NULL,'bzt','brithenig','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1336,0,NULL,'bzu','burmeso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1337,0,NULL,'bzv','bebe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1338,0,NULL,'bzw','basa (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1339,0,NULL,'bzx','hainyaxo bozo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1340,0,NULL,'bzy','obanliku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1341,0,NULL,'bzz','evant','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1342,0,NULL,'caa','chortí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1343,0,NULL,'cab','garifuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1344,0,NULL,'cac','chuj','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1345,0,NULL,'cad','caddo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1346,0,NULL,'cae','laalaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1346,0,NULL,'cae','lehar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1347,0,NULL,'caf','southern carrier','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1348,0,NULL,'cag','nivaclé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1349,0,NULL,'cah','cahuarano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1350,0,NULL,'cai','central american indian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1351,0,NULL,'caj','chané','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1352,0,NULL,'cak','cakchiquel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1352,0,NULL,'cak','kaqchikel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1353,0,NULL,'cal','carolinian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1354,0,NULL,'cam','cemuhî','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1355,0,NULL,'can','chambri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1356,0,NULL,'cao','chácobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1357,0,NULL,'cap','chipaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1358,0,NULL,'caq','car nicobarese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1359,0,NULL,'car','galibi carib','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1360,0,NULL,'cas','tsimané','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1361,0,NULL,'cau','caucasian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1362,0,NULL,'cav','cavineña','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1363,0,NULL,'caw','callawalla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1364,0,NULL,'cax','chiquitano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1365,0,NULL,'cay','cayuga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1366,0,NULL,'caz','canichana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1367,0,NULL,'cba','chibchan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1368,0,NULL,'cbb','cabiyarí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1369,0,NULL,'cbc','carapana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1370,0,NULL,'cbd','carijona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1371,0,NULL,'cbe','chipiajes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1372,0,NULL,'cbg','chimila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1373,0,NULL,'cbh','cagua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1374,0,NULL,'cbi','chachi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1375,0,NULL,'cbj','ede cabe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1376,0,NULL,'cbk','chavacano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1377,0,NULL,'cbl','bualkhaw chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1378,0,NULL,'cbn','nyahkur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1379,0,NULL,'cbo','izora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1380,0,NULL,'cbr','cashibo-cacataibo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1381,0,NULL,'cbs','cashinahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1382,0,NULL,'cbt','chayahuita','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1383,0,NULL,'cbu','candoshi-shapra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1384,0,NULL,'cbv','cacua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1385,0,NULL,'cbw','kinabalian','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1386,0,NULL,'cby','carabayo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1387,0,NULL,'cca','cauca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1388,0,NULL,'ccc','chamicuro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1389,0,NULL,'ccd','cafundo creole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1390,0,NULL,'cce','chopi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1391,0,NULL,'ccg','samba daka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1392,0,NULL,'cch','atsam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1393,0,NULL,'ccj','kasanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1394,0,NULL,'ccl','cutchi-swahili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1395,0,NULL,'ccm','malaccan creole malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1396,0,NULL,'ccn','north caucasian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1397,0,NULL,'cco','comaltepec chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1398,0,NULL,'ccp','chakma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1399,0,NULL,'ccq','chaungtha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1400,0,NULL,'ccr','cacaopera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1401,0,NULL,'ccs','south caucasian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1402,0,NULL,'cda','choni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1403,0,NULL,'cdc','chadic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1404,0,NULL,'cdd','caddoan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1405,0,NULL,'cde','chenchu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1406,0,NULL,'cdf','chiru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1407,0,NULL,'cdg','chamari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1408,0,NULL,'cdh','chambeali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1409,0,NULL,'cdi','chodri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1410,0,NULL,'cdj','churahi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1411,0,NULL,'cdm','chepang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1412,0,NULL,'cdn','chaudangsi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1413,0,NULL,'cdo','min dong chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(1414,0,NULL,'cdr','cinda-regi-tiyal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1415,0,NULL,'cds','chadian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1416,0,NULL,'cdy','chadong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1417,0,NULL,'cdz','koda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1418,0,NULL,'cea','lower chehalis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1419,0,NULL,'ceb','cebuano','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1420,0,NULL,'ceg','chamacoco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1421,0,NULL,'cel','celtic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1422,0,NULL,'cen','cen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1423,0,NULL,'cet','centúúm','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1424,0,NULL,'cfa','dijim-bwilim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1425,0,NULL,'cfd','cara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1426,0,NULL,'cfg','como karim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1427,0,NULL,'cfm','falam chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1428,0,NULL,'cga','changriwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1429,0,NULL,'cgc','kagayanen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1430,0,NULL,'cgg','chiga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1431,0,NULL,'cgk','chocangacakha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1432,0,NULL,'chb','chibcha','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1433,0,NULL,'chc','catawba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1434,0,NULL,'chd','highland oaxaca chontal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1435,0,NULL,'chf','tabasco chontal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1436,0,NULL,'chg','chagatai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1437,0,NULL,'chh','chinook','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1438,0,NULL,'chj','ojitlán chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1439,0,NULL,'chk','chuukese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1440,0,NULL,'chl','cahuilla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1441,0,NULL,'chm','mari (russia)','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(1442,0,NULL,'chn','chinook jargon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1443,0,NULL,'cho','choctaw','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1444,0,NULL,'chp','chipewyan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1444,0,NULL,'chp','dene suline','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1445,0,NULL,'chq','quiotepec chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1446,0,NULL,'chr','cherokee','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1447,0,NULL,'cht','cholón','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1448,0,NULL,'chw','chuwabu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1449,0,NULL,'chx','chantyal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1450,0,NULL,'chy','cheyenne','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1451,0,NULL,'chz','ozumacín chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1452,0,NULL,'cia','cia-cia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1453,0,NULL,'cib','ci gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1454,0,NULL,'cic','chickasaw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1455,0,NULL,'cid','chimariko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1456,0,NULL,'cie','cineni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1457,0,NULL,'cih','chinali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1458,0,NULL,'cik','chitkuli kinnauri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1459,0,NULL,'cim','cimbrian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1460,0,NULL,'cin','cinta larga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1461,0,NULL,'cip','chiapanec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1462,0,NULL,'cir','tiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1463,0,NULL,'ciw','chippewa','1248825600',NULL,NULL,NULL,NULL,'oj',NULL,NULL); +INSERT INTO "iana_records" VALUES(1464,0,NULL,'ciy','chaima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1465,0,NULL,'cja','western cham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1466,0,NULL,'cje','chru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1467,0,NULL,'cjh','upper chehalis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1468,0,NULL,'cji','chamalal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1469,0,NULL,'cjk','chokwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1470,0,NULL,'cjm','eastern cham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1471,0,NULL,'cjn','chenapian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1472,0,NULL,'cjo','ashéninka pajonal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1473,0,NULL,'cjp','cabécar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1474,0,NULL,'cjr','chorotega','1248825600',1268265600,'mom',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1475,0,NULL,'cjs','shor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1476,0,NULL,'cjv','chuave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1477,0,NULL,'cjy','jinyu chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(1478,0,NULL,'cka','khumi awa chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1479,0,NULL,'ckb','central kurdish','1248825600',NULL,NULL,NULL,NULL,'ku',NULL,NULL); +INSERT INTO "iana_records" VALUES(1480,0,NULL,'ckh','chak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1481,0,NULL,'ckl','cibak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1482,0,NULL,'cko','anufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1483,0,NULL,'ckq','kajakse','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1484,0,NULL,'ckr','kairak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1485,0,NULL,'cks','tayo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1486,0,NULL,'ckt','chukot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1487,0,NULL,'cku','koasati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1488,0,NULL,'ckv','kavalan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1489,0,NULL,'ckx','caka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1490,0,NULL,'cky','cakfem-mushere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1491,0,NULL,'ckz','cakchiquel-quiché mixed language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1492,0,NULL,'cla','ron','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1493,0,NULL,'clc','chilcotin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1494,0,NULL,'cld','chaldean neo-aramaic','1248825600',NULL,NULL,NULL,NULL,'syr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1495,0,NULL,'cle','lealao chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1496,0,NULL,'clh','chilisso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1497,0,NULL,'cli','chakali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1498,0,NULL,'clk','idu-mishmi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1499,0,NULL,'cll','chala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1500,0,NULL,'clm','clallam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1501,0,NULL,'clo','lowland oaxaca chontal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1502,0,NULL,'clu','caluyanun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1503,0,NULL,'clw','chulym','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1504,0,NULL,'cly','eastern highland chatino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1505,0,NULL,'cma','maa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1506,0,NULL,'cmc','chamic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1507,0,NULL,'cme','cerma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1508,0,NULL,'cmg','classical mongolian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1509,0,NULL,'cmi','emberá-chamí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1510,0,NULL,'cmk','chimakum','1248825600',1268265600,'xch',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1511,0,NULL,'cml','campalagian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1512,0,NULL,'cmm','michigamea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1513,0,NULL,'cmn','mandarin chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(1514,0,NULL,'cmo','central mnong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1515,0,NULL,'cmr','mro chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1516,0,NULL,'cms','messapic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1517,0,NULL,'cmt','camtho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1518,0,NULL,'cna','changthang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1519,0,NULL,'cnb','chinbon chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1520,0,NULL,'cnc','côông','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1521,0,NULL,'cng','northern qiang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1522,0,NULL,'cnh','haka chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1523,0,NULL,'cni','asháninka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1524,0,NULL,'cnk','khumi chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1525,0,NULL,'cnl','lalana chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1526,0,NULL,'cno','con','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1527,0,NULL,'cns','central asmat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1528,0,NULL,'cnt','tepetotutla chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1529,0,NULL,'cnu','chenoua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1530,0,NULL,'cnw','ngawn chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1531,0,NULL,'cnx','middle cornish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1532,0,NULL,'coa','cocos islands malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(1533,0,NULL,'cob','chicomuceltec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1534,0,NULL,'coc','cocopa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1535,0,NULL,'cod','cocama-cocamilla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1536,0,NULL,'coe','koreguaje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1537,0,NULL,'cof','colorado','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1538,0,NULL,'cog','chong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1539,0,NULL,'coh','chichonyi-chidzihana-chikauma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1539,0,NULL,'coh','chonyi-dzihana-kauma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1540,0,NULL,'coj','cochimi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1541,0,NULL,'cok','santa teresa cora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1542,0,NULL,'col','columbia-wenatchi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1543,0,NULL,'com','comanche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1544,0,NULL,'con','cofán','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1545,0,NULL,'coo','comox','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1546,0,NULL,'cop','coptic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1547,0,NULL,'coq','coquille','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1548,0,NULL,'cot','caquinte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1549,0,NULL,'cou','wamey','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1550,0,NULL,'cov','cao miao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1551,0,NULL,'cow','cowlitz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1552,0,NULL,'cox','nanti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1553,0,NULL,'coy','coyaima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1554,0,NULL,'coz','chochotec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1555,0,NULL,'cpa','palantla chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1556,0,NULL,'cpb','ucayali-yurúa ashéninka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1557,0,NULL,'cpc','ajyíninka apurucayali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1558,0,NULL,'cpe','english-based creoles and pidgins','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1559,0,NULL,'cpf','french-based creoles and pidgins','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1560,0,NULL,'cpg','cappadocian greek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1561,0,NULL,'cpi','chinese pidgin english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1562,0,NULL,'cpn','cherepon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1563,0,NULL,'cpp','portuguese-based creoles and pidgins','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1564,0,NULL,'cps','capiznon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1565,0,NULL,'cpu','pichis ashéninka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1566,0,NULL,'cpx','pu-xian chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(1567,0,NULL,'cpy','south ucayali ashéninka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1568,0,NULL,'cqd','chuanqiandian cluster miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(1569,0,NULL,'cqu','chilean quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(1570,0,NULL,'cra','chara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1571,0,NULL,'crb','island carib','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1572,0,NULL,'crc','lonwolwol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1573,0,NULL,'crd','coeur d''alene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1574,0,NULL,'crf','caramanta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1575,0,NULL,'crg','michif','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1576,0,NULL,'crh','crimean tatar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1576,0,NULL,'crh','crimean turkish','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1577,0,NULL,'cri','sãotomense','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1578,0,NULL,'crj','southern east cree','1248825600',NULL,NULL,NULL,NULL,'cr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1579,0,NULL,'crk','plains cree','1248825600',NULL,NULL,NULL,NULL,'cr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1580,0,NULL,'crl','northern east cree','1248825600',NULL,NULL,NULL,NULL,'cr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1581,0,NULL,'crm','moose cree','1248825600',NULL,NULL,NULL,NULL,'cr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1582,0,NULL,'crn','el nayar cora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1583,0,NULL,'cro','crow','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1584,0,NULL,'crp','creoles and pidgins','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1585,0,NULL,'crq','iyo''wujwa chorote','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1586,0,NULL,'crr','carolina algonquian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1587,0,NULL,'crs','seselwa creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1588,0,NULL,'crt','iyojwa''ja chorote','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1589,0,NULL,'crv','chaura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1590,0,NULL,'crw','chrau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1591,0,NULL,'crx','carrier','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1592,0,NULL,'cry','cori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1593,0,NULL,'crz','cruzeño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1594,0,NULL,'csa','chiltepec chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1595,0,NULL,'csb','kashubian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1596,0,NULL,'csc','catalan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1596,0,NULL,'csc','lengua de señas catalana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1596,0,NULL,'csc','llengua de signes catalana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1597,0,NULL,'csd','chiangmai sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1598,0,NULL,'cse','czech sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1599,0,NULL,'csf','cuba sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1600,0,NULL,'csg','chilean sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1601,0,NULL,'csh','asho chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1602,0,NULL,'csi','coast miwok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1603,0,NULL,'csk','jola-kasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1604,0,NULL,'csl','chinese sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1605,0,NULL,'csm','central sierra miwok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1606,0,NULL,'csn','colombian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1607,0,NULL,'cso','sochiapam chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1607,0,NULL,'cso','sochiapan chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1608,0,NULL,'csq','croatia sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1609,0,NULL,'csr','costa rican sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1610,0,NULL,'css','southern ohlone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1611,0,NULL,'cst','northern ohlone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1612,0,NULL,'csu','central sudanic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1613,0,NULL,'csw','swampy cree','1248825600',NULL,NULL,NULL,NULL,'cr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1614,0,NULL,'csy','siyin chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1615,0,NULL,'csz','coos','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1616,0,NULL,'cta','tataltepec chatino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1617,0,NULL,'ctc','chetco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1618,0,NULL,'ctd','tedim chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1619,0,NULL,'cte','tepinapa chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1620,0,NULL,'ctg','chittagonian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1621,0,NULL,'ctl','tlacoatzintepec chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1622,0,NULL,'ctm','chitimacha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1623,0,NULL,'ctn','chhintange','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1624,0,NULL,'cto','emberá-catío','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1625,0,NULL,'ctp','western highland chatino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1626,0,NULL,'cts','northern catanduanes bicolano','1248825600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(1627,0,NULL,'ctt','wayanad chetti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1628,0,NULL,'ctu','chol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1629,0,NULL,'ctz','zacatepec chatino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1630,0,NULL,'cua','cua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1631,0,NULL,'cub','cubeo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1632,0,NULL,'cuc','usila chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1633,0,NULL,'cug','cung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1634,0,NULL,'cuh','chuka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1634,0,NULL,'cuh','gichuka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1635,0,NULL,'cui','cuiba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1636,0,NULL,'cuj','mashco piro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1637,0,NULL,'cuk','san blas kuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1638,0,NULL,'cul','culina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1638,0,NULL,'cul','kulina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1639,0,NULL,'cum','cumeral','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1640,0,NULL,'cuo','cumanagoto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1641,0,NULL,'cup','cupeño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1642,0,NULL,'cuq','cun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1643,0,NULL,'cur','chhulung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1644,0,NULL,'cus','cushitic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1645,0,NULL,'cut','teutila cuicatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1646,0,NULL,'cuu','tai ya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1647,0,NULL,'cuv','cuvok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1648,0,NULL,'cuw','chukwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1649,0,NULL,'cux','tepeuxila cuicatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1650,0,NULL,'cvg','chug','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1651,0,NULL,'cvn','valle nacional chinantec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1652,0,NULL,'cwa','kabwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1653,0,NULL,'cwb','maindo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1654,0,NULL,'cwd','woods cree','1248825600',NULL,NULL,NULL,NULL,'cr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1655,0,NULL,'cwe','kwere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1656,0,NULL,'cwg','cheq wong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1656,0,NULL,'cwg','chewong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1657,0,NULL,'cwt','kuwaataay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1658,0,NULL,'cya','nopala chatino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1659,0,NULL,'cyb','cayubaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1660,0,NULL,'cyo','cuyonon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1661,0,NULL,'czh','huizhou chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(1662,0,NULL,'czk','knaanic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1663,0,NULL,'czn','zenzontepec chatino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1664,0,NULL,'czo','min zhong chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(1665,0,NULL,'czt','zotung chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1666,0,NULL,'daa','dangaléat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1667,0,NULL,'dac','dambi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1668,0,NULL,'dad','marik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1669,0,NULL,'dae','duupa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1670,0,NULL,'daf','dan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1671,0,NULL,'dag','dagbani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1672,0,NULL,'dah','gwahatike','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1673,0,NULL,'dai','day','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1674,0,NULL,'daj','dar fur daju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1675,0,NULL,'dak','dakota','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1676,0,NULL,'dal','dahalo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1677,0,NULL,'dam','damakawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1678,0,NULL,'dao','daai chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1679,0,NULL,'dap','nisi (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1680,0,NULL,'daq','dandami maria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1681,0,NULL,'dar','dargwa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1682,0,NULL,'das','daho-doo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1683,0,NULL,'dau','dar sila daju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1684,0,NULL,'dav','dawida','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1684,0,NULL,'dav','taita','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1685,0,NULL,'daw','davawenyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1686,0,NULL,'dax','dayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1687,0,NULL,'day','land dayak languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1688,0,NULL,'daz','dao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1689,0,NULL,'dba','bangi me','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1690,0,NULL,'dbb','deno','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1691,0,NULL,'dbd','dadiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1692,0,NULL,'dbe','dabe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1693,0,NULL,'dbf','edopi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1694,0,NULL,'dbg','dogul dom dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1695,0,NULL,'dbi','doka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1696,0,NULL,'dbj','ida''an','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1697,0,NULL,'dbl','dyirbal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1698,0,NULL,'dbm','duguri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1699,0,NULL,'dbn','duriankere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1700,0,NULL,'dbo','dulbu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1701,0,NULL,'dbp','duwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1702,0,NULL,'dbq','daba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1703,0,NULL,'dbr','dabarre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1704,0,NULL,'dbu','bondum dom dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1705,0,NULL,'dbv','dungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1706,0,NULL,'dby','dibiyaso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1707,0,NULL,'dcc','deccan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1708,0,NULL,'dcr','negerhollands','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1709,0,NULL,'ddd','dongotono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1710,0,NULL,'dde','doondo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1711,0,NULL,'ddg','fataluku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1712,0,NULL,'ddi','west goodenough','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1713,0,NULL,'ddj','jaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1714,0,NULL,'ddn','dendi (benin)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1715,0,NULL,'ddo','dido','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1716,0,NULL,'dds','donno so dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1717,0,NULL,'ddw','dawera-daweloor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1718,0,NULL,'dec','dagik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1719,0,NULL,'ded','dedua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1720,0,NULL,'dee','dewoin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1721,0,NULL,'def','dezfuli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1722,0,NULL,'deg','degema','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1723,0,NULL,'deh','dehwari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1724,0,NULL,'dei','demisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1725,0,NULL,'dek','dek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1726,0,NULL,'del','delaware','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(1727,0,NULL,'dem','dem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1728,0,NULL,'den','slave (athapascan)','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(1729,0,NULL,'dep','pidgin delaware','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1730,0,NULL,'deq','dendi (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1731,0,NULL,'der','deori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1732,0,NULL,'des','desano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1733,0,NULL,'dev','domung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1734,0,NULL,'dez','dengese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1735,0,NULL,'dga','southern dagaare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1736,0,NULL,'dgb','bunoge dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1737,0,NULL,'dgc','casiguran dumagat agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1738,0,NULL,'dgd','dagaari dioula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1739,0,NULL,'dge','degenan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1740,0,NULL,'dgg','doga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1741,0,NULL,'dgh','dghwede','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1742,0,NULL,'dgi','northern dagara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1743,0,NULL,'dgk','dagba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1744,0,NULL,'dgn','dagoman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1745,0,NULL,'dgo','dogri (individual language)','1248825600',NULL,NULL,NULL,NULL,'doi',NULL,NULL); +INSERT INTO "iana_records" VALUES(1746,0,NULL,'dgr','dogrib','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1747,0,NULL,'dgs','dogoso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1748,0,NULL,'dgu','degaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1749,0,NULL,'dgx','doghoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1750,0,NULL,'dgz','daga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1751,0,NULL,'dha','dhanwar (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1752,0,NULL,'dhd','dhundari','1248825600',NULL,NULL,NULL,NULL,'mwr',NULL,NULL); +INSERT INTO "iana_records" VALUES(1753,0,NULL,'dhg','dhangu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1754,0,NULL,'dhi','dhimal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1755,0,NULL,'dhl','dhalandji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1756,0,NULL,'dhm','zemba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1757,0,NULL,'dhn','dhanki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1758,0,NULL,'dho','dhodia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1759,0,NULL,'dhr','dhargari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1760,0,NULL,'dhs','dhaiso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1761,0,NULL,'dhu','dhurga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1762,0,NULL,'dhv','dehu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1763,0,NULL,'dhw','dhanwar (nepal)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1764,0,NULL,'dia','dia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1765,0,NULL,'dib','south central dinka','1248825600',NULL,NULL,NULL,NULL,'din',NULL,NULL); +INSERT INTO "iana_records" VALUES(1766,0,NULL,'dic','lakota dida','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1767,0,NULL,'did','didinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1768,0,NULL,'dif','dieri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1769,0,NULL,'dig','chidigo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1769,0,NULL,'dig','digo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1770,0,NULL,'dih','kumiai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1771,0,NULL,'dii','dimbong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1772,0,NULL,'dij','dai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1773,0,NULL,'dik','southwestern dinka','1248825600',NULL,NULL,NULL,NULL,'din',NULL,NULL); +INSERT INTO "iana_records" VALUES(1774,0,NULL,'dil','dilling','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1775,0,NULL,'dim','dime','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1776,0,NULL,'din','dinka','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(1777,0,NULL,'dio','dibo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1778,0,NULL,'dip','northeastern dinka','1248825600',NULL,NULL,NULL,NULL,'din',NULL,NULL); +INSERT INTO "iana_records" VALUES(1779,0,NULL,'diq','dimli (individual language)','1248825600',NULL,NULL,NULL,NULL,'zza',NULL,NULL); +INSERT INTO "iana_records" VALUES(1780,0,NULL,'dir','dirim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1781,0,NULL,'dis','dimasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1782,0,NULL,'dit','dirari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1783,0,NULL,'diu','diriku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1784,0,NULL,'diw','northwestern dinka','1248825600',NULL,NULL,NULL,NULL,'din',NULL,NULL); +INSERT INTO "iana_records" VALUES(1785,0,NULL,'dix','dixon reef','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1786,0,NULL,'diy','diuwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1787,0,NULL,'diz','ding','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1788,0,NULL,'djb','djinba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1789,0,NULL,'djc','dar daju daju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1790,0,NULL,'djd','djamindjung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1791,0,NULL,'dje','zarma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1792,0,NULL,'djf','djangun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1793,0,NULL,'dji','djinang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1794,0,NULL,'djj','djeebbana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1795,0,NULL,'djk','businenge tongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1795,0,NULL,'djk','eastern maroon creole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1795,0,NULL,'djk','nenge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1796,0,NULL,'djl','djiwarli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1797,0,NULL,'djm','jamsay dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1798,0,NULL,'djn','djauan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1799,0,NULL,'djo','jangkang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1800,0,NULL,'djr','djambarrpuyngu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1801,0,NULL,'dju','kapriman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1802,0,NULL,'djw','djawi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1803,0,NULL,'dka','dakpakha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1804,0,NULL,'dkk','dakka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1805,0,NULL,'dkl','kolum so dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1806,0,NULL,'dkr','kuijau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1807,0,NULL,'dks','southeastern dinka','1248825600',NULL,NULL,NULL,NULL,'din',NULL,NULL); +INSERT INTO "iana_records" VALUES(1808,0,NULL,'dkx','mazagway','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1809,0,NULL,'dlg','dolgan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1810,0,NULL,'dlm','dalmatian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1811,0,NULL,'dln','darlong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1812,0,NULL,'dma','duma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1813,0,NULL,'dmc','dimir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1814,0,NULL,'dme','dugwor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1815,0,NULL,'dmg','upper kinabatangan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1816,0,NULL,'dmk','domaaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1817,0,NULL,'dml','dameli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1818,0,NULL,'dmm','dama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1819,0,NULL,'dmn','mande languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1820,0,NULL,'dmo','kemezung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1821,0,NULL,'dmr','east damar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1822,0,NULL,'dms','dampelas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1823,0,NULL,'dmu','dubu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1823,0,NULL,'dmu','tebi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1824,0,NULL,'dmv','dumpas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1825,0,NULL,'dmx','dema','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1826,0,NULL,'dmy','demta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1826,0,NULL,'dmy','sowari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1827,0,NULL,'dna','upper grand valley dani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1828,0,NULL,'dnd','daonda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1829,0,NULL,'dne','ndendeule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1830,0,NULL,'dng','dungan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1831,0,NULL,'dni','lower grand valley dani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1832,0,NULL,'dnk','dengka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1833,0,NULL,'dnn','dzùùngoo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1834,0,NULL,'dnr','danaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1835,0,NULL,'dnt','mid grand valley dani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1836,0,NULL,'dnu','danau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1837,0,NULL,'dnw','western dani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1838,0,NULL,'dny','dení','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1839,0,NULL,'doa','dom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1840,0,NULL,'dob','dobu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1841,0,NULL,'doc','northern dong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1842,0,NULL,'doe','doe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1843,0,NULL,'dof','domu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1844,0,NULL,'doh','dong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1845,0,NULL,'doi','dogri (macrolanguage)','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(1846,0,NULL,'dok','dondo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1847,0,NULL,'dol','doso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1848,0,NULL,'don','toura (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1849,0,NULL,'doo','dongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1850,0,NULL,'dop','lukpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1851,0,NULL,'doq','dominican sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1852,0,NULL,'dor','dori''o','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1853,0,NULL,'dos','dogosé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1854,0,NULL,'dot','dass','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1855,0,NULL,'dov','dombe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1856,0,NULL,'dow','doyayo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1857,0,NULL,'dox','bussa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1858,0,NULL,'doy','dompo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1859,0,NULL,'doz','dorze','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1860,0,NULL,'dpp','papar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1861,0,NULL,'dra','dravidian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1862,0,NULL,'drb','dair','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1863,0,NULL,'drd','darmiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1864,0,NULL,'dre','dolpo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1865,0,NULL,'drg','rungus','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1866,0,NULL,'drh','darkhat','1248825600',1268265600,'khk',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1867,0,NULL,'dri','c''lela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1868,0,NULL,'drl','darling','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1869,0,NULL,'drn','west damar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1870,0,NULL,'dro','daro-matu melanau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1871,0,NULL,'drq','dura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1872,0,NULL,'drr','dororo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1873,0,NULL,'drs','gedeo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1874,0,NULL,'drt','drents','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1875,0,NULL,'dru','rukai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1876,0,NULL,'drw','darwazi','1248825600',1268265600,'prs',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1877,0,NULL,'dry','darai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1878,0,NULL,'dsb','lower sorbian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1879,0,NULL,'dse','dutch sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1880,0,NULL,'dsh','daasanach','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1881,0,NULL,'dsi','disa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1882,0,NULL,'dsl','danish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1883,0,NULL,'dsn','dusner','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1884,0,NULL,'dso','desiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1885,0,NULL,'dsq','tadaksahak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1886,0,NULL,'dta','daur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1887,0,NULL,'dtb','labuk-kinabatangan kadazan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1888,0,NULL,'dti','ana tinga dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1889,0,NULL,'dtk','tene kan dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1890,0,NULL,'dtm','tomo kan dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1891,0,NULL,'dtp','central dusun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1892,0,NULL,'dtr','lotud','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1893,0,NULL,'dts','toro so dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1894,0,NULL,'dtt','toro tegu dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1895,0,NULL,'dtu','tebul ure dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1896,0,NULL,'dua','duala','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1897,0,NULL,'dub','dubli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1898,0,NULL,'duc','duna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1899,0,NULL,'dud','hun-saare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1900,0,NULL,'due','umiray dumaget agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1901,0,NULL,'duf','dumbea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1902,0,NULL,'dug','chiduruma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1902,0,NULL,'dug','duruma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1903,0,NULL,'duh','dungra bhil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1904,0,NULL,'dui','dumun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1905,0,NULL,'duj','dhuwal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1906,0,NULL,'duk','duduela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1907,0,NULL,'dul','alabat island agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1908,0,NULL,'dum','middle dutch (ca. 1050-1350)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1909,0,NULL,'dun','dusun deyah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1910,0,NULL,'duo','dupaninan agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1911,0,NULL,'dup','duano','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(1912,0,NULL,'duq','dusun malang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1913,0,NULL,'dur','dii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1914,0,NULL,'dus','dumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1915,0,NULL,'duu','drung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1916,0,NULL,'duv','duvle','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1917,0,NULL,'duw','dusun witu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1918,0,NULL,'dux','duungooma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1919,0,NULL,'duy','dicamay agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1920,0,NULL,'duz','duli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1921,0,NULL,'dva','duau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1922,0,NULL,'dwa','diri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1923,0,NULL,'dwl','walo kumbe dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1924,0,NULL,'dwr','dawro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1925,0,NULL,'dws','dutton world speedwords','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1926,0,NULL,'dww','dawawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1927,0,NULL,'dya','dyan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1928,0,NULL,'dyb','dyaberdyaber','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1929,0,NULL,'dyd','dyugun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1930,0,NULL,'dyg','villa viciosa agta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1931,0,NULL,'dyi','djimini senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1932,0,NULL,'dym','yanda dom dogon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1933,0,NULL,'dyn','dyangadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1934,0,NULL,'dyo','jola-fonyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1935,0,NULL,'dyu','dyula','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1936,0,NULL,'dyy','dyaabugay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1937,0,NULL,'dza','tunzu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1938,0,NULL,'dzd','daza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1939,0,NULL,'dzg','dazaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1940,0,NULL,'dzl','dzalakha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1941,0,NULL,'dzn','dzando','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1942,0,NULL,'ebg','ebughu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1943,0,NULL,'ebk','eastern bontok','1268265600',NULL,NULL,NULL,NULL,'bnc',NULL,NULL); +INSERT INTO "iana_records" VALUES(1944,0,NULL,'ebo','teke-ebo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1945,0,NULL,'ebr','ebrié','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1946,0,NULL,'ebu','embu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1946,0,NULL,'ebu','kiembu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1947,0,NULL,'ecr','eteocretan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1948,0,NULL,'ecs','ecuadorian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1949,0,NULL,'ecy','eteocypriot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1950,0,NULL,'eee','e','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1951,0,NULL,'efa','efai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1952,0,NULL,'efe','efe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1953,0,NULL,'efi','efik','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1954,0,NULL,'ega','ega','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1955,0,NULL,'egl','emilian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1956,0,NULL,'ego','eggon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1957,0,NULL,'egx','egyptian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(1958,0,NULL,'egy','egyptian (ancient)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1959,0,NULL,'ehu','ehueun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1960,0,NULL,'eip','eipomek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1961,0,NULL,'eit','eitiep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1962,0,NULL,'eiv','askopan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1963,0,NULL,'eja','ejamat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1964,0,NULL,'eka','ekajuk','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1965,0,NULL,'eke','ekit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1966,0,NULL,'ekg','ekari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1967,0,NULL,'eki','eki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1968,0,NULL,'ekk','standard estonian','1248825600',NULL,NULL,NULL,NULL,'et',NULL,NULL); +INSERT INTO "iana_records" VALUES(1969,0,NULL,'ekl','kol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1970,0,NULL,'ekm','elip','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1971,0,NULL,'eko','koti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1972,0,NULL,'ekp','ekpeye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1973,0,NULL,'ekr','yace','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1974,0,NULL,'eky','eastern kayah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1975,0,NULL,'ele','elepi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1976,0,NULL,'elh','el hugeirat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1977,0,NULL,'eli','nding','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1978,0,NULL,'elk','elkei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1979,0,NULL,'elm','eleme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1980,0,NULL,'elo','el molo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1981,0,NULL,'elp','elpaputih','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1982,0,NULL,'elu','elu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1983,0,NULL,'elx','elamite','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1984,0,NULL,'ema','emai-iuleha-ora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1985,0,NULL,'emb','embaloh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1986,0,NULL,'eme','emerillon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1987,0,NULL,'emg','eastern meohang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1988,0,NULL,'emi','mussau-emira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1989,0,NULL,'emk','eastern maninkakan','1248825600',NULL,NULL,NULL,NULL,'man',NULL,NULL); +INSERT INTO "iana_records" VALUES(1990,0,NULL,'emm','mamulique','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1991,0,NULL,'emn','eman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1992,0,NULL,'emo','emok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1993,0,NULL,'emp','northern emberá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1994,0,NULL,'ems','pacific gulf yupik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1995,0,NULL,'emu','eastern muria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1996,0,NULL,'emw','emplawas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1997,0,NULL,'emx','erromintxela','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1998,0,NULL,'emy','epigraphic mayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(1999,0,NULL,'ena','apali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2000,0,NULL,'enb','markweeta','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(2001,0,NULL,'enc','en','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2002,0,NULL,'end','ende','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2003,0,NULL,'enf','forest enets','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2004,0,NULL,'enh','tundra enets','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2005,0,NULL,'enm','middle english (1100-1500)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2006,0,NULL,'enn','engenni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2007,0,NULL,'eno','enggano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2008,0,NULL,'enq','enga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2009,0,NULL,'enr','emem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2009,0,NULL,'enr','emumu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2010,0,NULL,'enu','enu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2011,0,NULL,'env','enwan (edu state)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2012,0,NULL,'enw','enwan (akwa ibom state)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2013,0,NULL,'eot','beti (côte d''ivoire)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2014,0,NULL,'epi','epie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2015,0,NULL,'era','eravallan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2016,0,NULL,'erg','sie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2017,0,NULL,'erh','eruwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2018,0,NULL,'eri','ogea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2019,0,NULL,'erk','south efate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2020,0,NULL,'ero','horpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2021,0,NULL,'err','erre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2022,0,NULL,'ers','ersu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2023,0,NULL,'ert','eritai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2024,0,NULL,'erw','erokwanas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2025,0,NULL,'ese','ese ejja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2026,0,NULL,'esh','eshtehardi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2027,0,NULL,'esi','north alaskan inupiatun','1248825600',NULL,NULL,NULL,NULL,'ik',NULL,NULL); +INSERT INTO "iana_records" VALUES(2028,0,NULL,'esk','northwest alaska inupiatun','1248825600',NULL,NULL,NULL,NULL,'ik',NULL,NULL); +INSERT INTO "iana_records" VALUES(2029,0,NULL,'esl','egypt sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2030,0,NULL,'esm','esuma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2031,0,NULL,'esn','salvadoran sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2032,0,NULL,'eso','estonian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2033,0,NULL,'esq','esselen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2034,0,NULL,'ess','central siberian yupik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2035,0,NULL,'esu','central yupik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2036,0,NULL,'esx','eskimo-aleut languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2037,0,NULL,'etb','etebi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2038,0,NULL,'etc','etchemin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2039,0,NULL,'eth','ethiopian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2040,0,NULL,'etn','eton (vanuatu)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2041,0,NULL,'eto','eton (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2042,0,NULL,'etr','edolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2043,0,NULL,'ets','yekhee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2044,0,NULL,'ett','etruscan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2045,0,NULL,'etu','ejagham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2046,0,NULL,'etx','eten','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2047,0,NULL,'etz','semimi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2048,0,NULL,'euq','basque (family)','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2049,0,NULL,'eve','even','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2050,0,NULL,'evh','uvbie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2051,0,NULL,'evn','evenki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2052,0,NULL,'ewo','ewondo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2053,0,NULL,'ext','extremaduran','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2054,0,NULL,'eya','eyak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2055,0,NULL,'eyo','keiyo','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(2056,0,NULL,'eze','uzekwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2057,0,NULL,'faa','fasu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2058,0,NULL,'fab','fa d''ambu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2059,0,NULL,'fad','wagi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2060,0,NULL,'faf','fagani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2061,0,NULL,'fag','finongan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2062,0,NULL,'fah','baissa fali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2063,0,NULL,'fai','faiwol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2064,0,NULL,'faj','faita','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2065,0,NULL,'fak','fang (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2066,0,NULL,'fal','south fali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2067,0,NULL,'fam','fam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2068,0,NULL,'fan','fang (equatorial guinea)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2069,0,NULL,'fap','palor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2070,0,NULL,'far','fataleka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2071,0,NULL,'fat','fanti','1129420800',NULL,NULL,NULL,NULL,'ak',NULL,NULL); +INSERT INTO "iana_records" VALUES(2072,0,NULL,'fau','fayu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2073,0,NULL,'fax','fala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2074,0,NULL,'fay','southwestern fars','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2075,0,NULL,'faz','northwestern fars','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2076,0,NULL,'fbl','west albay bikol','1268265600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(2077,0,NULL,'fcs','quebec sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2078,0,NULL,'fer','feroge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2079,0,NULL,'ffi','foia foia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2080,0,NULL,'ffm','maasina fulfulde','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2081,0,NULL,'fgr','fongoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2082,0,NULL,'fia','nobiin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2083,0,NULL,'fie','fyer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2084,0,NULL,'fil','filipino','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2084,0,NULL,'fil','pilipino','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2085,0,NULL,'fip','fipa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2086,0,NULL,'fir','firan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2087,0,NULL,'fit','tornedalen finnish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2088,0,NULL,'fiu','finno-ugrian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2089,0,NULL,'fiw','fiwaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2090,0,NULL,'fkv','kven finnish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2091,0,NULL,'fla','kalispel-pend d''oreille','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2092,0,NULL,'flh','foau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2093,0,NULL,'fli','fali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2094,0,NULL,'fll','north fali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2095,0,NULL,'fln','flinders island','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2096,0,NULL,'flr','fuliiru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2097,0,NULL,'fly','tsotsitaal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2098,0,NULL,'fmp','fe''fe''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2099,0,NULL,'fmu','far western muria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2100,0,NULL,'fng','fanagalo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2101,0,NULL,'fni','fania','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2102,0,NULL,'fod','foodo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2103,0,NULL,'foi','foi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2104,0,NULL,'fom','foma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2105,0,NULL,'fon','fon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2106,0,NULL,'for','fore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2107,0,NULL,'fos','siraya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2108,0,NULL,'fox','formosan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2109,0,NULL,'fpe','fernando po creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2110,0,NULL,'fqs','fas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2111,0,NULL,'frc','cajun french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2112,0,NULL,'frd','fordata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2113,0,NULL,'frk','frankish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2114,0,NULL,'frm','middle french (ca. 1400-1600)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2115,0,NULL,'fro','old french (842-ca. 1400)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2116,0,NULL,'frp','arpitan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2116,0,NULL,'frp','francoprovençal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2117,0,NULL,'frq','forak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2118,0,NULL,'frr','northern frisian','1141776000',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2119,0,NULL,'frs','eastern frisian','1141776000',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2120,0,NULL,'frt','fortsenal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2121,0,NULL,'fse','finnish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2122,0,NULL,'fsl','french sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2123,0,NULL,'fss','finland-swedish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2123,0,NULL,'fss','finlandssvenskt teckenspråk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2123,0,NULL,'fss','suomenruotsalainen viittomakieli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2124,0,NULL,'fub','adamawa fulfulde','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2125,0,NULL,'fuc','pulaar','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2126,0,NULL,'fud','east futuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2127,0,NULL,'fue','borgu fulfulde','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2128,0,NULL,'fuf','pular','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2129,0,NULL,'fuh','western niger fulfulde','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2130,0,NULL,'fui','bagirmi fulfulde','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2131,0,NULL,'fuj','ko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2132,0,NULL,'fum','fum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2133,0,NULL,'fun','fulniô','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2134,0,NULL,'fuq','central-eastern niger fulfulde','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2135,0,NULL,'fur','friulian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2136,0,NULL,'fut','futuna-aniwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2137,0,NULL,'fuu','furu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2138,0,NULL,'fuv','nigerian fulfulde','1248825600',NULL,NULL,NULL,NULL,'ff',NULL,NULL); +INSERT INTO "iana_records" VALUES(2139,0,NULL,'fuy','fuyug','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2140,0,NULL,'fvr','fur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2141,0,NULL,'fwa','fwâi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2142,0,NULL,'fwe','fwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2143,0,NULL,'gaa','ga','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2144,0,NULL,'gab','gabri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2145,0,NULL,'gac','mixed great andamanese','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2146,0,NULL,'gad','gaddang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2147,0,NULL,'gae','guarequena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2148,0,NULL,'gaf','gende','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2149,0,NULL,'gag','gagauz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2150,0,NULL,'gah','alekano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2151,0,NULL,'gai','borei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2152,0,NULL,'gaj','gadsup','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2153,0,NULL,'gak','gamkonora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2154,0,NULL,'gal','galoli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2155,0,NULL,'gam','kandawo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2156,0,NULL,'gan','gan chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(2157,0,NULL,'gao','gants','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2158,0,NULL,'gap','gal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2159,0,NULL,'gaq','gata''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2160,0,NULL,'gar','galeya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2161,0,NULL,'gas','adiwasi garasia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2162,0,NULL,'gat','kenati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2163,0,NULL,'gau','mudhili gadaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2164,0,NULL,'gav','gabutamon','1248825600',1268265600,'dev',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2165,0,NULL,'gaw','nobonob','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2166,0,NULL,'gax','borana-arsi-guji oromo','1248825600',NULL,NULL,NULL,NULL,'om',NULL,NULL); +INSERT INTO "iana_records" VALUES(2167,0,NULL,'gay','gayo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2168,0,NULL,'gaz','west central oromo','1248825600',NULL,NULL,NULL,NULL,'om',NULL,NULL); +INSERT INTO "iana_records" VALUES(2169,0,NULL,'gba','gbaya (central african republic)','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(2170,0,NULL,'gbb','kaytetye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2171,0,NULL,'gbc','garawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2172,0,NULL,'gbd','karadjeri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2173,0,NULL,'gbe','niksek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2174,0,NULL,'gbf','gaikundi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2175,0,NULL,'gbg','gbanziri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2176,0,NULL,'gbh','defi gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2177,0,NULL,'gbi','galela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2178,0,NULL,'gbj','bodo gadaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2179,0,NULL,'gbk','gaddi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2180,0,NULL,'gbl','gamit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2181,0,NULL,'gbm','garhwali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2182,0,NULL,'gbn','mo''da','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2183,0,NULL,'gbo','northern grebo','1248825600',NULL,NULL,NULL,NULL,'grb',NULL,NULL); +INSERT INTO "iana_records" VALUES(2184,0,NULL,'gbp','gbaya-bossangoa','1248825600',NULL,NULL,NULL,NULL,'gba',NULL,NULL); +INSERT INTO "iana_records" VALUES(2185,0,NULL,'gbq','gbaya-bozoum','1248825600',NULL,NULL,NULL,NULL,'gba',NULL,NULL); +INSERT INTO "iana_records" VALUES(2186,0,NULL,'gbr','gbagyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2187,0,NULL,'gbs','gbesi gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2188,0,NULL,'gbu','gagadu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2189,0,NULL,'gbv','gbanu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2190,0,NULL,'gbx','eastern xwla gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2191,0,NULL,'gby','gbari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2192,0,NULL,'gbz','zoroastrian dari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2193,0,NULL,'gcc','mali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2194,0,NULL,'gcd','ganggalida','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2195,0,NULL,'gce','galice','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2196,0,NULL,'gcf','guadeloupean creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2197,0,NULL,'gcl','grenadian creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2198,0,NULL,'gcn','gaina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2199,0,NULL,'gcr','guianese creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2200,0,NULL,'gct','colonia tovar german','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2201,0,NULL,'gda','gade lohar','1248825600',NULL,NULL,NULL,NULL,'raj',NULL,NULL); +INSERT INTO "iana_records" VALUES(2202,0,NULL,'gdb','pottangi ollar gadaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2203,0,NULL,'gdc','gugu badhun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2204,0,NULL,'gdd','gedaged','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2205,0,NULL,'gde','gude','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2206,0,NULL,'gdf','guduf-gava','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2207,0,NULL,'gdg','ga''dang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2208,0,NULL,'gdh','gadjerawang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2209,0,NULL,'gdi','gundi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2210,0,NULL,'gdj','gurdjar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2211,0,NULL,'gdk','gadang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2212,0,NULL,'gdl','dirasha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2213,0,NULL,'gdm','laal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2214,0,NULL,'gdn','umanakaina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2215,0,NULL,'gdo','ghodoberi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2216,0,NULL,'gdq','mehri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2217,0,NULL,'gdr','wipi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2218,0,NULL,'gdu','gudu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2219,0,NULL,'gdx','godwari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2220,0,NULL,'gea','geruma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2221,0,NULL,'geb','kire','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2222,0,NULL,'gec','gboloo grebo','1248825600',NULL,NULL,NULL,NULL,'grb',NULL,NULL); +INSERT INTO "iana_records" VALUES(2223,0,NULL,'ged','gade','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2224,0,NULL,'geg','gengle','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2225,0,NULL,'geh','hutterisch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2225,0,NULL,'geh','hutterite german','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2226,0,NULL,'gei','gebe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2227,0,NULL,'gej','gen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2228,0,NULL,'gek','yiwom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2229,0,NULL,'gel','kag-fer-jiir-koor-ror-us-zuksun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2230,0,NULL,'gem','germanic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2231,0,NULL,'geq','geme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2232,0,NULL,'ges','geser-gorom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2233,0,NULL,'gew','gera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2234,0,NULL,'gex','garre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2235,0,NULL,'gey','enya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2236,0,NULL,'gez','geez','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2237,0,NULL,'gfk','patpatar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2238,0,NULL,'gft','gafat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2239,0,NULL,'gga','gao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2240,0,NULL,'ggb','gbii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2241,0,NULL,'ggd','gugadj','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2242,0,NULL,'gge','guragone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2243,0,NULL,'ggg','gurgula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2244,0,NULL,'ggk','kungarakany','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2245,0,NULL,'ggl','ganglau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2246,0,NULL,'ggn','eastern gurung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2247,0,NULL,'ggo','southern gondi','1248825600',NULL,NULL,NULL,NULL,'gon',NULL,NULL); +INSERT INTO "iana_records" VALUES(2248,0,NULL,'ggr','aghu tharnggalu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2249,0,NULL,'ggt','gitua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2250,0,NULL,'ggu','gagu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2251,0,NULL,'ggw','gogodala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2252,0,NULL,'gha','ghadamès','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2253,0,NULL,'ghc','hiberno-scottish gaelic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2254,0,NULL,'ghe','southern ghale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2255,0,NULL,'ghh','northern ghale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2256,0,NULL,'ghk','geko karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2257,0,NULL,'ghl','ghulfan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2258,0,NULL,'ghn','ghanongga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2259,0,NULL,'gho','ghomara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2260,0,NULL,'ghr','ghera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2261,0,NULL,'ghs','guhu-samane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2262,0,NULL,'ght','kutang ghale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2263,0,NULL,'gia','kitja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2264,0,NULL,'gib','gibanawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2265,0,NULL,'gic','gail','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2266,0,NULL,'gid','gidar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2267,0,NULL,'gig','goaria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2268,0,NULL,'gil','gilbertese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2269,0,NULL,'gim','gimi (eastern highlands)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2270,0,NULL,'gin','hinukh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2271,0,NULL,'gio','gelao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2272,0,NULL,'gip','gimi (west new britain)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2273,0,NULL,'giq','green gelao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2274,0,NULL,'gir','red gelao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2275,0,NULL,'gis','north giziga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2276,0,NULL,'git','gitxsan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2277,0,NULL,'giw','white gelao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2278,0,NULL,'gix','gilima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2279,0,NULL,'giy','giyug','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2280,0,NULL,'giz','south giziga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2281,0,NULL,'gji','geji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2282,0,NULL,'gjk','kachi koli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2283,0,NULL,'gjn','gonja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2284,0,NULL,'gju','gujari','1248825600',NULL,NULL,NULL,NULL,'raj',NULL,NULL); +INSERT INTO "iana_records" VALUES(2285,0,NULL,'gka','guya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2286,0,NULL,'gke','ndai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2287,0,NULL,'gkn','gokana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2288,0,NULL,'gkp','guinea kpelle','1248825600',NULL,NULL,NULL,NULL,'kpe',NULL,NULL); +INSERT INTO "iana_records" VALUES(2289,0,NULL,'glc','bon gula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2290,0,NULL,'gld','nanai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2291,0,NULL,'glh','northwest pashayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2292,0,NULL,'gli','guliguli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2293,0,NULL,'glj','gula iro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2294,0,NULL,'glk','gilaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2295,0,NULL,'glo','galambu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2296,0,NULL,'glr','glaro-twabo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2297,0,NULL,'glu','gula (chad)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2298,0,NULL,'glw','glavda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2299,0,NULL,'gly','gule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2300,0,NULL,'gma','gambera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2301,0,NULL,'gmb','gula''alaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2302,0,NULL,'gmd','mághdì','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2303,0,NULL,'gme','east germanic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2304,0,NULL,'gmh','middle high german (ca. 1050-1500)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2305,0,NULL,'gml','middle low german','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2306,0,NULL,'gmm','gbaya-mbodomo','1248825600',NULL,NULL,NULL,NULL,'gba',NULL,NULL); +INSERT INTO "iana_records" VALUES(2307,0,NULL,'gmn','gimnime','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2308,0,NULL,'gmq','north germanic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2309,0,NULL,'gmu','gumalu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2310,0,NULL,'gmv','gamo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2311,0,NULL,'gmw','west germanic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2312,0,NULL,'gmx','magoma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2313,0,NULL,'gmy','mycenaean greek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2314,0,NULL,'gna','kaansa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2315,0,NULL,'gnb','gangte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2316,0,NULL,'gnc','guanche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2317,0,NULL,'gnd','zulgo-gemzek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2318,0,NULL,'gne','ganang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2319,0,NULL,'gng','ngangam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2320,0,NULL,'gnh','lere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2321,0,NULL,'gni','gooniyandi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2322,0,NULL,'gnk','//gana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2323,0,NULL,'gnl','gangulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2324,0,NULL,'gnm','ginuman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2325,0,NULL,'gnn','gumatj','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2326,0,NULL,'gno','northern gondi','1248825600',NULL,NULL,NULL,NULL,'gon',NULL,NULL); +INSERT INTO "iana_records" VALUES(2327,0,NULL,'gnq','gana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2328,0,NULL,'gnr','gureng gureng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2329,0,NULL,'gnt','guntai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2330,0,NULL,'gnu','gnau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2331,0,NULL,'gnw','western bolivian guaraní','1248825600',NULL,NULL,NULL,NULL,'gn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2332,0,NULL,'gnz','ganzi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2333,0,NULL,'goa','guro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2334,0,NULL,'gob','playero','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2335,0,NULL,'goc','gorakor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2336,0,NULL,'god','godié','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2337,0,NULL,'goe','gongduk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2338,0,NULL,'gof','gofa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2339,0,NULL,'gog','gogo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2340,0,NULL,'goh','old high german (ca. 750-1050)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2341,0,NULL,'goi','gobasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2342,0,NULL,'goj','gowlan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2343,0,NULL,'gok','gowli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2344,0,NULL,'gol','gola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2345,0,NULL,'gom','goan konkani','1248825600',NULL,NULL,NULL,NULL,'kok',NULL,NULL); +INSERT INTO "iana_records" VALUES(2346,0,NULL,'gon','gondi','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(2347,0,NULL,'goo','gone dau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2348,0,NULL,'gop','yeretuar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2349,0,NULL,'goq','gorap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2350,0,NULL,'gor','gorontalo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2351,0,NULL,'gos','gronings','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2352,0,NULL,'got','gothic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2353,0,NULL,'gou','gavar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2354,0,NULL,'gow','gorowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2355,0,NULL,'gox','gobu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2356,0,NULL,'goy','goundo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2357,0,NULL,'goz','gozarkhani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2358,0,NULL,'gpa','gupa-abawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2359,0,NULL,'gpn','taiap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2360,0,NULL,'gqa','ga''anda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2361,0,NULL,'gqi','guiqiong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2362,0,NULL,'gqn','guana (brazil)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2363,0,NULL,'gqr','gor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2364,0,NULL,'gra','rajput garasia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2365,0,NULL,'grb','grebo','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(2366,0,NULL,'grc','ancient greek (to 1453)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2367,0,NULL,'grd','guruntum-mbaaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2368,0,NULL,'grg','madi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2369,0,NULL,'grh','gbiri-niragu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2370,0,NULL,'gri','ghari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2371,0,NULL,'grj','southern grebo','1248825600',NULL,NULL,NULL,NULL,'grb',NULL,NULL); +INSERT INTO "iana_records" VALUES(2372,0,NULL,'grk','greek languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2373,0,NULL,'grm','kota marudu talantang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2374,0,NULL,'gro','groma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2375,0,NULL,'grq','gorovu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2376,0,NULL,'grr','taznatit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2377,0,NULL,'grs','gresi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2378,0,NULL,'grt','garo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2379,0,NULL,'gru','kistane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2380,0,NULL,'grv','central grebo','1248825600',NULL,NULL,NULL,NULL,'grb',NULL,NULL); +INSERT INTO "iana_records" VALUES(2381,0,NULL,'grw','gweda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2382,0,NULL,'grx','guriaso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2383,0,NULL,'gry','barclayville grebo','1248825600',NULL,NULL,NULL,NULL,'grb',NULL,NULL); +INSERT INTO "iana_records" VALUES(2384,0,NULL,'grz','guramalum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2385,0,NULL,'gse','ghanaian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2386,0,NULL,'gsg','german sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2387,0,NULL,'gsl','gusilay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2388,0,NULL,'gsm','guatemalan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2389,0,NULL,'gsn','gusan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2390,0,NULL,'gso','southwest gbaya','1248825600',NULL,NULL,NULL,NULL,'gba',NULL,NULL); +INSERT INTO "iana_records" VALUES(2391,0,NULL,'gsp','wasembo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2392,0,NULL,'gss','greek sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2393,0,NULL,'gsw','alemannic','1141776000',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2393,0,NULL,'gsw','alsatian','1141776000',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2393,0,NULL,'gsw','swiss german','1141776000',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2394,0,NULL,'gta','guató','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2395,0,NULL,'gti','gbati-ri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2396,0,NULL,'gua','shiki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2397,0,NULL,'gub','guajajára','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2398,0,NULL,'guc','wayuu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2399,0,NULL,'gud','yocoboué dida','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2400,0,NULL,'gue','gurinji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2401,0,NULL,'guf','gupapuyngu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2402,0,NULL,'gug','paraguayan guaraní','1248825600',NULL,NULL,NULL,NULL,'gn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2403,0,NULL,'guh','guahibo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2404,0,NULL,'gui','eastern bolivian guaraní','1248825600',NULL,NULL,NULL,NULL,'gn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2405,0,NULL,'guk','gumuz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2406,0,NULL,'gul','sea island creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2407,0,NULL,'gum','guambiano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2408,0,NULL,'gun','mbyá guaraní','1248825600',NULL,NULL,NULL,NULL,'gn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2409,0,NULL,'guo','guayabero','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2410,0,NULL,'gup','gunwinggu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2411,0,NULL,'guq','aché','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2412,0,NULL,'gur','farefare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2413,0,NULL,'gus','guinean sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2414,0,NULL,'gut','maléku jaíka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2415,0,NULL,'guu','yanomamö','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2416,0,NULL,'guv','gey','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2417,0,NULL,'guw','gun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2418,0,NULL,'gux','gourmanchéma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2419,0,NULL,'guz','ekegusii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2419,0,NULL,'guz','gusii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2420,0,NULL,'gva','guana (paraguay)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2421,0,NULL,'gvc','guanano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2422,0,NULL,'gve','duwet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2423,0,NULL,'gvf','golin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2424,0,NULL,'gvj','guajá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2425,0,NULL,'gvl','gulay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2426,0,NULL,'gvm','gurmana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2427,0,NULL,'gvn','kuku-yalanji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2428,0,NULL,'gvo','gavião do jiparaná','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2429,0,NULL,'gvp','pará gavião','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2430,0,NULL,'gvr','western gurung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2431,0,NULL,'gvs','gumawana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2432,0,NULL,'gvy','guyani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2433,0,NULL,'gwa','mbato','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2434,0,NULL,'gwb','gwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2435,0,NULL,'gwc','kalami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2436,0,NULL,'gwd','gawwada','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2437,0,NULL,'gwe','gweno','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2438,0,NULL,'gwf','gowro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2439,0,NULL,'gwg','moo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2440,0,NULL,'gwi','gwichʼin','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2441,0,NULL,'gwj','/gwi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2442,0,NULL,'gwn','gwandara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2443,0,NULL,'gwr','gwere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2444,0,NULL,'gwt','gawar-bati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2445,0,NULL,'gwu','guwamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2446,0,NULL,'gww','kwini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2447,0,NULL,'gwx','gua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2448,0,NULL,'gxx','wè southern','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2449,0,NULL,'gya','northwest gbaya','1248825600',NULL,NULL,NULL,NULL,'gba',NULL,NULL); +INSERT INTO "iana_records" VALUES(2450,0,NULL,'gyb','garus','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2451,0,NULL,'gyd','kayardild','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2452,0,NULL,'gye','gyem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2453,0,NULL,'gyf','gungabula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2454,0,NULL,'gyg','gbayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2455,0,NULL,'gyi','gyele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2456,0,NULL,'gyl','gayil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2457,0,NULL,'gym','ngäbere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2458,0,NULL,'gyn','guyanese creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2459,0,NULL,'gyr','guarayu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2460,0,NULL,'gyy','gunya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2461,0,NULL,'gza','ganza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2462,0,NULL,'gzi','gazi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2463,0,NULL,'gzn','gane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2464,0,NULL,'haa','han','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2465,0,NULL,'hab','hanoi sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2466,0,NULL,'hac','gurani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2467,0,NULL,'had','hatam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2468,0,NULL,'hae','eastern oromo','1248825600',NULL,NULL,NULL,NULL,'om',NULL,NULL); +INSERT INTO "iana_records" VALUES(2469,0,NULL,'haf','haiphong sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2470,0,NULL,'hag','hanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2471,0,NULL,'hah','hahon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2472,0,NULL,'hai','haida','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(2473,0,NULL,'haj','hajong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2474,0,NULL,'hak','hakka chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(2475,0,NULL,'hal','halang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2476,0,NULL,'ham','hewa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2477,0,NULL,'han','hangaza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2478,0,NULL,'hao','hakö','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2479,0,NULL,'hap','hupla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2480,0,NULL,'haq','ha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2481,0,NULL,'har','harari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2482,0,NULL,'has','haisla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2483,0,NULL,'hav','havu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2484,0,NULL,'haw','hawaiian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2485,0,NULL,'hax','southern haida','1248825600',NULL,NULL,NULL,NULL,'hai',NULL,NULL); +INSERT INTO "iana_records" VALUES(2486,0,NULL,'hay','haya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2487,0,NULL,'haz','hazaragi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2488,0,NULL,'hba','hamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2489,0,NULL,'hbb','huba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2490,0,NULL,'hbn','heiban','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2491,0,NULL,'hbo','ancient hebrew','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2492,0,NULL,'hbu','habu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2493,0,NULL,'hca','andaman creole hindi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2494,0,NULL,'hch','huichol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2495,0,NULL,'hdn','northern haida','1248825600',NULL,NULL,NULL,NULL,'hai',NULL,NULL); +INSERT INTO "iana_records" VALUES(2496,0,NULL,'hds','honduras sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2497,0,NULL,'hdy','hadiyya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2498,0,NULL,'hea','northern qiandong miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2499,0,NULL,'hed','herdé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2500,0,NULL,'heg','helong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2501,0,NULL,'heh','hehe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2502,0,NULL,'hei','heiltsuk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2503,0,NULL,'hem','hemba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2504,0,NULL,'hgm','hai//om','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2505,0,NULL,'hgw','haigwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2506,0,NULL,'hhi','hoia hoia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2507,0,NULL,'hhr','kerak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2508,0,NULL,'hhy','hoyahoya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2509,0,NULL,'hia','lamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2510,0,NULL,'hib','hibito','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2511,0,NULL,'hid','hidatsa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2512,0,NULL,'hif','fiji hindi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2513,0,NULL,'hig','kamwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2514,0,NULL,'hih','pamosu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2515,0,NULL,'hii','hinduri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2516,0,NULL,'hij','hijuk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2517,0,NULL,'hik','seit-kaitetu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2518,0,NULL,'hil','hiligaynon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2519,0,NULL,'him','himachali languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2519,0,NULL,'him','western pahari languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2520,0,NULL,'hio','tsoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2521,0,NULL,'hir','himarimã','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2522,0,NULL,'hit','hittite','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2523,0,NULL,'hiw','hiw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2524,0,NULL,'hix','hixkaryána','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2525,0,NULL,'hji','haji','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(2526,0,NULL,'hka','kahe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2527,0,NULL,'hke','hunde','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2528,0,NULL,'hkk','hunjara-kaina ke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2529,0,NULL,'hks','heung kong sau yue','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2529,0,NULL,'hks','hong kong sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2530,0,NULL,'hla','halia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2531,0,NULL,'hlb','halbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2532,0,NULL,'hld','halang doan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2533,0,NULL,'hle','hlersu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2534,0,NULL,'hlt','nga la','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2535,0,NULL,'hlu','hieroglyphic luwian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2536,0,NULL,'hma','southern mashan hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2536,0,NULL,'hma','southern mashan miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2537,0,NULL,'hmb','humburi senni songhay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2538,0,NULL,'hmc','central huishui hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2538,0,NULL,'hmc','central huishui miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2539,0,NULL,'hmd','a-hmaos','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2539,0,NULL,'hmd','da-hua miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2539,0,NULL,'hmd','large flowery miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2540,0,NULL,'hme','eastern huishui hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2540,0,NULL,'hme','eastern huishui miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2541,0,NULL,'hmf','hmong don','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2542,0,NULL,'hmg','southwestern guiyang hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2543,0,NULL,'hmh','southwestern huishui hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2543,0,NULL,'hmh','southwestern huishui miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2544,0,NULL,'hmi','northern huishui hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2544,0,NULL,'hmi','northern huishui miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2545,0,NULL,'hmj','ge','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2545,0,NULL,'hmj','gejia','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2546,0,NULL,'hmk','maek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2547,0,NULL,'hml','luopohe hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2547,0,NULL,'hml','luopohe miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2548,0,NULL,'hmm','central mashan hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2548,0,NULL,'hmm','central mashan miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2549,0,NULL,'hmn','hmong','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(2549,0,NULL,'hmn','mong','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(2550,0,NULL,'hmp','northern mashan hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2550,0,NULL,'hmp','northern mashan miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2551,0,NULL,'hmq','eastern qiandong miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2552,0,NULL,'hmr','hmar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2553,0,NULL,'hms','southern qiandong miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2554,0,NULL,'hmt','hamtai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2555,0,NULL,'hmu','hamap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2556,0,NULL,'hmv','hmong dô','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2557,0,NULL,'hmw','western mashan hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2557,0,NULL,'hmw','western mashan miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2558,0,NULL,'hmx','hmong-mien languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2559,0,NULL,'hmy','southern guiyang hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2559,0,NULL,'hmy','southern guiyang miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2560,0,NULL,'hmz','hmong shua','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2560,0,NULL,'hmz','sinicized miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2561,0,NULL,'hna','mina (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2562,0,NULL,'hnd','southern hindko','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(2563,0,NULL,'hne','chhattisgarhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2564,0,NULL,'hnh','//ani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2565,0,NULL,'hni','hani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2566,0,NULL,'hnj','hmong njua','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2566,0,NULL,'hnj','mong leng','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2566,0,NULL,'hnj','mong njua','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2567,0,NULL,'hnn','hanunoo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2568,0,NULL,'hno','northern hindko','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(2569,0,NULL,'hns','caribbean hindustani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2570,0,NULL,'hnu','hung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2571,0,NULL,'hoa','hoava','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2572,0,NULL,'hob','mari (madang province)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2573,0,NULL,'hoc','ho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2574,0,NULL,'hod','holma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2575,0,NULL,'hoe','horom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2576,0,NULL,'hoh','hobyót','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2577,0,NULL,'hoi','holikachuk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2578,0,NULL,'hoj','hadothi','1248825600',NULL,NULL,NULL,NULL,'raj',NULL,NULL); +INSERT INTO "iana_records" VALUES(2579,0,NULL,'hok','hokan languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2580,0,NULL,'hol','holu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2581,0,NULL,'hom','homa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2582,0,NULL,'hoo','holoholo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2583,0,NULL,'hop','hopi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2584,0,NULL,'hor','horo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2585,0,NULL,'hos','ho chi minh city sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2586,0,NULL,'hot','hote','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2586,0,NULL,'hot','malê','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2587,0,NULL,'hov','hovongan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2588,0,NULL,'how','honi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2589,0,NULL,'hoy','holiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2590,0,NULL,'hoz','hozo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2591,0,NULL,'hpo','hpon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2592,0,NULL,'hps','hawai''i pidgin sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2593,0,NULL,'hra','hrangkhol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2594,0,NULL,'hre','hre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2595,0,NULL,'hrk','haruku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2596,0,NULL,'hrm','horned miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2597,0,NULL,'hro','haroi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2598,0,NULL,'hrr','horuru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2599,0,NULL,'hrt','hértevin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2600,0,NULL,'hru','hruso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2601,0,NULL,'hrx','hunsrik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2602,0,NULL,'hrz','harzani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2603,0,NULL,'hsb','upper sorbian','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2604,0,NULL,'hsh','hungarian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2605,0,NULL,'hsl','hausa sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2606,0,NULL,'hsn','xiang chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(2607,0,NULL,'hss','harsusi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2608,0,NULL,'hti','hoti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2609,0,NULL,'hto','minica huitoto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2610,0,NULL,'hts','hadza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2611,0,NULL,'htu','hitu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2612,0,NULL,'htx','middle hittite','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2613,0,NULL,'hub','huambisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2614,0,NULL,'huc','=/hua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2615,0,NULL,'hud','huaulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2616,0,NULL,'hue','san francisco del mar huave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2617,0,NULL,'huf','humene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2618,0,NULL,'hug','huachipaeri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2619,0,NULL,'huh','huilliche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2620,0,NULL,'hui','huli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2621,0,NULL,'huj','northern guiyang hmong','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2621,0,NULL,'huj','northern guiyang miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(2622,0,NULL,'huk','hulung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2623,0,NULL,'hul','hula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2624,0,NULL,'hum','hungana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2625,0,NULL,'huo','hu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2626,0,NULL,'hup','hupa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2627,0,NULL,'huq','tsat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2628,0,NULL,'hur','halkomelem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2629,0,NULL,'hus','huastec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2630,0,NULL,'hut','humla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2631,0,NULL,'huu','murui huitoto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2632,0,NULL,'huv','san mateo del mar huave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2633,0,NULL,'huw','hukumina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2634,0,NULL,'hux','nüpode huitoto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2635,0,NULL,'huy','hulaulá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2636,0,NULL,'huz','hunzib','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2637,0,NULL,'hvc','haitian vodoun culture language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2638,0,NULL,'hve','san dionisio del mar huave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2639,0,NULL,'hvk','haveke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2640,0,NULL,'hvn','sabu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2641,0,NULL,'hvv','santa maría del mar huave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2642,0,NULL,'hwa','wané','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2643,0,NULL,'hwc','hawai''i creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2644,0,NULL,'hwo','hwana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2645,0,NULL,'hya','hya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2646,0,NULL,'hyx','armenian (family)','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2647,0,NULL,'iai','iaai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2648,0,NULL,'ian','iatmul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2649,0,NULL,'iap','iapama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2650,0,NULL,'iar','purari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2651,0,NULL,'iba','iban','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2652,0,NULL,'ibb','ibibio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2653,0,NULL,'ibd','iwaidja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2654,0,NULL,'ibe','akpes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2655,0,NULL,'ibg','ibanag','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2656,0,NULL,'ibi','ibilo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2657,0,NULL,'ibl','ibaloi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2658,0,NULL,'ibm','agoi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2659,0,NULL,'ibn','ibino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2660,0,NULL,'ibr','ibuoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2661,0,NULL,'ibu','ibu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2662,0,NULL,'iby','ibani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2663,0,NULL,'ica','ede ica','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2664,0,NULL,'ich','etkywan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2665,0,NULL,'icl','icelandic sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2666,0,NULL,'icr','islander creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2667,0,NULL,'ida','idakho-isukha-tiriki','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(2667,0,NULL,'ida','luidakho-luisukha-lutirichi','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(2668,0,NULL,'idb','indo-portuguese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2669,0,NULL,'idc','idon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2670,0,NULL,'idd','ede idaca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2671,0,NULL,'ide','idere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2672,0,NULL,'idi','idi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2673,0,NULL,'idr','indri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2674,0,NULL,'ids','idesa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2675,0,NULL,'idt','idaté','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2676,0,NULL,'idu','idoma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2677,0,NULL,'ifa','amganad ifugao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2678,0,NULL,'ifb','ayangan ifugao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2678,0,NULL,'ifb','batad ifugao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2679,0,NULL,'ife','ifè','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2680,0,NULL,'iff','ifo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2681,0,NULL,'ifk','tuwali ifugao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2682,0,NULL,'ifm','teke-fuumu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2683,0,NULL,'ifu','mayoyao ifugao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2684,0,NULL,'ify','keley-i kallahan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2685,0,NULL,'igb','ebira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2686,0,NULL,'ige','igede','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2687,0,NULL,'igg','igana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2688,0,NULL,'igl','igala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2689,0,NULL,'igm','kanggape','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2690,0,NULL,'ign','ignaciano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2691,0,NULL,'igo','isebe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2692,0,NULL,'igs','interglossa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2693,0,NULL,'igw','igwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2694,0,NULL,'ihb','iha based pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2695,0,NULL,'ihi','ihievbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2696,0,NULL,'ihp','iha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2697,0,NULL,'iir','indo-iranian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2698,0,NULL,'ijc','izon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2699,0,NULL,'ije','biseni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2700,0,NULL,'ijj','ede ije','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2701,0,NULL,'ijn','kalabari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2702,0,NULL,'ijo','ijo languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2703,0,NULL,'ijs','southeast ijo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2704,0,NULL,'ike','eastern canadian inuktitut','1248825600',NULL,NULL,NULL,NULL,'iu',NULL,NULL); +INSERT INTO "iana_records" VALUES(2705,0,NULL,'iki','iko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2706,0,NULL,'ikk','ika','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2707,0,NULL,'ikl','ikulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2708,0,NULL,'iko','olulumo-ikom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2709,0,NULL,'ikp','ikpeshi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2710,0,NULL,'ikt','western canadian inuktitut','1248825600',NULL,NULL,NULL,NULL,'iu',NULL,NULL); +INSERT INTO "iana_records" VALUES(2711,0,NULL,'ikv','iku-gora-ankwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2712,0,NULL,'ikw','ikwere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2713,0,NULL,'ikx','ik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2714,0,NULL,'ikz','ikizu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2715,0,NULL,'ila','ile ape','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2716,0,NULL,'ilb','ila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2717,0,NULL,'ilg','garig-ilgar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2718,0,NULL,'ili','ili turki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2719,0,NULL,'ilk','ilongot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2720,0,NULL,'ill','iranun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2721,0,NULL,'ilo','iloko','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2722,0,NULL,'ils','international sign','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2723,0,NULL,'ilu','ili''uun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2724,0,NULL,'ilv','ilue','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2725,0,NULL,'ilw','talur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2726,0,NULL,'ima','mala malasar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2727,0,NULL,'ime','imeraguen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2728,0,NULL,'imi','anamgura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2729,0,NULL,'iml','miluk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2730,0,NULL,'imn','imonda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2731,0,NULL,'imo','imbongu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2732,0,NULL,'imr','imroing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2733,0,NULL,'ims','marsian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2734,0,NULL,'imy','milyan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2735,0,NULL,'inb','inga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2736,0,NULL,'inc','indic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2737,0,NULL,'ine','indo-european languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2738,0,NULL,'ing','degexit''an','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2739,0,NULL,'inh','ingush','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2740,0,NULL,'inj','jungle inga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2741,0,NULL,'inl','indonesian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2742,0,NULL,'inm','minaean','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2743,0,NULL,'inn','isinai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2744,0,NULL,'ino','inoke-yate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2745,0,NULL,'inp','iñapari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2746,0,NULL,'ins','indian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2747,0,NULL,'int','intha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2748,0,NULL,'inz','ineseño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2749,0,NULL,'ior','inor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2750,0,NULL,'iou','tuma-irumu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2751,0,NULL,'iow','iowa-oto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2752,0,NULL,'ipi','ipili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2753,0,NULL,'ipo','ipiko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2754,0,NULL,'iqu','iquito','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2755,0,NULL,'ira','iranian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2756,0,NULL,'ire','iresim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2757,0,NULL,'irh','irarutu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2758,0,NULL,'iri','irigwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2759,0,NULL,'irk','iraqw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2760,0,NULL,'irn','irántxe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2761,0,NULL,'iro','iroquoian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2762,0,NULL,'irr','ir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2763,0,NULL,'iru','irula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2764,0,NULL,'irx','kamberau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2765,0,NULL,'iry','iraya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2766,0,NULL,'isa','isabi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2767,0,NULL,'isc','isconahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2768,0,NULL,'isd','isnag','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2769,0,NULL,'ise','italian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2770,0,NULL,'isg','irish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2771,0,NULL,'ish','esan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2772,0,NULL,'isi','nkem-nkum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2773,0,NULL,'isk','ishkashimi','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2774,0,NULL,'ism','masimasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2775,0,NULL,'isn','isanzu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2776,0,NULL,'iso','isoko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2777,0,NULL,'isr','israeli sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2778,0,NULL,'ist','istriot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2779,0,NULL,'isu','isu (menchum division)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2780,0,NULL,'itb','binongan itneg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2781,0,NULL,'itc','italic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2782,0,NULL,'ite','itene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2783,0,NULL,'iti','inlaod itneg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2784,0,NULL,'itk','judeo-italian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2785,0,NULL,'itl','itelmen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2786,0,NULL,'itm','itu mbon uzo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2787,0,NULL,'ito','itonama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2788,0,NULL,'itr','iteri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2789,0,NULL,'its','isekiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2790,0,NULL,'itt','maeng itneg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2791,0,NULL,'itv','itawit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2792,0,NULL,'itw','ito','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2793,0,NULL,'itx','itik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2794,0,NULL,'ity','moyadan itneg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2795,0,NULL,'itz','itzá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2796,0,NULL,'ium','iu mien','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2797,0,NULL,'ivb','ibatan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2798,0,NULL,'ivv','ivatan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2799,0,NULL,'iwk','i-wak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2800,0,NULL,'iwm','iwam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2801,0,NULL,'iwo','iwur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2802,0,NULL,'iws','sepik iwam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2803,0,NULL,'ixc','ixcatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2804,0,NULL,'ixl','ixil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2805,0,NULL,'iya','iyayu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2806,0,NULL,'iyo','mesaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2807,0,NULL,'iyx','yaka (congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2808,0,NULL,'izh','ingrian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2809,0,NULL,'izi','izi-ezaa-ikwo-mgbo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2810,0,NULL,'izr','izere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2811,0,NULL,'jaa','jamamadí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2812,0,NULL,'jab','hyam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2813,0,NULL,'jac','jakalteko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2813,0,NULL,'jac','popti''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2814,0,NULL,'jad','jahanka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2815,0,NULL,'jae','yabem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2816,0,NULL,'jaf','jara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2817,0,NULL,'jah','jah hut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2818,0,NULL,'jaj','zazao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2819,0,NULL,'jak','jakun','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(2820,0,NULL,'jal','yalahatan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2821,0,NULL,'jam','jamaican creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2822,0,NULL,'jao','yanyuwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2823,0,NULL,'jaq','yaqay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2824,0,NULL,'jar','jarawa (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2825,0,NULL,'jas','new caledonian javanese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2826,0,NULL,'jat','jakati','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(2827,0,NULL,'jau','yaur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2828,0,NULL,'jax','jambi malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(2829,0,NULL,'jay','yan-nhangu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2830,0,NULL,'jaz','jawe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2831,0,NULL,'jbe','judeo-berber','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2832,0,NULL,'jbj','arandai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2833,0,NULL,'jbn','nafusi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2834,0,NULL,'jbo','lojban','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2835,0,NULL,'jbr','jofotek-bromnya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2836,0,NULL,'jbt','jabutí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2837,0,NULL,'jbu','jukun takum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2838,0,NULL,'jcs','jamaican country sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2839,0,NULL,'jct','krymchak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2840,0,NULL,'jda','jad','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2841,0,NULL,'jdg','jadgali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2842,0,NULL,'jdt','judeo-tat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2843,0,NULL,'jeb','jebero','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2844,0,NULL,'jee','jerung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2845,0,NULL,'jeg','jeng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2846,0,NULL,'jeh','jeh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2847,0,NULL,'jei','yei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2848,0,NULL,'jek','jeri kuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2849,0,NULL,'jel','yelmek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2850,0,NULL,'jen','dza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2851,0,NULL,'jer','jere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2852,0,NULL,'jet','manem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2853,0,NULL,'jeu','jonkor bourmataguil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2854,0,NULL,'jgb','ngbee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2855,0,NULL,'jge','judeo-georgian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2856,0,NULL,'jgo','ngomba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2857,0,NULL,'jhi','jehai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2858,0,NULL,'jhs','jhankot sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2859,0,NULL,'jia','jina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2860,0,NULL,'jib','jibu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2861,0,NULL,'jic','tol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2862,0,NULL,'jid','bu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2863,0,NULL,'jie','jilbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2864,0,NULL,'jig','djingili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2865,0,NULL,'jih','shangzhai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2866,0,NULL,'jii','jiiddu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2867,0,NULL,'jil','jilim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2868,0,NULL,'jim','jimi (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2869,0,NULL,'jio','jiamao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2870,0,NULL,'jiq','guanyinqiao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2871,0,NULL,'jit','jita','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2872,0,NULL,'jiu','youle jinuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2873,0,NULL,'jiv','shuar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2874,0,NULL,'jiy','buyuan jinuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2875,0,NULL,'jko','kubo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2876,0,NULL,'jku','labir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2877,0,NULL,'jle','ngile','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2878,0,NULL,'jls','jamaican sign language','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2879,0,NULL,'jma','dima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2880,0,NULL,'jmb','zumbun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2881,0,NULL,'jmc','machame','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2882,0,NULL,'jmd','yamdena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2883,0,NULL,'jmi','jimi (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2884,0,NULL,'jml','jumli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2885,0,NULL,'jmn','makuri naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2886,0,NULL,'jmr','kamara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2887,0,NULL,'jms','mashi (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2888,0,NULL,'jmx','western juxtlahuaca mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2889,0,NULL,'jna','jangshung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2890,0,NULL,'jnd','jandavra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2891,0,NULL,'jng','yangman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2892,0,NULL,'jni','janji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2893,0,NULL,'jnj','yemsa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2894,0,NULL,'jnl','rawat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2895,0,NULL,'jns','jaunsari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2896,0,NULL,'job','joba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2897,0,NULL,'jod','wojenaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2898,0,NULL,'jor','jorá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2899,0,NULL,'jos','jordanian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2900,0,NULL,'jow','jowulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2901,0,NULL,'jpa','jewish palestinian aramaic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2902,0,NULL,'jpr','judeo-persian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2903,0,NULL,'jpx','japanese (family)','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2904,0,NULL,'jqr','jaqaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2905,0,NULL,'jra','jarai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2906,0,NULL,'jrb','judeo-arabic','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(2907,0,NULL,'jrr','jiru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2908,0,NULL,'jrt','jorto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2909,0,NULL,'jru','japrería','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2910,0,NULL,'jsl','japanese sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2911,0,NULL,'jua','júma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2912,0,NULL,'jub','wannu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2913,0,NULL,'juc','jurchen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2914,0,NULL,'jud','worodougou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2915,0,NULL,'juh','hõne','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2916,0,NULL,'juk','wapan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2917,0,NULL,'jul','jirel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2918,0,NULL,'jum','jumjum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2919,0,NULL,'jun','juang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2920,0,NULL,'juo','jiba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2921,0,NULL,'jup','hupdë','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2922,0,NULL,'jur','jurúna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2923,0,NULL,'jus','jumla sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2924,0,NULL,'jut','jutish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2925,0,NULL,'juu','ju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2926,0,NULL,'juw','wãpha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2927,0,NULL,'juy','juray','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2928,0,NULL,'jvd','javindo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2929,0,NULL,'jvn','caribbean javanese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2930,0,NULL,'jwi','jwira-pepesa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2931,0,NULL,'jya','jiarong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2932,0,NULL,'jye','judeo-yemeni arabic','1248825600',NULL,NULL,NULL,NULL,'jrb',NULL,NULL); +INSERT INTO "iana_records" VALUES(2933,0,NULL,'jyy','jaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2934,0,NULL,'kaa','kara-kalpak','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2935,0,NULL,'kab','kabyle','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2936,0,NULL,'kac','jingpho','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2936,0,NULL,'kac','kachin','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2937,0,NULL,'kad','kadara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2938,0,NULL,'kae','ketangalan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2939,0,NULL,'kaf','katso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2940,0,NULL,'kag','kajaman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2941,0,NULL,'kah','kara (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2942,0,NULL,'kai','karekare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2943,0,NULL,'kaj','jju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2944,0,NULL,'kak','kayapa kallahan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2945,0,NULL,'kam','kamba (kenya)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2946,0,NULL,'kao','xaasongaxango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2947,0,NULL,'kap','bezhta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2948,0,NULL,'kaq','capanahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2949,0,NULL,'kar','karen languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(2950,0,NULL,'kav','katukína','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2951,0,NULL,'kaw','kawi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2952,0,NULL,'kax','kao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2953,0,NULL,'kay','kamayurá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2954,0,NULL,'kba','kalarko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2955,0,NULL,'kbb','kaxuiâna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2956,0,NULL,'kbc','kadiwéu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2957,0,NULL,'kbd','kabardian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2958,0,NULL,'kbe','kanju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2959,0,NULL,'kbf','kakauhua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2960,0,NULL,'kbg','khamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2961,0,NULL,'kbh','camsá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2962,0,NULL,'kbi','kaptiau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2963,0,NULL,'kbj','kari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2964,0,NULL,'kbk','grass koiari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2965,0,NULL,'kbl','kanembu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2966,0,NULL,'kbm','iwal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2967,0,NULL,'kbn','kare (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2968,0,NULL,'kbo','keliko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2969,0,NULL,'kbp','kabiyè','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2970,0,NULL,'kbq','kamano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2971,0,NULL,'kbr','kafa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2972,0,NULL,'kbs','kande','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2973,0,NULL,'kbt','abadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2974,0,NULL,'kbu','kabutra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2975,0,NULL,'kbv','dera (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2976,0,NULL,'kbw','kaiep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2977,0,NULL,'kbx','ap ma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2978,0,NULL,'kby','manga kanuri','1248825600',NULL,NULL,NULL,NULL,'kr',NULL,NULL); +INSERT INTO "iana_records" VALUES(2979,0,NULL,'kbz','duhwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2980,0,NULL,'kca','khanty','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2981,0,NULL,'kcb','kawacha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2982,0,NULL,'kcc','lubila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2983,0,NULL,'kcd','ngkâlmpw kanum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2984,0,NULL,'kce','kaivi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2985,0,NULL,'kcf','ukaan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2986,0,NULL,'kcg','tyap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2987,0,NULL,'kch','vono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2988,0,NULL,'kci','kamantan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2989,0,NULL,'kcj','kobiana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2990,0,NULL,'kck','kalanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2991,0,NULL,'kcl','kela (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2992,0,NULL,'kcm','gula (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2993,0,NULL,'kcn','nubi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2994,0,NULL,'kco','kinalakna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2995,0,NULL,'kcp','kanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2996,0,NULL,'kcq','kamo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2997,0,NULL,'kcr','katla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2998,0,NULL,'kcs','koenoem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(2999,0,NULL,'kct','kaian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3000,0,NULL,'kcu','kami (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3001,0,NULL,'kcv','kete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3002,0,NULL,'kcw','kabwari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3003,0,NULL,'kcx','kachama-ganjule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3004,0,NULL,'kcy','korandje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3005,0,NULL,'kcz','konongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3006,0,NULL,'kda','worimi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3007,0,NULL,'kdc','kutu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3008,0,NULL,'kdd','yankunytjatjara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3009,0,NULL,'kde','makonde','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3010,0,NULL,'kdf','mamusi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3011,0,NULL,'kdg','seba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3012,0,NULL,'kdh','tem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3013,0,NULL,'kdi','kumam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3014,0,NULL,'kdj','karamojong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3015,0,NULL,'kdk','numee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3016,0,NULL,'kdl','tsikimba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3017,0,NULL,'kdm','kagoma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3018,0,NULL,'kdn','kunda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3019,0,NULL,'kdo','kordofanian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(3020,0,NULL,'kdp','kaningdon-nindem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3021,0,NULL,'kdq','koch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3022,0,NULL,'kdr','karaim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3023,0,NULL,'kdt','kuy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3024,0,NULL,'kdu','kadaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3025,0,NULL,'kdv','kado','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3026,0,NULL,'kdw','koneraw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3027,0,NULL,'kdx','kam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3028,0,NULL,'kdy','keder','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3028,0,NULL,'kdy','keijar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3029,0,NULL,'kdz','kwaja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3030,0,NULL,'kea','kabuverdianu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3031,0,NULL,'keb','kélé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3032,0,NULL,'kec','keiga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3033,0,NULL,'ked','kerewe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3034,0,NULL,'kee','eastern keres','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3035,0,NULL,'kef','kpessi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3036,0,NULL,'keg','tese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3037,0,NULL,'keh','keak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3038,0,NULL,'kei','kei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3039,0,NULL,'kej','kadar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3040,0,NULL,'kek','kekchí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3041,0,NULL,'kel','kela (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3042,0,NULL,'kem','kemak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3043,0,NULL,'ken','kenyang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3044,0,NULL,'keo','kakwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3045,0,NULL,'kep','kaikadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3046,0,NULL,'keq','kamar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3047,0,NULL,'ker','kera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3048,0,NULL,'kes','kugbo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3049,0,NULL,'ket','ket','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3050,0,NULL,'keu','akebu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3051,0,NULL,'kev','kanikkaran','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3052,0,NULL,'kew','west kewa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3053,0,NULL,'kex','kukna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3054,0,NULL,'key','kupia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3055,0,NULL,'kez','kukele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3056,0,NULL,'kfa','kodava','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3057,0,NULL,'kfb','northwestern kolami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3058,0,NULL,'kfc','konda-dora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3059,0,NULL,'kfd','korra koraga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3060,0,NULL,'kfe','kota (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3061,0,NULL,'kff','koya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3062,0,NULL,'kfg','kudiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3063,0,NULL,'kfh','kurichiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3064,0,NULL,'kfi','kannada kurumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3065,0,NULL,'kfj','kemiehua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3066,0,NULL,'kfk','kinnauri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3067,0,NULL,'kfl','kung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3068,0,NULL,'kfm','khunsari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3069,0,NULL,'kfn','kuk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3070,0,NULL,'kfo','koro (côte d''ivoire)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3071,0,NULL,'kfp','korwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3072,0,NULL,'kfq','korku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3073,0,NULL,'kfr','kachchi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3074,0,NULL,'kfs','bilaspuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3075,0,NULL,'kft','kanjari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3076,0,NULL,'kfu','katkari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3077,0,NULL,'kfv','kurmukar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3078,0,NULL,'kfw','kharam naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3079,0,NULL,'kfx','kullu pahari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3080,0,NULL,'kfy','kumaoni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3081,0,NULL,'kfz','koromfé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3082,0,NULL,'kga','koyaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3083,0,NULL,'kgb','kawe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3084,0,NULL,'kgc','kasseng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3085,0,NULL,'kgd','kataang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3086,0,NULL,'kge','komering','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3087,0,NULL,'kgf','kube','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3088,0,NULL,'kgg','kusunda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3089,0,NULL,'kgh','upper tanudan kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3090,0,NULL,'kgi','selangor sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3091,0,NULL,'kgj','gamale kham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3092,0,NULL,'kgk','kaiwá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3093,0,NULL,'kgl','kunggari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3094,0,NULL,'kgm','karipúna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3095,0,NULL,'kgn','karingani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3096,0,NULL,'kgo','krongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3097,0,NULL,'kgp','kaingang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3098,0,NULL,'kgq','kamoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3099,0,NULL,'kgr','abun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3100,0,NULL,'kgs','kumbainggar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3101,0,NULL,'kgt','somyev','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3102,0,NULL,'kgu','kobol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3103,0,NULL,'kgv','karas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3104,0,NULL,'kgw','karon dori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3105,0,NULL,'kgx','kamaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3106,0,NULL,'kgy','kyerung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3107,0,NULL,'kha','khasi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,'as of 2008-04-21 this subtag does not include lyngngam; see lyg'); +INSERT INTO "iana_records" VALUES(3108,0,NULL,'khb','lü','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3109,0,NULL,'khc','tukang besi north','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3110,0,NULL,'khd','bädi kanum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3111,0,NULL,'khe','korowai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3112,0,NULL,'khf','khuen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3113,0,NULL,'khg','khams tibetan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3114,0,NULL,'khh','kehu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3115,0,NULL,'khi','khoisan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(3116,0,NULL,'khj','kuturmi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3117,0,NULL,'khk','halh mongolian','1248825600',NULL,NULL,NULL,NULL,'mn',NULL,NULL); +INSERT INTO "iana_records" VALUES(3118,0,NULL,'khl','lusi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3119,0,NULL,'khn','khandesi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3120,0,NULL,'kho','khotanese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3120,0,NULL,'kho','sakan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3121,0,NULL,'khp','kapauri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3121,0,NULL,'khp','kapori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3122,0,NULL,'khq','koyra chiini songhay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3123,0,NULL,'khr','kharia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3124,0,NULL,'khs','kasua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3125,0,NULL,'kht','khamti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3126,0,NULL,'khu','nkhumbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3127,0,NULL,'khv','khvarshi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3128,0,NULL,'khw','khowar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3129,0,NULL,'khx','kanu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3130,0,NULL,'khy','kele (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3131,0,NULL,'khz','keapara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3132,0,NULL,'kia','kim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3133,0,NULL,'kib','koalib','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3134,0,NULL,'kic','kickapoo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3135,0,NULL,'kid','koshin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3136,0,NULL,'kie','kibet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3137,0,NULL,'kif','eastern parbate kham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3138,0,NULL,'kig','kimaama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3138,0,NULL,'kig','kimaghima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3139,0,NULL,'kih','kilmeri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3140,0,NULL,'kii','kitsai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3141,0,NULL,'kij','kilivila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3142,0,NULL,'kil','kariya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3143,0,NULL,'kim','karagas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3144,0,NULL,'kio','kiowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3145,0,NULL,'kip','sheshi kham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3146,0,NULL,'kiq','kosadle','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3146,0,NULL,'kiq','kosare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3147,0,NULL,'kis','kis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3148,0,NULL,'kit','agob','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3149,0,NULL,'kiu','kirmanjki (individual language)','1248825600',NULL,NULL,NULL,NULL,'zza',NULL,NULL); +INSERT INTO "iana_records" VALUES(3150,0,NULL,'kiv','kimbu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3151,0,NULL,'kiw','northeast kiwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3152,0,NULL,'kix','khiamniungan naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3153,0,NULL,'kiy','kirikiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3154,0,NULL,'kiz','kisi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3155,0,NULL,'kja','mlap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3156,0,NULL,'kjb','kanjobal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3156,0,NULL,'kjb','q''anjob''al','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3157,0,NULL,'kjc','coastal konjo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3158,0,NULL,'kjd','southern kiwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3159,0,NULL,'kje','kisar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3160,0,NULL,'kjf','khalaj','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3161,0,NULL,'kjg','khmu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3162,0,NULL,'kjh','khakas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3163,0,NULL,'kji','zabana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3164,0,NULL,'kjj','khinalugh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3165,0,NULL,'kjk','highland konjo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3166,0,NULL,'kjl','western parbate kham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3167,0,NULL,'kjm','kháng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3168,0,NULL,'kjn','kunjen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3169,0,NULL,'kjo','harijan kinnauri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3170,0,NULL,'kjp','pwo eastern karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3171,0,NULL,'kjq','western keres','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3172,0,NULL,'kjr','kurudu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3173,0,NULL,'kjs','east kewa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3174,0,NULL,'kjt','phrae pwo karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3175,0,NULL,'kju','kashaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3176,0,NULL,'kjx','ramopa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3177,0,NULL,'kjy','erave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3178,0,NULL,'kjz','bumthangkha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3179,0,NULL,'kka','kakanda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3180,0,NULL,'kkb','kwerisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3181,0,NULL,'kkc','odoodee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3182,0,NULL,'kkd','kinuku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3183,0,NULL,'kke','kakabe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3184,0,NULL,'kkf','kalaktang monpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3185,0,NULL,'kkg','mabaka valley kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3186,0,NULL,'kkh','khün','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3187,0,NULL,'kki','kagulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3188,0,NULL,'kkj','kako','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3189,0,NULL,'kkk','kokota','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3190,0,NULL,'kkl','kosarek yale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3191,0,NULL,'kkm','kiong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3192,0,NULL,'kkn','kon keu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3193,0,NULL,'kko','karko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3194,0,NULL,'kkp','gugubera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3195,0,NULL,'kkq','kaiku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3196,0,NULL,'kkr','kir-balar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3197,0,NULL,'kks','giiwo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3198,0,NULL,'kkt','koi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3199,0,NULL,'kku','tumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3200,0,NULL,'kkv','kangean','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3201,0,NULL,'kkw','teke-kukuya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3202,0,NULL,'kkx','kohin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3203,0,NULL,'kky','guguyimidjir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3204,0,NULL,'kkz','kaska','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3205,0,NULL,'kla','klamath-modoc','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3206,0,NULL,'klb','kiliwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3207,0,NULL,'klc','kolbila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3208,0,NULL,'kld','gamilaraay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3209,0,NULL,'kle','kulung (nepal)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3210,0,NULL,'klf','kendeje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3211,0,NULL,'klg','tagakaulo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3212,0,NULL,'klh','weliki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3213,0,NULL,'kli','kalumpang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3214,0,NULL,'klj','turkic khalaj','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3215,0,NULL,'klk','kono (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3216,0,NULL,'kll','kagan kalagan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3217,0,NULL,'klm','migum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3218,0,NULL,'kln','kalenjin','1248825600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(3219,0,NULL,'klo','kapya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3220,0,NULL,'klp','kamasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3221,0,NULL,'klq','rumu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3222,0,NULL,'klr','khaling','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3223,0,NULL,'kls','kalasha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3224,0,NULL,'klt','nukna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3225,0,NULL,'klu','klao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3226,0,NULL,'klv','maskelynes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3227,0,NULL,'klw','lindu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3228,0,NULL,'klx','koluwawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3229,0,NULL,'kly','kalao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3230,0,NULL,'klz','kabola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3231,0,NULL,'kma','konni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3232,0,NULL,'kmb','kimbundu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3233,0,NULL,'kmc','southern dong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3234,0,NULL,'kmd','majukayang kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3235,0,NULL,'kme','bakole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3236,0,NULL,'kmf','kare (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3237,0,NULL,'kmg','kâte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3238,0,NULL,'kmh','kalam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3239,0,NULL,'kmi','kami (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3240,0,NULL,'kmj','kumarbhag paharia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3241,0,NULL,'kmk','limos kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3242,0,NULL,'kml','lower tanudan kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3243,0,NULL,'kmm','kom (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3244,0,NULL,'kmn','awtuw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3245,0,NULL,'kmo','kwoma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3246,0,NULL,'kmp','gimme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3247,0,NULL,'kmq','kwama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3248,0,NULL,'kmr','northern kurdish','1248825600',NULL,NULL,NULL,NULL,'ku',NULL,NULL); +INSERT INTO "iana_records" VALUES(3249,0,NULL,'kms','kamasau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3250,0,NULL,'kmt','kemtuik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3251,0,NULL,'kmu','kanite','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3252,0,NULL,'kmv','karipúna creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3253,0,NULL,'kmw','komo (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3254,0,NULL,'kmx','waboda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3255,0,NULL,'kmy','koma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3256,0,NULL,'kmz','khorasani turkish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3257,0,NULL,'kna','dera (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3258,0,NULL,'knb','lubuagan kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3259,0,NULL,'knc','central kanuri','1248825600',NULL,NULL,NULL,NULL,'kr',NULL,NULL); +INSERT INTO "iana_records" VALUES(3260,0,NULL,'knd','konda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3261,0,NULL,'kne','kankanaey','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3262,0,NULL,'knf','mankanya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3263,0,NULL,'kng','koongo','1248825600',NULL,NULL,NULL,NULL,'kg',NULL,NULL); +INSERT INTO "iana_records" VALUES(3264,0,NULL,'kni','kanufi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3265,0,NULL,'knj','western kanjobal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3266,0,NULL,'knk','kuranko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3267,0,NULL,'knl','keninjal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3268,0,NULL,'knm','kanamarí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3269,0,NULL,'knn','konkani (individual language)','1248825600',NULL,NULL,NULL,NULL,'kok',NULL,NULL); +INSERT INTO "iana_records" VALUES(3270,0,NULL,'kno','kono (sierra leone)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3271,0,NULL,'knp','kwanja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3272,0,NULL,'knq','kintaq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3273,0,NULL,'knr','kaningra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3274,0,NULL,'kns','kensiu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3275,0,NULL,'knt','panoan katukína','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3276,0,NULL,'knu','kono (guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3277,0,NULL,'knv','tabo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3278,0,NULL,'knw','kung-ekoka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3279,0,NULL,'knx','kendayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3279,0,NULL,'knx','salako','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3280,0,NULL,'kny','kanyok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3281,0,NULL,'knz','kalamsé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3282,0,NULL,'koa','konomala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3283,0,NULL,'koc','kpati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3284,0,NULL,'kod','kodi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3285,0,NULL,'koe','kacipo-balesi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3286,0,NULL,'kof','kubi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3287,0,NULL,'kog','cogui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3287,0,NULL,'kog','kogi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3288,0,NULL,'koh','koyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3289,0,NULL,'koi','komi-permyak','1248825600',NULL,NULL,NULL,NULL,'kv',NULL,NULL); +INSERT INTO "iana_records" VALUES(3290,0,NULL,'koj','sara dunjo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3291,0,NULL,'kok','konkani (macrolanguage)','1129420800',NULL,NULL,NULL,'deva',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(3292,0,NULL,'kol','kol (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3293,0,NULL,'koo','konzo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3294,0,NULL,'kop','kwato','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3295,0,NULL,'koq','kota (gabon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3296,0,NULL,'kos','kosraean','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3297,0,NULL,'kot','lagwan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3298,0,NULL,'kou','koke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3299,0,NULL,'kov','kudu-camo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3300,0,NULL,'kow','kugama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3301,0,NULL,'kox','coxima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3302,0,NULL,'koy','koyukon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3303,0,NULL,'koz','korak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3304,0,NULL,'kpa','kutto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3305,0,NULL,'kpb','mullu kurumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3306,0,NULL,'kpc','curripaco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3307,0,NULL,'kpd','koba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3308,0,NULL,'kpe','kpelle','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(3309,0,NULL,'kpf','komba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3310,0,NULL,'kpg','kapingamarangi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3311,0,NULL,'kph','kplang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3312,0,NULL,'kpi','kofei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3313,0,NULL,'kpj','karajá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3314,0,NULL,'kpk','kpan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3315,0,NULL,'kpl','kpala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3316,0,NULL,'kpm','koho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3317,0,NULL,'kpn','kepkiriwát','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3318,0,NULL,'kpo','ikposo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3319,0,NULL,'kpp','paku karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3320,0,NULL,'kpq','korupun-sela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3321,0,NULL,'kpr','korafe-yegha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3322,0,NULL,'kps','tehit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3323,0,NULL,'kpt','karata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3324,0,NULL,'kpu','kafoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3325,0,NULL,'kpv','komi-zyrian','1248825600',NULL,NULL,NULL,NULL,'kv',NULL,NULL); +INSERT INTO "iana_records" VALUES(3326,0,NULL,'kpw','kobon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3327,0,NULL,'kpx','mountain koiali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3328,0,NULL,'kpy','koryak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3329,0,NULL,'kpz','kupsabiny','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3330,0,NULL,'kqa','mum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3331,0,NULL,'kqb','kovai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3332,0,NULL,'kqc','doromu-koki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3333,0,NULL,'kqd','koy sanjaq surat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3334,0,NULL,'kqe','kalagan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3335,0,NULL,'kqf','kakabai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3336,0,NULL,'kqg','khe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3337,0,NULL,'kqh','kisankasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3338,0,NULL,'kqi','koitabu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3339,0,NULL,'kqj','koromira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3340,0,NULL,'kqk','kotafon gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3341,0,NULL,'kql','kyenele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3342,0,NULL,'kqm','khisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3343,0,NULL,'kqn','kaonde','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3344,0,NULL,'kqo','eastern krahn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3345,0,NULL,'kqp','kimré','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3346,0,NULL,'kqq','krenak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3347,0,NULL,'kqr','kimaragang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3348,0,NULL,'kqs','northern kissi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3349,0,NULL,'kqt','klias river kadazan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3350,0,NULL,'kqu','seroa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3351,0,NULL,'kqv','okolod','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3352,0,NULL,'kqw','kandas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3353,0,NULL,'kqx','mser','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3354,0,NULL,'kqy','koorete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3355,0,NULL,'kqz','korana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3356,0,NULL,'kra','kumhali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3357,0,NULL,'krb','karkin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3358,0,NULL,'krc','karachay-balkar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3359,0,NULL,'krd','kairui-midiki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3360,0,NULL,'kre','panará','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3361,0,NULL,'krf','koro (vanuatu)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3362,0,NULL,'krh','kurama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3363,0,NULL,'kri','krio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3364,0,NULL,'krj','kinaray-a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3365,0,NULL,'krk','kerek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3366,0,NULL,'krl','karelian','1141776000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3367,0,NULL,'krm','krim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3368,0,NULL,'krn','sapo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3369,0,NULL,'kro','kru languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(3370,0,NULL,'krp','korop','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3371,0,NULL,'krr','kru''ng 2','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3372,0,NULL,'krs','gbaya (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3373,0,NULL,'krt','tumari kanuri','1248825600',NULL,NULL,NULL,NULL,'kr',NULL,NULL); +INSERT INTO "iana_records" VALUES(3374,0,NULL,'kru','kurukh','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3375,0,NULL,'krv','kavet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3376,0,NULL,'krw','western krahn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3377,0,NULL,'krx','karon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3378,0,NULL,'kry','kryts','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3379,0,NULL,'krz','sota kanum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3380,0,NULL,'ksa','shuwa-zamani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3381,0,NULL,'ksb','shambala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3382,0,NULL,'ksc','southern kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3383,0,NULL,'ksd','kuanua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3384,0,NULL,'kse','kuni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3385,0,NULL,'ksf','bafia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3386,0,NULL,'ksg','kusaghe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3387,0,NULL,'ksh','kölsch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3388,0,NULL,'ksi','i''saka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3388,0,NULL,'ksi','krisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3389,0,NULL,'ksj','uare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3390,0,NULL,'ksk','kansa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3391,0,NULL,'ksl','kumalu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3392,0,NULL,'ksm','kumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3393,0,NULL,'ksn','kasiguranin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3394,0,NULL,'kso','kofa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3395,0,NULL,'ksp','kaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3396,0,NULL,'ksq','kwaami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3397,0,NULL,'ksr','borong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3398,0,NULL,'kss','southern kisi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3399,0,NULL,'kst','winyé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3400,0,NULL,'ksu','khamyang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3401,0,NULL,'ksv','kusu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3402,0,NULL,'ksw','s''gaw karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3403,0,NULL,'ksx','kedang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3404,0,NULL,'ksy','kharia thar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3405,0,NULL,'ksz','kodaku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3406,0,NULL,'kta','katua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3407,0,NULL,'ktb','kambaata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3408,0,NULL,'ktc','kholok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3409,0,NULL,'ktd','kokata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3410,0,NULL,'kte','nubri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3411,0,NULL,'ktf','kwami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3412,0,NULL,'ktg','kalkutung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3413,0,NULL,'kth','karanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3414,0,NULL,'kti','north muyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3415,0,NULL,'ktj','plapo krumen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3416,0,NULL,'ktk','kaniet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3417,0,NULL,'ktl','koroshi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3418,0,NULL,'ktm','kurti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3419,0,NULL,'ktn','karitiâna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3420,0,NULL,'kto','kuot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3421,0,NULL,'ktp','kaduo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3422,0,NULL,'ktq','katabaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3423,0,NULL,'ktr','kota marudu tinagas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3424,0,NULL,'kts','south muyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3425,0,NULL,'ktt','ketum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3426,0,NULL,'ktu','kituba (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3427,0,NULL,'ktv','eastern katu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3428,0,NULL,'ktw','kato','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3429,0,NULL,'ktx','kaxararí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3430,0,NULL,'kty','kango (bas-uélé district)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3431,0,NULL,'ktz','ju/''hoan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3432,0,NULL,'kub','kutep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3433,0,NULL,'kuc','kwinsu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3434,0,NULL,'kud','''auhelawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3435,0,NULL,'kue','kuman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3436,0,NULL,'kuf','western katu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3437,0,NULL,'kug','kupa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3438,0,NULL,'kuh','kushi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3439,0,NULL,'kui','kuikúro-kalapálo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3440,0,NULL,'kuj','kuria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3441,0,NULL,'kuk','kepo''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3442,0,NULL,'kul','kulere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3443,0,NULL,'kum','kumyk','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3444,0,NULL,'kun','kunama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3445,0,NULL,'kuo','kumukio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3446,0,NULL,'kup','kunimaipa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3447,0,NULL,'kuq','karipuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3448,0,NULL,'kus','kusaal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3449,0,NULL,'kut','kutenai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3450,0,NULL,'kuu','upper kuskokwim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3451,0,NULL,'kuv','kur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3452,0,NULL,'kuw','kpagua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3453,0,NULL,'kux','kukatja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3454,0,NULL,'kuy','kuuku-ya''u','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3455,0,NULL,'kuz','kunza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3456,0,NULL,'kva','bagvalal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3457,0,NULL,'kvb','kubu','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(3458,0,NULL,'kvc','kove','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3459,0,NULL,'kvd','kui (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3460,0,NULL,'kve','kalabakan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3461,0,NULL,'kvf','kabalai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3462,0,NULL,'kvg','kuni-boazi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3463,0,NULL,'kvh','komodo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3464,0,NULL,'kvi','kwang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3465,0,NULL,'kvj','psikye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3466,0,NULL,'kvk','korean sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3467,0,NULL,'kvl','brek karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3468,0,NULL,'kvm','kendem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3469,0,NULL,'kvn','border kuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3470,0,NULL,'kvo','dobel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3471,0,NULL,'kvp','kompane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3472,0,NULL,'kvq','geba karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3473,0,NULL,'kvr','kerinci','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(3474,0,NULL,'kvs','kunggara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3475,0,NULL,'kvt','lahta karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3476,0,NULL,'kvu','yinbaw karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3477,0,NULL,'kvv','kola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3478,0,NULL,'kvw','wersing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3479,0,NULL,'kvx','parkari koli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3480,0,NULL,'kvy','yintale karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3481,0,NULL,'kvz','tsakwambo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3481,0,NULL,'kvz','tsaukambo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3482,0,NULL,'kwa','dâw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3483,0,NULL,'kwb','kwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3484,0,NULL,'kwc','likwala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3485,0,NULL,'kwd','kwaio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3486,0,NULL,'kwe','kwerba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3487,0,NULL,'kwf','kwara''ae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3488,0,NULL,'kwg','sara kaba deme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3489,0,NULL,'kwh','kowiai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3490,0,NULL,'kwi','awa-cuaiquer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3491,0,NULL,'kwj','kwanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3492,0,NULL,'kwk','kwakiutl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3493,0,NULL,'kwl','kofyar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3494,0,NULL,'kwm','kwambi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3495,0,NULL,'kwn','kwangali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3496,0,NULL,'kwo','kwomtari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3497,0,NULL,'kwp','kodia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3498,0,NULL,'kwq','kwak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3499,0,NULL,'kwr','kwer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3500,0,NULL,'kws','kwese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3501,0,NULL,'kwt','kwesten','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3502,0,NULL,'kwu','kwakum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3503,0,NULL,'kwv','sara kaba náà','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3504,0,NULL,'kww','kwinti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3505,0,NULL,'kwx','khirwar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3506,0,NULL,'kwy','san salvador kongo','1248825600',NULL,NULL,NULL,NULL,'kg',NULL,NULL); +INSERT INTO "iana_records" VALUES(3507,0,NULL,'kwz','kwadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3508,0,NULL,'kxa','kairiru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3509,0,NULL,'kxb','krobu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3510,0,NULL,'kxc','khonso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3510,0,NULL,'kxc','konso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3511,0,NULL,'kxd','brunei','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(3512,0,NULL,'kxe','kakihum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3513,0,NULL,'kxf','manumanaw karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3514,0,NULL,'kxh','karo (ethiopia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3515,0,NULL,'kxi','keningau murut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3516,0,NULL,'kxj','kulfa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3517,0,NULL,'kxk','zayein karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3518,0,NULL,'kxl','nepali kurux','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3519,0,NULL,'kxm','northern khmer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3520,0,NULL,'kxn','kanowit-tanjong melanau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3521,0,NULL,'kxo','kanoé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3522,0,NULL,'kxp','wadiyara koli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3523,0,NULL,'kxq','smärky kanum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3524,0,NULL,'kxr','koro (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3525,0,NULL,'kxs','kangjia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3526,0,NULL,'kxt','koiwat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3527,0,NULL,'kxu','kui (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3528,0,NULL,'kxv','kuvi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3529,0,NULL,'kxw','konai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3530,0,NULL,'kxx','likuba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3531,0,NULL,'kxy','kayong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3532,0,NULL,'kxz','kerewo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3533,0,NULL,'kya','kwaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3534,0,NULL,'kyb','butbut kalinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3535,0,NULL,'kyc','kyaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3536,0,NULL,'kyd','karey','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3537,0,NULL,'kye','krache','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3538,0,NULL,'kyf','kouya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3539,0,NULL,'kyg','keyagana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3540,0,NULL,'kyh','karok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3541,0,NULL,'kyi','kiput','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3542,0,NULL,'kyj','karao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3543,0,NULL,'kyk','kamayo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3544,0,NULL,'kyl','kalapuya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3545,0,NULL,'kym','kpatili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3546,0,NULL,'kyn','northern binukidnon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3547,0,NULL,'kyo','kelon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3548,0,NULL,'kyp','kang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3549,0,NULL,'kyq','kenga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3550,0,NULL,'kyr','kuruáya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3551,0,NULL,'kys','baram kayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3552,0,NULL,'kyt','kayagar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3553,0,NULL,'kyu','western kayah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3554,0,NULL,'kyv','kayort','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3555,0,NULL,'kyw','kudmali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3556,0,NULL,'kyx','rapoisi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3557,0,NULL,'kyy','kambaira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3558,0,NULL,'kyz','kayabí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3559,0,NULL,'kza','western karaboro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3560,0,NULL,'kzb','kaibobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3561,0,NULL,'kzc','bondoukou kulango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3562,0,NULL,'kzd','kadai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3563,0,NULL,'kze','kosena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3564,0,NULL,'kzf','da''a kaili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3565,0,NULL,'kzg','kikai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3566,0,NULL,'kzh','kenuzi-dongola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3567,0,NULL,'kzi','kelabit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3568,0,NULL,'kzj','coastal kadazan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3569,0,NULL,'kzk','kazukuru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3570,0,NULL,'kzl','kayeli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3571,0,NULL,'kzm','kais','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3572,0,NULL,'kzn','kokola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3573,0,NULL,'kzo','kaningi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3574,0,NULL,'kzp','kaidipang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3575,0,NULL,'kzq','kaike','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3576,0,NULL,'kzr','karang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3577,0,NULL,'kzs','sugut dusun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3578,0,NULL,'kzt','tambunan dusun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3579,0,NULL,'kzu','kayupulau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3580,0,NULL,'kzv','komyandaret','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3581,0,NULL,'kzw','karirí-xocó','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3582,0,NULL,'kzx','kamarian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3583,0,NULL,'kzy','kango (tshopo district)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3584,0,NULL,'kzz','kalabra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3585,0,NULL,'laa','southern subanen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3586,0,NULL,'lab','linear a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3587,0,NULL,'lac','lacandon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3588,0,NULL,'lad','ladino','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3589,0,NULL,'lae','pattani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3590,0,NULL,'laf','lafofa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3591,0,NULL,'lag','langi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3592,0,NULL,'lah','lahnda','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(3593,0,NULL,'lai','lambya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3594,0,NULL,'laj','lango (uganda)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3595,0,NULL,'lak','laka (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3596,0,NULL,'lal','lalia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3597,0,NULL,'lam','lamba','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3598,0,NULL,'lan','laru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3599,0,NULL,'lap','laka (chad)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3600,0,NULL,'laq','qabiao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3601,0,NULL,'lar','larteh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3602,0,NULL,'las','lama (togo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3603,0,NULL,'lau','laba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3604,0,NULL,'law','lauje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3605,0,NULL,'lax','tiwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3606,0,NULL,'lay','lama (myanmar)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3607,0,NULL,'laz','aribwatsa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3608,0,NULL,'lba','lui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3609,0,NULL,'lbb','label','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3610,0,NULL,'lbc','lakkia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3611,0,NULL,'lbe','lak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3612,0,NULL,'lbf','tinani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3613,0,NULL,'lbg','laopang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3614,0,NULL,'lbi','la''bi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3615,0,NULL,'lbj','ladakhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3616,0,NULL,'lbk','central bontok','1268265600',NULL,NULL,NULL,NULL,'bnc',NULL,NULL); +INSERT INTO "iana_records" VALUES(3617,0,NULL,'lbl','libon bikol','1268265600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(3618,0,NULL,'lbm','lodhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3619,0,NULL,'lbn','lamet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3620,0,NULL,'lbo','laven','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3621,0,NULL,'lbq','wampar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3622,0,NULL,'lbr','northern lorung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3623,0,NULL,'lbs','libyan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3624,0,NULL,'lbt','lachi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3625,0,NULL,'lbu','labu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3626,0,NULL,'lbv','lavatbura-lamusong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3627,0,NULL,'lbw','tolaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3628,0,NULL,'lbx','lawangan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3629,0,NULL,'lby','lamu-lamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3630,0,NULL,'lbz','lardil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3631,0,NULL,'lcc','legenyem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3632,0,NULL,'lcd','lola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3633,0,NULL,'lce','loncong','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(3634,0,NULL,'lcf','lubu','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(3635,0,NULL,'lch','luchazi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3636,0,NULL,'lcl','lisela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3637,0,NULL,'lcm','tungag','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3638,0,NULL,'lcp','western lawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3639,0,NULL,'lcq','luhu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3640,0,NULL,'lcs','lisabata-nuniali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3641,0,NULL,'ldb','idun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3642,0,NULL,'ldd','luri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3643,0,NULL,'ldg','lenyima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3644,0,NULL,'ldh','lamja-dengsa-tola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3645,0,NULL,'ldi','laari','1248825600',NULL,NULL,NULL,NULL,'kg',NULL,NULL); +INSERT INTO "iana_records" VALUES(3646,0,NULL,'ldj','lemoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3647,0,NULL,'ldk','leelau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3648,0,NULL,'ldl','kaan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3649,0,NULL,'ldm','landoma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3650,0,NULL,'ldn','láadan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3651,0,NULL,'ldo','loo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3652,0,NULL,'ldp','tso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3653,0,NULL,'ldq','lufu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3654,0,NULL,'lea','lega-shabunda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3655,0,NULL,'leb','lala-bisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3656,0,NULL,'lec','leco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3657,0,NULL,'led','lendu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3658,0,NULL,'lee','lyélé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3659,0,NULL,'lef','lelemi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3660,0,NULL,'leg','lengua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3661,0,NULL,'leh','lenje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3662,0,NULL,'lei','lemio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3663,0,NULL,'lej','lengola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3664,0,NULL,'lek','leipon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3665,0,NULL,'lel','lele (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3666,0,NULL,'lem','nomaande','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3667,0,NULL,'len','lenca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3668,0,NULL,'leo','leti (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3669,0,NULL,'lep','lepcha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3670,0,NULL,'leq','lembena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3671,0,NULL,'ler','lenkau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3672,0,NULL,'les','lese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3673,0,NULL,'let','lesing-gelimi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3674,0,NULL,'leu','kara (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3675,0,NULL,'lev','lamma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3676,0,NULL,'lew','ledo kaili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3677,0,NULL,'lex','luang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3678,0,NULL,'ley','lemolang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3679,0,NULL,'lez','lezghian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3680,0,NULL,'lfa','lefa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3681,0,NULL,'lfn','lingua franca nova','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3682,0,NULL,'lga','lungga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3683,0,NULL,'lgb','laghu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3684,0,NULL,'lgg','lugbara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3685,0,NULL,'lgh','laghuu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3686,0,NULL,'lgi','lengilu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3687,0,NULL,'lgk','lingarak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3687,0,NULL,'lgk','neverver','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3688,0,NULL,'lgl','wala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3689,0,NULL,'lgm','lega-mwenga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3690,0,NULL,'lgn','opuuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3691,0,NULL,'lgq','logba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3692,0,NULL,'lgr','lengo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3693,0,NULL,'lgt','pahi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3694,0,NULL,'lgu','longgu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3695,0,NULL,'lgz','ligenza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3696,0,NULL,'lha','laha (viet nam)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3697,0,NULL,'lhh','laha (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3698,0,NULL,'lhi','lahu shi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3699,0,NULL,'lhl','lahul lohar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3700,0,NULL,'lhm','lhomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3701,0,NULL,'lhn','lahanan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3702,0,NULL,'lhp','lhokpu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3703,0,NULL,'lhs','mlahsö','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3704,0,NULL,'lht','lo-toga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3705,0,NULL,'lhu','lahu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3706,0,NULL,'lia','west-central limba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3707,0,NULL,'lib','likum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3708,0,NULL,'lic','hlai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3709,0,NULL,'lid','nyindrou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3710,0,NULL,'lie','likila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3711,0,NULL,'lif','limbu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3712,0,NULL,'lig','ligbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3713,0,NULL,'lih','lihir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3714,0,NULL,'lii','lingkhim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3715,0,NULL,'lij','ligurian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3716,0,NULL,'lik','lika','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3717,0,NULL,'lil','lillooet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3718,0,NULL,'lio','liki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3719,0,NULL,'lip','sekpele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3720,0,NULL,'liq','libido','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3721,0,NULL,'lir','liberian english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3722,0,NULL,'lis','lisu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3723,0,NULL,'liu','logorik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3724,0,NULL,'liv','liv','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3725,0,NULL,'liw','col','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(3726,0,NULL,'lix','liabuku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3727,0,NULL,'liy','banda-bambari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3728,0,NULL,'liz','libinza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3729,0,NULL,'lje','rampi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3730,0,NULL,'lji','laiyolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3731,0,NULL,'ljl','li''o','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3732,0,NULL,'ljp','lampung api','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3733,0,NULL,'lka','lakalei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3734,0,NULL,'lkb','kabras','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3734,0,NULL,'lkb','lukabaras','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3735,0,NULL,'lkc','kucong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3736,0,NULL,'lkd','lakondê','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3737,0,NULL,'lke','kenyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3738,0,NULL,'lkh','lakha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3739,0,NULL,'lki','laki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3740,0,NULL,'lkj','remun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3741,0,NULL,'lkl','laeko-libuat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3742,0,NULL,'lkn','lakon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3742,0,NULL,'lkn','vure','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3743,0,NULL,'lko','khayo','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3743,0,NULL,'lko','olukhayo','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3744,0,NULL,'lkr','päri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3745,0,NULL,'lks','kisa','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3745,0,NULL,'lks','olushisa','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3746,0,NULL,'lkt','lakota','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3747,0,NULL,'lky','lokoya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3748,0,NULL,'lla','lala-roba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3749,0,NULL,'llb','lolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3750,0,NULL,'llc','lele (guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3751,0,NULL,'lld','ladin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3752,0,NULL,'lle','lele (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3753,0,NULL,'llf','hermit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3754,0,NULL,'llg','lole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3755,0,NULL,'llh','lamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3756,0,NULL,'lli','teke-laali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3757,0,NULL,'llk','lelak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3758,0,NULL,'lll','lilau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3759,0,NULL,'llm','lasalimu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3760,0,NULL,'lln','lele (chad)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3761,0,NULL,'llo','khlor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3762,0,NULL,'llp','north efate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3763,0,NULL,'llq','lolak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3764,0,NULL,'lls','lithuanian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3765,0,NULL,'llu','lau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3766,0,NULL,'llx','lauan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3767,0,NULL,'lma','east limba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3768,0,NULL,'lmb','merei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3769,0,NULL,'lmc','limilngan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3770,0,NULL,'lmd','lumun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3771,0,NULL,'lme','pévé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3772,0,NULL,'lmf','south lembata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3773,0,NULL,'lmg','lamogai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3774,0,NULL,'lmh','lambichhong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3775,0,NULL,'lmi','lombi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3776,0,NULL,'lmj','west lembata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3777,0,NULL,'lmk','lamkang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3778,0,NULL,'lml','hano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3779,0,NULL,'lmm','lamam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3780,0,NULL,'lmn','lambadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3781,0,NULL,'lmo','lombard','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3782,0,NULL,'lmp','limbum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3783,0,NULL,'lmq','lamatuka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3784,0,NULL,'lmr','lamalera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3785,0,NULL,'lmu','lamenu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3786,0,NULL,'lmv','lomaiviti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3787,0,NULL,'lmw','lake miwok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3788,0,NULL,'lmx','laimbue','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3789,0,NULL,'lmy','lamboya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3790,0,NULL,'lmz','lumbee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3791,0,NULL,'lna','langbashe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3792,0,NULL,'lnb','mbalanhu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3793,0,NULL,'lnd','lun bawang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3793,0,NULL,'lnd','lundayeh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3794,0,NULL,'lng','langobardic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3795,0,NULL,'lnh','lanoh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3796,0,NULL,'lni','daantanai''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3797,0,NULL,'lnj','leningitij','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3798,0,NULL,'lnl','south central banda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3799,0,NULL,'lnm','langam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3800,0,NULL,'lnn','lorediakarkar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3801,0,NULL,'lno','lango (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3802,0,NULL,'lns','lamnso''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3803,0,NULL,'lnu','longuda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3804,0,NULL,'lnz','lonzo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3805,0,NULL,'loa','loloda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3806,0,NULL,'lob','lobi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3807,0,NULL,'loc','inonhan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3808,0,NULL,'loe','saluan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3809,0,NULL,'lof','logol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3810,0,NULL,'log','logo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3811,0,NULL,'loh','narim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3812,0,NULL,'loi','loma (côte d''ivoire)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3813,0,NULL,'loj','lou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3814,0,NULL,'lok','loko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3815,0,NULL,'lol','mongo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3816,0,NULL,'lom','loma (liberia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3817,0,NULL,'lon','malawi lomwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3818,0,NULL,'loo','lombo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3819,0,NULL,'lop','lopa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3820,0,NULL,'loq','lobala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3821,0,NULL,'lor','téén','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3822,0,NULL,'los','loniu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3823,0,NULL,'lot','otuho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3824,0,NULL,'lou','louisiana creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3825,0,NULL,'lov','lopi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3826,0,NULL,'low','tampias lobu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3827,0,NULL,'lox','loun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3828,0,NULL,'loy','lowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3829,0,NULL,'loz','lozi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3830,0,NULL,'lpa','lelepa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3831,0,NULL,'lpe','lepki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3832,0,NULL,'lpn','long phuri naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3833,0,NULL,'lpo','lipo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3834,0,NULL,'lpx','lopit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3835,0,NULL,'lra','rara bakati''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3836,0,NULL,'lrc','northern luri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3837,0,NULL,'lre','laurentian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3838,0,NULL,'lrg','laragia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3839,0,NULL,'lri','marachi','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3839,0,NULL,'lri','olumarachi','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3840,0,NULL,'lrk','loarki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3841,0,NULL,'lrl','lari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3842,0,NULL,'lrm','marama','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3842,0,NULL,'lrm','olumarama','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3843,0,NULL,'lrn','lorang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3844,0,NULL,'lro','laro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3845,0,NULL,'lrr','southern lorung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3846,0,NULL,'lrt','larantuka malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3847,0,NULL,'lrv','larevat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3848,0,NULL,'lrz','lemerig','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3849,0,NULL,'lsa','lasgerdi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3850,0,NULL,'lsd','lishana deni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3851,0,NULL,'lse','lusengo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3852,0,NULL,'lsg','lyons sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3853,0,NULL,'lsh','lish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3854,0,NULL,'lsi','lashi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3855,0,NULL,'lsl','latvian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3856,0,NULL,'lsm','olusamia','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3856,0,NULL,'lsm','saamia','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3857,0,NULL,'lso','laos sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3858,0,NULL,'lsp','lengua de señas panameñas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3858,0,NULL,'lsp','panamanian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3859,0,NULL,'lsr','aruop','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3860,0,NULL,'lss','lasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3861,0,NULL,'lst','trinidad and tobago sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3862,0,NULL,'lsy','mauritian sign language','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3863,0,NULL,'ltc','late middle chinese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3864,0,NULL,'ltg','latgalian','1268265600',NULL,NULL,NULL,NULL,'lv',NULL,NULL); +INSERT INTO "iana_records" VALUES(3865,0,NULL,'lti','leti (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3866,0,NULL,'ltn','latundê','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3867,0,NULL,'lto','olutsotso','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3867,0,NULL,'lto','tsotso','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3868,0,NULL,'lts','lutachoni','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3868,0,NULL,'lts','tachoni','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3869,0,NULL,'ltu','latu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3870,0,NULL,'lua','luba-lulua','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3871,0,NULL,'luc','aringa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3872,0,NULL,'lud','ludian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3873,0,NULL,'lue','luvale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3874,0,NULL,'luf','laua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3875,0,NULL,'lui','luiseno','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3876,0,NULL,'luj','luna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3877,0,NULL,'luk','lunanakha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3878,0,NULL,'lul','olu''bo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3879,0,NULL,'lum','luimbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3880,0,NULL,'lun','lunda','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3881,0,NULL,'luo','dholuo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3881,0,NULL,'luo','luo (kenya and tanzania)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3882,0,NULL,'lup','lumbu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3883,0,NULL,'luq','lucumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3884,0,NULL,'lur','laura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3885,0,NULL,'lus','lushai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3886,0,NULL,'lut','lushootseed','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3887,0,NULL,'luu','lumba-yakkha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3888,0,NULL,'luv','luwati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3889,0,NULL,'luw','luo (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3890,0,NULL,'luy','luyia','1248825600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(3890,0,NULL,'luy','oluluyia','1248825600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(3891,0,NULL,'luz','southern luri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3892,0,NULL,'lva','maku''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3893,0,NULL,'lvk','lavukaleve','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3894,0,NULL,'lvs','standard latvian','1268265600',NULL,NULL,NULL,NULL,'lv',NULL,NULL); +INSERT INTO "iana_records" VALUES(3895,0,NULL,'lvu','levuka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3896,0,NULL,'lwa','lwalu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3897,0,NULL,'lwe','lewo eleng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3898,0,NULL,'lwg','oluwanga','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3898,0,NULL,'lwg','wanga','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(3899,0,NULL,'lwh','white lachi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3900,0,NULL,'lwl','eastern lawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3901,0,NULL,'lwm','laomian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3902,0,NULL,'lwo','luwo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3903,0,NULL,'lwt','lewotobi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3904,0,NULL,'lww','lewo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3905,0,NULL,'lya','layakha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3906,0,NULL,'lyg','lyngngam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3907,0,NULL,'lyn','luyana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3908,0,NULL,'lzh','literary chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(3909,0,NULL,'lzl','litzlitz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3910,0,NULL,'lzn','leinong naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3911,0,NULL,'lzz','laz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3912,0,NULL,'maa','san jerónimo tecóatl mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3913,0,NULL,'mab','yutanduchi mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3914,0,NULL,'mad','madurese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3915,0,NULL,'mae','bo-rukul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3916,0,NULL,'maf','mafa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3917,0,NULL,'mag','magahi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3918,0,NULL,'mai','maithili','1129420800',NULL,NULL,NULL,'deva',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3919,0,NULL,'maj','jalapa de díaz mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3920,0,NULL,'mak','makasar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3921,0,NULL,'mam','mam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3922,0,NULL,'man','mandingo','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(3923,0,NULL,'map','austronesian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(3924,0,NULL,'maq','chiquihuitlán mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3925,0,NULL,'mas','masai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3926,0,NULL,'mat','san francisco matlatzinca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3927,0,NULL,'mau','huautla mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3928,0,NULL,'mav','sateré-mawé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3929,0,NULL,'maw','mampruli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3930,0,NULL,'max','north moluccan malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(3931,0,NULL,'maz','central mazahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3932,0,NULL,'mba','higaonon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3933,0,NULL,'mbb','western bukidnon manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3934,0,NULL,'mbc','macushi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3935,0,NULL,'mbd','dibabawon manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3936,0,NULL,'mbe','molale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3937,0,NULL,'mbf','baba malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3938,0,NULL,'mbh','mangseng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3939,0,NULL,'mbi','ilianen manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3940,0,NULL,'mbj','nadëb','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3941,0,NULL,'mbk','malol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3942,0,NULL,'mbl','maxakalí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3943,0,NULL,'mbm','ombamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3944,0,NULL,'mbn','macaguán','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3945,0,NULL,'mbo','mbo (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3946,0,NULL,'mbp','malayo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3947,0,NULL,'mbq','maisin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3948,0,NULL,'mbr','nukak makú','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3949,0,NULL,'mbs','sarangani manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3950,0,NULL,'mbt','matigsalug manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3951,0,NULL,'mbu','mbula-bwazza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3952,0,NULL,'mbv','mbulungish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3953,0,NULL,'mbw','maring','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3954,0,NULL,'mbx','mari (east sepik province)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3955,0,NULL,'mby','memoni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3956,0,NULL,'mbz','amoltepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3957,0,NULL,'mca','maca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3958,0,NULL,'mcb','machiguenga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3959,0,NULL,'mcc','bitur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3960,0,NULL,'mcd','sharanahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3961,0,NULL,'mce','itundujia mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3962,0,NULL,'mcf','matsés','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3963,0,NULL,'mcg','mapoyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3964,0,NULL,'mch','maquiritari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3965,0,NULL,'mci','mese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3966,0,NULL,'mcj','mvanip','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3967,0,NULL,'mck','mbunda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3968,0,NULL,'mcl','macaguaje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3969,0,NULL,'mcm','malaccan creole portuguese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3970,0,NULL,'mcn','masana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3971,0,NULL,'mco','coatlán mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3972,0,NULL,'mcp','makaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3973,0,NULL,'mcq','ese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3974,0,NULL,'mcr','menya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3975,0,NULL,'mcs','mambai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3976,0,NULL,'mct','mengisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3977,0,NULL,'mcu','cameroon mambila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3978,0,NULL,'mcv','minanibai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3979,0,NULL,'mcw','mawa (chad)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3980,0,NULL,'mcx','mpiemo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3981,0,NULL,'mcy','south watut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3982,0,NULL,'mcz','mawan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3983,0,NULL,'mda','mada (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3984,0,NULL,'mdb','morigi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3985,0,NULL,'mdc','male (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3986,0,NULL,'mdd','mbum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3987,0,NULL,'mde','maba (chad)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3988,0,NULL,'mdf','moksha','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3989,0,NULL,'mdg','massalat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3990,0,NULL,'mdh','maguindanaon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3991,0,NULL,'mdi','mamvu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3992,0,NULL,'mdj','mangbetu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3993,0,NULL,'mdk','mangbutu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3994,0,NULL,'mdl','maltese sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3995,0,NULL,'mdm','mayogo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3996,0,NULL,'mdn','mbati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3997,0,NULL,'mdp','mbala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3998,0,NULL,'mdq','mbole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(3999,0,NULL,'mdr','mandar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4000,0,NULL,'mds','maria (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4001,0,NULL,'mdt','mbere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4002,0,NULL,'mdu','mboko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4003,0,NULL,'mdv','santa lucía monteverde mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4004,0,NULL,'mdw','mbosi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4005,0,NULL,'mdx','dizin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4006,0,NULL,'mdy','male (ethiopia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4007,0,NULL,'mdz','suruí do pará','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4008,0,NULL,'mea','menka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4009,0,NULL,'meb','ikobi-mena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4010,0,NULL,'mec','mara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4011,0,NULL,'med','melpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4012,0,NULL,'mee','mengen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4013,0,NULL,'mef','megam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4014,0,NULL,'meg','mea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4015,0,NULL,'meh','southwestern tlaxiaco mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4016,0,NULL,'mei','midob','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4017,0,NULL,'mej','meyah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4018,0,NULL,'mek','mekeo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4019,0,NULL,'mel','central melanau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4020,0,NULL,'mem','mangala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4021,0,NULL,'men','mende (sierra leone)','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4022,0,NULL,'meo','kedah malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(4023,0,NULL,'mep','miriwung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4024,0,NULL,'meq','merey','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4025,0,NULL,'mer','meru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4026,0,NULL,'mes','masmaje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4027,0,NULL,'met','mato','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4028,0,NULL,'meu','motu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4029,0,NULL,'mev','mann','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4030,0,NULL,'mew','maaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4031,0,NULL,'mey','hassaniyya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4032,0,NULL,'mez','menominee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4033,0,NULL,'mfa','pattani malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(4034,0,NULL,'mfb','bangka','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(4035,0,NULL,'mfc','mba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4036,0,NULL,'mfd','mendankwe-nkwen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4037,0,NULL,'mfe','morisyen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4038,0,NULL,'mff','naki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4039,0,NULL,'mfg','mixifore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4040,0,NULL,'mfh','matal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4041,0,NULL,'mfi','wandala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4042,0,NULL,'mfj','mefele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4043,0,NULL,'mfk','north mofu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4044,0,NULL,'mfl','putai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4045,0,NULL,'mfm','marghi south','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4046,0,NULL,'mfn','cross river mbembe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4047,0,NULL,'mfo','mbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4048,0,NULL,'mfp','makassar malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4049,0,NULL,'mfq','moba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4050,0,NULL,'mfr','marithiel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4051,0,NULL,'mfs','mexican sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4052,0,NULL,'mft','mokerang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4053,0,NULL,'mfu','mbwela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4054,0,NULL,'mfv','mandjak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4055,0,NULL,'mfw','mulaha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4056,0,NULL,'mfx','melo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4057,0,NULL,'mfy','mayo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4058,0,NULL,'mfz','mabaan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4059,0,NULL,'mga','middle irish (900-1200)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4060,0,NULL,'mgb','mararit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4061,0,NULL,'mgc','morokodo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4062,0,NULL,'mgd','moru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4063,0,NULL,'mge','mango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4064,0,NULL,'mgf','maklew','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4065,0,NULL,'mgg','mpongmpong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4066,0,NULL,'mgh','makhuwa-meetto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4067,0,NULL,'mgi','lijili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4068,0,NULL,'mgj','abureni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4069,0,NULL,'mgk','mawes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4070,0,NULL,'mgl','maleu-kilenge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4071,0,NULL,'mgm','mambae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4072,0,NULL,'mgn','mbangi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4073,0,NULL,'mgo','meta''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4074,0,NULL,'mgp','eastern magar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4075,0,NULL,'mgq','malila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4076,0,NULL,'mgr','mambwe-lungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4077,0,NULL,'mgs','manda (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4078,0,NULL,'mgt','mongol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4079,0,NULL,'mgu','mailu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4080,0,NULL,'mgv','matengo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4081,0,NULL,'mgw','matumbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4082,0,NULL,'mgx','omati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4083,0,NULL,'mgy','mbunga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4084,0,NULL,'mgz','mbugwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4085,0,NULL,'mha','manda (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4086,0,NULL,'mhb','mahongwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4087,0,NULL,'mhc','mocho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4088,0,NULL,'mhd','mbugu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4089,0,NULL,'mhe','besisi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4089,0,NULL,'mhe','mah meri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4090,0,NULL,'mhf','mamaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4091,0,NULL,'mhg','margu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4092,0,NULL,'mhh','maskoy pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4093,0,NULL,'mhi','ma''di','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4094,0,NULL,'mhj','mogholi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4095,0,NULL,'mhk','mungaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4096,0,NULL,'mhl','mauwake','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4097,0,NULL,'mhm','makhuwa-moniga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4098,0,NULL,'mhn','mócheno','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4099,0,NULL,'mho','mashi (zambia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4100,0,NULL,'mhp','balinese malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4101,0,NULL,'mhq','mandan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4102,0,NULL,'mhr','eastern mari','1248825600',NULL,NULL,NULL,NULL,'chm',NULL,NULL); +INSERT INTO "iana_records" VALUES(4103,0,NULL,'mhs','buru (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4104,0,NULL,'mht','mandahuaca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4105,0,NULL,'mhu','darang deng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4105,0,NULL,'mhu','digaro-mishmi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4106,0,NULL,'mhw','mbukushu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4107,0,NULL,'mhx','lhaovo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4107,0,NULL,'mhx','maru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4108,0,NULL,'mhy','ma''anyan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4109,0,NULL,'mhz','mor (mor islands)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4110,0,NULL,'mia','miami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4111,0,NULL,'mib','atatláhuca mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4112,0,NULL,'mic','mi''kmaq','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4112,0,NULL,'mic','micmac','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4113,0,NULL,'mid','mandaic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4114,0,NULL,'mie','ocotepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4115,0,NULL,'mif','mofu-gudur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4116,0,NULL,'mig','san miguel el grande mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4117,0,NULL,'mih','chayuco mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4118,0,NULL,'mii','chigmecatitlán mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4119,0,NULL,'mij','abar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4120,0,NULL,'mik','mikasuki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4121,0,NULL,'mil','peñoles mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4122,0,NULL,'mim','alacatlatzala mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4123,0,NULL,'min','minangkabau','1129420800',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(4124,0,NULL,'mio','pinotepa nacional mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4125,0,NULL,'mip','apasco-apoala mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4126,0,NULL,'miq','mískito','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4127,0,NULL,'mir','isthmus mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4128,0,NULL,'mis','uncoded languages','1129420800',NULL,NULL,NULL,NULL,NULL,'special',NULL); +INSERT INTO "iana_records" VALUES(4129,0,NULL,'mit','southern puebla mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4130,0,NULL,'miu','cacaloxtepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4131,0,NULL,'miw','akoye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4132,0,NULL,'mix','mixtepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4133,0,NULL,'miy','ayutla mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4134,0,NULL,'miz','coatzospan mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4135,0,NULL,'mja','mahei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4136,0,NULL,'mjc','san juan colorado mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4137,0,NULL,'mjd','northwest maidu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4138,0,NULL,'mje','muskum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4139,0,NULL,'mjg','tu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4140,0,NULL,'mjh','mwera (nyasa)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4141,0,NULL,'mji','kim mun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4142,0,NULL,'mjj','mawak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4143,0,NULL,'mjk','matukar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4144,0,NULL,'mjl','mandeali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4145,0,NULL,'mjm','medebur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4146,0,NULL,'mjn','ma (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4147,0,NULL,'mjo','malankuravan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4148,0,NULL,'mjp','malapandaram','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4149,0,NULL,'mjq','malaryan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4150,0,NULL,'mjr','malavedan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4151,0,NULL,'mjs','miship','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4152,0,NULL,'mjt','sauria paharia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4153,0,NULL,'mju','manna-dora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4154,0,NULL,'mjv','mannan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4155,0,NULL,'mjw','karbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4156,0,NULL,'mjx','mahali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4157,0,NULL,'mjy','mahican','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4158,0,NULL,'mjz','majhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4159,0,NULL,'mka','mbre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4160,0,NULL,'mkb','mal paharia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4161,0,NULL,'mkc','siliput','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4162,0,NULL,'mke','mawchi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4163,0,NULL,'mkf','miya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4164,0,NULL,'mkg','mak (china)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4165,0,NULL,'mkh','mon-khmer languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4166,0,NULL,'mki','dhatki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4167,0,NULL,'mkj','mokilese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4168,0,NULL,'mkk','byep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4169,0,NULL,'mkl','mokole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4170,0,NULL,'mkm','moklen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4171,0,NULL,'mkn','kupang malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4172,0,NULL,'mko','mingang doso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4173,0,NULL,'mkp','moikodi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4174,0,NULL,'mkq','bay miwok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4175,0,NULL,'mkr','malas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4176,0,NULL,'mks','silacayoapan mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4177,0,NULL,'mkt','vamale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4178,0,NULL,'mku','konyanka maninka','1248825600',NULL,NULL,NULL,NULL,'man',NULL,NULL); +INSERT INTO "iana_records" VALUES(4179,0,NULL,'mkv','mafea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4180,0,NULL,'mkw','kituba (congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4181,0,NULL,'mkx','kinamiging manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4182,0,NULL,'mky','east makian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4183,0,NULL,'mkz','makasae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4184,0,NULL,'mla','malo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4185,0,NULL,'mlb','mbule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4186,0,NULL,'mlc','cao lan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4187,0,NULL,'mld','malakhel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4188,0,NULL,'mle','manambu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4189,0,NULL,'mlf','mal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4190,0,NULL,'mlh','mape','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4191,0,NULL,'mli','malimpung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4192,0,NULL,'mlj','miltu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4193,0,NULL,'mlk','ilwana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4193,0,NULL,'mlk','kiwilwana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4194,0,NULL,'mll','malua bay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4195,0,NULL,'mlm','mulam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4196,0,NULL,'mln','malango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4197,0,NULL,'mlo','mlomp','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4198,0,NULL,'mlp','bargam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4199,0,NULL,'mlq','western maninkakan','1248825600',NULL,NULL,NULL,NULL,'man',NULL,NULL); +INSERT INTO "iana_records" VALUES(4200,0,NULL,'mlr','vame','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4201,0,NULL,'mls','masalit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4202,0,NULL,'mlu','to''abaita','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4203,0,NULL,'mlv','motlav','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4203,0,NULL,'mlv','mwotlap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4204,0,NULL,'mlw','moloko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4205,0,NULL,'mlx','malfaxal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4205,0,NULL,'mlx','naha''ai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4206,0,NULL,'mlz','malaynon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4207,0,NULL,'mma','mama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4208,0,NULL,'mmb','momina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4209,0,NULL,'mmc','michoacán mazahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4210,0,NULL,'mmd','maonan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4211,0,NULL,'mme','mae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4212,0,NULL,'mmf','mundat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4213,0,NULL,'mmg','north ambrym','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4214,0,NULL,'mmh','mehináku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4215,0,NULL,'mmi','musar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4216,0,NULL,'mmj','majhwar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4217,0,NULL,'mmk','mukha-dora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4218,0,NULL,'mml','man met','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4219,0,NULL,'mmm','maii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4220,0,NULL,'mmn','mamanwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4221,0,NULL,'mmo','mangga buang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4222,0,NULL,'mmp','siawi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4223,0,NULL,'mmq','musak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4224,0,NULL,'mmr','western xiangxi miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(4225,0,NULL,'mmt','malalamai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4226,0,NULL,'mmu','mmaala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4227,0,NULL,'mmv','miriti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4228,0,NULL,'mmw','emae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4229,0,NULL,'mmx','madak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4230,0,NULL,'mmy','migaama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4231,0,NULL,'mmz','mabaale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4232,0,NULL,'mna','mbula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4233,0,NULL,'mnb','muna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4234,0,NULL,'mnc','manchu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4235,0,NULL,'mnd','mondé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4236,0,NULL,'mne','naba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4237,0,NULL,'mnf','mundani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4238,0,NULL,'mng','eastern mnong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4239,0,NULL,'mnh','mono (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4240,0,NULL,'mni','manipuri','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4241,0,NULL,'mnj','munji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4242,0,NULL,'mnk','mandinka','1248825600',NULL,NULL,NULL,NULL,'man',NULL,NULL); +INSERT INTO "iana_records" VALUES(4243,0,NULL,'mnl','tiale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4244,0,NULL,'mnm','mapena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4245,0,NULL,'mnn','southern mnong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4246,0,NULL,'mno','manobo languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4247,0,NULL,'mnp','min bei chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(4248,0,NULL,'mnq','minriq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4249,0,NULL,'mnr','mono (usa)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4250,0,NULL,'mns','mansi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4251,0,NULL,'mnt','maykulan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4252,0,NULL,'mnu','mer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4253,0,NULL,'mnv','rennell-bellona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4254,0,NULL,'mnw','mon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4255,0,NULL,'mnx','manikion','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4256,0,NULL,'mny','manyawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4257,0,NULL,'mnz','moni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4258,0,NULL,'moa','mwan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4259,0,NULL,'moc','mocoví','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4260,0,NULL,'mod','mobilian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4261,0,NULL,'moe','montagnais','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4262,0,NULL,'mof','mohegan-montauk-narragansett','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see xnt, xpq'); +INSERT INTO "iana_records" VALUES(4263,0,NULL,'mog','mongondow','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4264,0,NULL,'moh','mohawk','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4265,0,NULL,'moi','mboi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4266,0,NULL,'moj','monzombo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4267,0,NULL,'mok','morori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4268,0,NULL,'mom','mangue','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4269,0,NULL,'moo','monom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4270,0,NULL,'mop','mopán maya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4271,0,NULL,'moq','mor (bomberai peninsula)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4272,0,NULL,'mor','moro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4273,0,NULL,'mos','mossi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4274,0,NULL,'mot','barí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4275,0,NULL,'mou','mogum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4276,0,NULL,'mov','mohave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4277,0,NULL,'mow','moi (congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4278,0,NULL,'mox','molima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4279,0,NULL,'moy','shekkacho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4280,0,NULL,'moz','mukulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4281,0,NULL,'mpa','mpoto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4282,0,NULL,'mpb','mullukmulluk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4283,0,NULL,'mpc','mangarayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4284,0,NULL,'mpd','machinere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4285,0,NULL,'mpe','majang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4286,0,NULL,'mpg','marba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4287,0,NULL,'mph','maung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4288,0,NULL,'mpi','mpade','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4289,0,NULL,'mpj','martu wangka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4290,0,NULL,'mpk','mbara (chad)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4291,0,NULL,'mpl','middle watut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4292,0,NULL,'mpm','yosondúa mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4293,0,NULL,'mpn','mindiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4294,0,NULL,'mpo','miu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4295,0,NULL,'mpp','migabac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4296,0,NULL,'mpq','matís','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4297,0,NULL,'mpr','vangunu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4298,0,NULL,'mps','dadibi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4299,0,NULL,'mpt','mian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4300,0,NULL,'mpu','makuráp','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4301,0,NULL,'mpv','mungkip','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4302,0,NULL,'mpw','mapidian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4303,0,NULL,'mpx','misima-paneati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4304,0,NULL,'mpy','mapia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4305,0,NULL,'mpz','mpi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4306,0,NULL,'mqa','maba (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4307,0,NULL,'mqb','mbuko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4308,0,NULL,'mqc','mangole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4309,0,NULL,'mqe','matepi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4310,0,NULL,'mqf','momuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4311,0,NULL,'mqg','kota bangun kutai malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(4312,0,NULL,'mqh','tlazoyaltepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4313,0,NULL,'mqi','mariri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4314,0,NULL,'mqj','mamasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4315,0,NULL,'mqk','rajah kabunsuwan manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4316,0,NULL,'mql','mbelime','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4317,0,NULL,'mqm','south marquesan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4318,0,NULL,'mqn','moronene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4319,0,NULL,'mqo','modole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4320,0,NULL,'mqp','manipa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4321,0,NULL,'mqq','minokok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4322,0,NULL,'mqr','mander','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4323,0,NULL,'mqs','west makian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4324,0,NULL,'mqt','mok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4325,0,NULL,'mqu','mandari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4326,0,NULL,'mqv','mosimo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4327,0,NULL,'mqw','murupi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4328,0,NULL,'mqx','mamuju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4329,0,NULL,'mqy','manggarai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4330,0,NULL,'mqz','malasanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4331,0,NULL,'mra','mlabri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4332,0,NULL,'mrb','marino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4333,0,NULL,'mrc','maricopa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4334,0,NULL,'mrd','western magar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4335,0,NULL,'mre','martha''s vineyard sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4336,0,NULL,'mrf','elseng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4337,0,NULL,'mrg','miri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4338,0,NULL,'mrh','mara chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4339,0,NULL,'mrj','western mari','1248825600',NULL,NULL,NULL,NULL,'chm',NULL,NULL); +INSERT INTO "iana_records" VALUES(4340,0,NULL,'mrk','hmwaveke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4341,0,NULL,'mrl','mortlockese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4342,0,NULL,'mrm','merlav','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4342,0,NULL,'mrm','mwerlap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4343,0,NULL,'mrn','cheke holo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4344,0,NULL,'mro','mru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4345,0,NULL,'mrp','morouas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4346,0,NULL,'mrq','north marquesan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4347,0,NULL,'mrr','maria (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4348,0,NULL,'mrs','maragus','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4349,0,NULL,'mrt','marghi central','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4350,0,NULL,'mru','mono (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4351,0,NULL,'mrv','mangareva','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4352,0,NULL,'mrw','maranao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4353,0,NULL,'mrx','dineor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4353,0,NULL,'mrx','maremgi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4354,0,NULL,'mry','mandaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4355,0,NULL,'mrz','marind','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4356,0,NULL,'msb','masbatenyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4357,0,NULL,'msc','sankaran maninka','1248825600',NULL,NULL,NULL,NULL,'man',NULL,NULL); +INSERT INTO "iana_records" VALUES(4358,0,NULL,'msd','yucatec maya sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4359,0,NULL,'mse','musey','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4360,0,NULL,'msf','mekwei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4361,0,NULL,'msg','moraid','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4362,0,NULL,'msh','masikoro malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(4363,0,NULL,'msi','sabah malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(4364,0,NULL,'msj','ma (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4365,0,NULL,'msk','mansaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4366,0,NULL,'msl','molof','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4366,0,NULL,'msl','poule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4367,0,NULL,'msm','agusan manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4368,0,NULL,'msn','vurës','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4369,0,NULL,'mso','mombum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4370,0,NULL,'msp','maritsauá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4371,0,NULL,'msq','caac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4372,0,NULL,'msr','mongolian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4373,0,NULL,'mss','west masela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4374,0,NULL,'mst','cataelano mandaya','1248825600',1268265600,'mry',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4375,0,NULL,'msu','musom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4376,0,NULL,'msv','maslam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4377,0,NULL,'msw','mansoanka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4378,0,NULL,'msx','moresada','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4379,0,NULL,'msy','aruamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4380,0,NULL,'msz','momare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4381,0,NULL,'mta','cotabato manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4382,0,NULL,'mtb','anyin morofo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4383,0,NULL,'mtc','munit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4384,0,NULL,'mtd','mualang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4385,0,NULL,'mte','mono (solomon islands)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4386,0,NULL,'mtf','murik (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4387,0,NULL,'mtg','una','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4388,0,NULL,'mth','munggui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4389,0,NULL,'mti','maiwa (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4390,0,NULL,'mtj','moskona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4391,0,NULL,'mtk','mbe''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4392,0,NULL,'mtl','montol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4393,0,NULL,'mtm','mator','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4394,0,NULL,'mtn','matagalpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4395,0,NULL,'mto','totontepec mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4396,0,NULL,'mtp','wichí lhamtés nocten','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4397,0,NULL,'mtq','muong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4398,0,NULL,'mtr','mewari','1248825600',NULL,NULL,NULL,NULL,'mwr',NULL,NULL); +INSERT INTO "iana_records" VALUES(4399,0,NULL,'mts','yora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4400,0,NULL,'mtt','mota','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4401,0,NULL,'mtu','tututepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4402,0,NULL,'mtv','asaro''o','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4403,0,NULL,'mtw','southern binukidnon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4404,0,NULL,'mtx','tidaá mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4405,0,NULL,'mty','nabi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4406,0,NULL,'mua','mundang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4407,0,NULL,'mub','mubi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4408,0,NULL,'muc','mbu''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4409,0,NULL,'mud','mednyj aleut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4410,0,NULL,'mue','media lengua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4411,0,NULL,'mug','musgu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4412,0,NULL,'muh','mündü','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4413,0,NULL,'mui','musi','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(4414,0,NULL,'muj','mabire','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4415,0,NULL,'muk','mugom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4416,0,NULL,'mul','multiple languages','1129420800',NULL,NULL,NULL,NULL,NULL,'special',NULL); +INSERT INTO "iana_records" VALUES(4417,0,NULL,'mum','maiwala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4418,0,NULL,'mun','munda languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4419,0,NULL,'muo','nyong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4420,0,NULL,'mup','malvi','1248825600',NULL,NULL,NULL,NULL,'raj',NULL,NULL); +INSERT INTO "iana_records" VALUES(4421,0,NULL,'muq','eastern xiangxi miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(4422,0,NULL,'mur','murle','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4423,0,NULL,'mus','creek','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4424,0,NULL,'mut','western muria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4425,0,NULL,'muu','yaaku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4426,0,NULL,'muv','muthuvan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4427,0,NULL,'mux','bo-ung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4428,0,NULL,'muy','muyang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4429,0,NULL,'muz','mursi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4430,0,NULL,'mva','manam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4431,0,NULL,'mvb','mattole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4432,0,NULL,'mvd','mamboru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4433,0,NULL,'mve','marwari (pakistan)','1248825600',NULL,NULL,NULL,NULL,'mwr',NULL,NULL); +INSERT INTO "iana_records" VALUES(4434,0,NULL,'mvf','peripheral mongolian','1248825600',NULL,NULL,NULL,NULL,'mn',NULL,NULL); +INSERT INTO "iana_records" VALUES(4435,0,NULL,'mvg','yucuañe mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4436,0,NULL,'mvh','mire','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4437,0,NULL,'mvi','miyako','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4438,0,NULL,'mvk','mekmek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4439,0,NULL,'mvl','mbara (australia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4440,0,NULL,'mvm','muya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4441,0,NULL,'mvn','minaveha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4442,0,NULL,'mvo','marovo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4443,0,NULL,'mvp','duri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4444,0,NULL,'mvq','moere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4445,0,NULL,'mvr','marau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4446,0,NULL,'mvs','massep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4447,0,NULL,'mvt','mpotovoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4448,0,NULL,'mvu','marfa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4449,0,NULL,'mvv','tagal murut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4450,0,NULL,'mvw','machinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4451,0,NULL,'mvx','meoswar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4452,0,NULL,'mvy','indus kohistani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4453,0,NULL,'mvz','mesqan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4454,0,NULL,'mwa','mwatebu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4455,0,NULL,'mwb','juwal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4456,0,NULL,'mwc','are','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4457,0,NULL,'mwd','mudbura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4458,0,NULL,'mwe','mwera (chimwera)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4459,0,NULL,'mwf','murrinh-patha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4460,0,NULL,'mwg','aiklep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4461,0,NULL,'mwh','mouk-aria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4462,0,NULL,'mwi','labo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4462,0,NULL,'mwi','ninde','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4463,0,NULL,'mwj','maligo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4464,0,NULL,'mwk','kita maninkakan','1248825600',NULL,NULL,NULL,NULL,'man',NULL,NULL); +INSERT INTO "iana_records" VALUES(4465,0,NULL,'mwl','mirandese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4466,0,NULL,'mwm','sar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4467,0,NULL,'mwn','nyamwanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4468,0,NULL,'mwo','central maewo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4469,0,NULL,'mwp','kala lagaw ya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4470,0,NULL,'mwq','mün chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4471,0,NULL,'mwr','marwari','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(4472,0,NULL,'mws','mwimbi-muthambi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4473,0,NULL,'mwt','moken','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4474,0,NULL,'mwu','mittu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4475,0,NULL,'mwv','mentawai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4476,0,NULL,'mww','hmong daw','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(4477,0,NULL,'mwx','mediak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4478,0,NULL,'mwy','mosiro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4479,0,NULL,'mwz','moingi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4480,0,NULL,'mxa','northwest oaxaca mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4481,0,NULL,'mxb','tezoatlán mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4482,0,NULL,'mxc','manyika','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4483,0,NULL,'mxd','modang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4484,0,NULL,'mxe','mele-fila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4485,0,NULL,'mxf','malgbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4486,0,NULL,'mxg','mbangala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4487,0,NULL,'mxh','mvuba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4488,0,NULL,'mxi','mozarabic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4489,0,NULL,'mxj','geman deng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4489,0,NULL,'mxj','miju-mishmi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4490,0,NULL,'mxk','monumbo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4491,0,NULL,'mxl','maxi gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4492,0,NULL,'mxm','meramera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4493,0,NULL,'mxn','moi (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4494,0,NULL,'mxo','mbowe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4495,0,NULL,'mxp','tlahuitoltepec mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4496,0,NULL,'mxq','juquila mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4497,0,NULL,'mxr','murik (malaysia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4498,0,NULL,'mxs','huitepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4499,0,NULL,'mxt','jamiltepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4500,0,NULL,'mxu','mada (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4501,0,NULL,'mxv','metlatónoc mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4502,0,NULL,'mxw','namo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4503,0,NULL,'mxx','mahou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4503,0,NULL,'mxx','mawukakan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4504,0,NULL,'mxy','southeastern nochixtlán mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4505,0,NULL,'mxz','central masela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4506,0,NULL,'myb','mbay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4507,0,NULL,'myc','mayeka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4508,0,NULL,'myd','maramba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4509,0,NULL,'mye','myene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4510,0,NULL,'myf','bambassi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4511,0,NULL,'myg','manta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4512,0,NULL,'myh','makah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4513,0,NULL,'myi','mina (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4514,0,NULL,'myj','mangayat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4515,0,NULL,'myk','mamara senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4516,0,NULL,'myl','moma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4517,0,NULL,'mym','me''en','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4518,0,NULL,'myn','mayan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4519,0,NULL,'myo','anfillo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4520,0,NULL,'myp','pirahã','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4521,0,NULL,'myq','forest maninka','1248825600',NULL,NULL,NULL,NULL,'man',NULL,NULL); +INSERT INTO "iana_records" VALUES(4522,0,NULL,'myr','muniche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4523,0,NULL,'mys','mesmes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4524,0,NULL,'myt','sangab mandaya','1248825600',1268265600,'mry',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4525,0,NULL,'myu','mundurukú','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4526,0,NULL,'myv','erzya','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4527,0,NULL,'myw','muyuw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4528,0,NULL,'myx','masaaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4529,0,NULL,'myy','macuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4530,0,NULL,'myz','classical mandaic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4531,0,NULL,'mza','santa maría zacatepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4532,0,NULL,'mzb','tumzabt','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4533,0,NULL,'mzc','madagascar sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4534,0,NULL,'mzd','malimba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4535,0,NULL,'mze','morawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4536,0,NULL,'mzg','monastic sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4537,0,NULL,'mzh','wichí lhamtés güisnay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4538,0,NULL,'mzi','ixcatlán mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4539,0,NULL,'mzj','manya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4540,0,NULL,'mzk','nigeria mambila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4541,0,NULL,'mzl','mazatlán mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4542,0,NULL,'mzm','mumuye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4543,0,NULL,'mzn','mazanderani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4544,0,NULL,'mzo','matipuhy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4545,0,NULL,'mzp','movima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4546,0,NULL,'mzq','mori atas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4547,0,NULL,'mzr','marúbo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4548,0,NULL,'mzs','macanese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4549,0,NULL,'mzt','mintil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4550,0,NULL,'mzu','inapang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4551,0,NULL,'mzv','manza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4552,0,NULL,'mzw','deg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4553,0,NULL,'mzx','mawayana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4554,0,NULL,'mzy','mozambican sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4555,0,NULL,'mzz','maiadomu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4556,0,NULL,'naa','namla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4557,0,NULL,'nab','southern nambikuára','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4558,0,NULL,'nac','narak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4559,0,NULL,'nad','nijadali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4560,0,NULL,'nae','naka''ela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4561,0,NULL,'naf','nabak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4562,0,NULL,'nag','naga pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4563,0,NULL,'nah','nahuatl languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4564,0,NULL,'nai','north american indian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4565,0,NULL,'naj','nalu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4566,0,NULL,'nak','nakanai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4567,0,NULL,'nal','nalik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4568,0,NULL,'nam','nangikurrunggurr','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4569,0,NULL,'nan','min nan chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(4570,0,NULL,'nao','naaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4571,0,NULL,'nap','neapolitan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4572,0,NULL,'naq','nama (namibia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4573,0,NULL,'nar','iguta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4574,0,NULL,'nas','naasioi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4575,0,NULL,'nat','hungworo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4576,0,NULL,'naw','nawuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4577,0,NULL,'nax','nakwi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4578,0,NULL,'nay','narrinyeri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4579,0,NULL,'naz','coatepec nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4580,0,NULL,'nba','nyemba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4581,0,NULL,'nbb','ndoe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4582,0,NULL,'nbc','chang naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4583,0,NULL,'nbd','ngbinda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4584,0,NULL,'nbe','konyak naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4585,0,NULL,'nbf','naxi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4586,0,NULL,'nbg','nagarchal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4587,0,NULL,'nbh','ngamo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4588,0,NULL,'nbi','mao naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4589,0,NULL,'nbj','ngarinman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4590,0,NULL,'nbk','nake','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4591,0,NULL,'nbm','ngbaka ma''bo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4592,0,NULL,'nbn','kuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4593,0,NULL,'nbo','nkukoli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4594,0,NULL,'nbp','nnam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4595,0,NULL,'nbq','nggem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4596,0,NULL,'nbr','numana-nunku-gbantu-numbu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4597,0,NULL,'nbs','namibian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4598,0,NULL,'nbt','na','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4599,0,NULL,'nbu','rongmei naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4600,0,NULL,'nbv','ngamambo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4601,0,NULL,'nbw','southern ngbandi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4602,0,NULL,'nbx','ngura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4603,0,NULL,'nby','ningera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4604,0,NULL,'nca','iyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4605,0,NULL,'ncb','central nicobarese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4606,0,NULL,'ncc','ponam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4607,0,NULL,'ncd','nachering','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4608,0,NULL,'nce','yale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4609,0,NULL,'ncf','notsi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4610,0,NULL,'ncg','nisga''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4611,0,NULL,'nch','central huasteca nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4612,0,NULL,'nci','classical nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4613,0,NULL,'ncj','northern puebla nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4614,0,NULL,'nck','nakara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4615,0,NULL,'ncl','michoacán nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4616,0,NULL,'ncm','nambo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4617,0,NULL,'ncn','nauna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4618,0,NULL,'nco','sibe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4619,0,NULL,'ncp','ndaktup','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4620,0,NULL,'ncr','ncane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4621,0,NULL,'ncs','nicaraguan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4622,0,NULL,'nct','chothe naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4623,0,NULL,'ncu','chumburung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4624,0,NULL,'ncx','central puebla nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4625,0,NULL,'ncz','natchez','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4626,0,NULL,'nda','ndasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4627,0,NULL,'ndb','kenswei nsei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4628,0,NULL,'ndc','ndau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4629,0,NULL,'ndd','nde-nsele-nta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4630,0,NULL,'ndf','nadruvian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4631,0,NULL,'ndg','ndengereko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4632,0,NULL,'ndh','ndali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4633,0,NULL,'ndi','samba leko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4634,0,NULL,'ndj','ndamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4635,0,NULL,'ndk','ndaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4636,0,NULL,'ndl','ndolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4637,0,NULL,'ndm','ndam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4638,0,NULL,'ndn','ngundi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4639,0,NULL,'ndp','ndo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4640,0,NULL,'ndq','ndombe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4641,0,NULL,'ndr','ndoola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4642,0,NULL,'nds','low german','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4642,0,NULL,'nds','low saxon','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4643,0,NULL,'ndt','ndunga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4644,0,NULL,'ndu','dugun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4645,0,NULL,'ndv','ndut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4646,0,NULL,'ndw','ndobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4647,0,NULL,'ndx','nduga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4648,0,NULL,'ndy','lutos','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4649,0,NULL,'ndz','ndogo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4650,0,NULL,'nea','eastern ngad''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4651,0,NULL,'neb','toura (côte d''ivoire)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4652,0,NULL,'nec','nedebang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4653,0,NULL,'ned','nde-gbite','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4654,0,NULL,'nee','kumak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4655,0,NULL,'nef','nefamese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4656,0,NULL,'neg','negidal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4657,0,NULL,'neh','nyenkha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4658,0,NULL,'nei','neo-hittite','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4659,0,NULL,'nej','neko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4660,0,NULL,'nek','neku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4661,0,NULL,'nem','nemi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4662,0,NULL,'nen','nengone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4663,0,NULL,'neo','ná-meo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4664,0,NULL,'neq','north central mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4665,0,NULL,'ner','yahadian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4666,0,NULL,'nes','bhoti kinnauri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4667,0,NULL,'net','nete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4668,0,NULL,'nev','nyaheun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4669,0,NULL,'new','nepal bhasa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4669,0,NULL,'new','newari','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4670,0,NULL,'nex','neme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4671,0,NULL,'ney','neyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4672,0,NULL,'nez','nez perce','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4673,0,NULL,'nfa','dhao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4674,0,NULL,'nfd','ahwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4675,0,NULL,'nfl','ayiwo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4675,0,NULL,'nfl','Äiwoo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4676,0,NULL,'nfr','nafaanra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4677,0,NULL,'nfu','mfumte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4678,0,NULL,'nga','ngbaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4679,0,NULL,'ngb','northern ngbandi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4680,0,NULL,'ngc','ngombe (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4681,0,NULL,'ngd','ngando (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4682,0,NULL,'nge','ngemba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4683,0,NULL,'ngf','trans-new guinea languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4684,0,NULL,'ngg','ngbaka manza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4685,0,NULL,'ngh','n/u','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4686,0,NULL,'ngi','ngizim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4687,0,NULL,'ngj','ngie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4688,0,NULL,'ngk','ngalkbun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4689,0,NULL,'ngl','lomwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4690,0,NULL,'ngm','ngatik men''s creole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4691,0,NULL,'ngn','ngwo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4692,0,NULL,'ngo','ngoni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4693,0,NULL,'ngp','ngulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4694,0,NULL,'ngq','ngoreme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4694,0,NULL,'ngq','ngurimi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4695,0,NULL,'ngr','nagu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4695,0,NULL,'ngr','nanggu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4696,0,NULL,'ngs','gvoko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4697,0,NULL,'ngt','ngeq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4698,0,NULL,'ngu','guerrero nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4699,0,NULL,'ngv','nagumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4700,0,NULL,'ngw','ngwaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4701,0,NULL,'ngx','nggwahyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4702,0,NULL,'ngy','tibea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4703,0,NULL,'ngz','ngungwel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4704,0,NULL,'nha','nhanda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4705,0,NULL,'nhb','beng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4706,0,NULL,'nhc','tabasco nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4707,0,NULL,'nhd','ava guaraní','1248825600',NULL,NULL,NULL,NULL,'gn',NULL,NULL); +INSERT INTO "iana_records" VALUES(4707,0,NULL,'nhd','chiripá','1248825600',NULL,NULL,NULL,NULL,'gn',NULL,NULL); +INSERT INTO "iana_records" VALUES(4708,0,NULL,'nhe','eastern huasteca nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4709,0,NULL,'nhf','nhuwala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4710,0,NULL,'nhg','tetelcingo nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4711,0,NULL,'nhh','nahari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4712,0,NULL,'nhi','zacatlán-ahuacatlán-tepetzintla nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4713,0,NULL,'nhk','isthmus-cosoleacaque nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4714,0,NULL,'nhm','morelos nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4715,0,NULL,'nhn','central nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4716,0,NULL,'nho','takuu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4717,0,NULL,'nhp','isthmus-pajapan nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4718,0,NULL,'nhq','huaxcaleca nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4719,0,NULL,'nhr','naro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4720,0,NULL,'nht','ometepec nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4721,0,NULL,'nhu','noone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4722,0,NULL,'nhv','temascaltepec nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4723,0,NULL,'nhw','western huasteca nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4724,0,NULL,'nhx','isthmus-mecayapan nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4725,0,NULL,'nhy','northern oaxaca nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4726,0,NULL,'nhz','santa maría la alta nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4727,0,NULL,'nia','nias','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4728,0,NULL,'nib','nakama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4729,0,NULL,'nic','niger-kordofanian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4730,0,NULL,'nid','ngandi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4731,0,NULL,'nie','niellim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4732,0,NULL,'nif','nek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4733,0,NULL,'nig','ngalakan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4734,0,NULL,'nih','nyiha (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4735,0,NULL,'nii','nii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4736,0,NULL,'nij','ngaju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4737,0,NULL,'nik','southern nicobarese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4738,0,NULL,'nil','nila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4739,0,NULL,'nim','nilamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4740,0,NULL,'nin','ninzo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4741,0,NULL,'nio','nganasan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4742,0,NULL,'niq','nandi','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(4743,0,NULL,'nir','nimboran','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4744,0,NULL,'nis','nimi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4745,0,NULL,'nit','southeastern kolami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4746,0,NULL,'niu','niuean','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4747,0,NULL,'niv','gilyak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4748,0,NULL,'niw','nimo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4749,0,NULL,'nix','hema','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4750,0,NULL,'niy','ngiti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4751,0,NULL,'niz','ningil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4752,0,NULL,'nja','nzanyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4753,0,NULL,'njb','nocte naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4754,0,NULL,'njd','ndonde hamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4755,0,NULL,'njh','lotha naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4756,0,NULL,'nji','gudanji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4757,0,NULL,'njj','njen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4758,0,NULL,'njl','njalgulgule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4759,0,NULL,'njm','angami naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4760,0,NULL,'njn','liangmai naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4761,0,NULL,'njo','ao naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4762,0,NULL,'njr','njerep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4763,0,NULL,'njs','nisa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4764,0,NULL,'njt','ndyuka-trio pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4765,0,NULL,'nju','ngadjunmaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4766,0,NULL,'njx','kunyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4767,0,NULL,'njy','njyem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4768,0,NULL,'nka','nkoya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4769,0,NULL,'nkb','khoibu naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4770,0,NULL,'nkc','nkongho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4771,0,NULL,'nkd','koireng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4772,0,NULL,'nke','duke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4773,0,NULL,'nkf','inpui naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4774,0,NULL,'nkg','nekgini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4775,0,NULL,'nkh','khezha naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4776,0,NULL,'nki','thangal naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4777,0,NULL,'nkj','nakai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4778,0,NULL,'nkk','nokuku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4779,0,NULL,'nkm','namat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4780,0,NULL,'nkn','nkangala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4781,0,NULL,'nko','nkonya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4782,0,NULL,'nkp','niuatoputapu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4783,0,NULL,'nkq','nkami','1271376000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4784,0,NULL,'nkr','nukuoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4785,0,NULL,'nks','north asmat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4786,0,NULL,'nkt','nyika (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4787,0,NULL,'nku','bouna kulango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4788,0,NULL,'nkv','nyika (malawi and zambia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4789,0,NULL,'nkw','nkutu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4790,0,NULL,'nkx','nkoroo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4791,0,NULL,'nkz','nkari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4792,0,NULL,'nla','ngombale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4793,0,NULL,'nlc','nalca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4794,0,NULL,'nle','east nyala','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(4795,0,NULL,'nlg','gela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4796,0,NULL,'nli','grangali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4797,0,NULL,'nlj','nyali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4798,0,NULL,'nlk','ninia yali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4799,0,NULL,'nll','nihali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4800,0,NULL,'nln','durango nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4801,0,NULL,'nlo','ngul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4802,0,NULL,'nlr','ngarla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4803,0,NULL,'nlu','nchumbulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4804,0,NULL,'nlv','orizaba nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4805,0,NULL,'nlx','nahali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4806,0,NULL,'nly','nyamal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4807,0,NULL,'nlz','nalögo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4808,0,NULL,'nma','maram naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4809,0,NULL,'nmb','big nambas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4809,0,NULL,'nmb','v''ënen taut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4810,0,NULL,'nmc','ngam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4811,0,NULL,'nmd','ndumu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4812,0,NULL,'nme','mzieme naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4813,0,NULL,'nmf','tangkhul naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4814,0,NULL,'nmg','kwasio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4815,0,NULL,'nmh','monsang naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4816,0,NULL,'nmi','nyam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4817,0,NULL,'nmj','ngombe (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4818,0,NULL,'nmk','namakura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4819,0,NULL,'nml','ndemli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4820,0,NULL,'nmm','manangba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4821,0,NULL,'nmn','!xóõ','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4822,0,NULL,'nmo','moyon naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4823,0,NULL,'nmp','nimanbur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4824,0,NULL,'nmq','nambya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4825,0,NULL,'nmr','nimbari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4826,0,NULL,'nms','letemboi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4827,0,NULL,'nmt','namonuito','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4828,0,NULL,'nmu','northeast maidu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4829,0,NULL,'nmv','ngamini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4830,0,NULL,'nmw','nimoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4831,0,NULL,'nmx','nama (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4832,0,NULL,'nmy','namuyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4833,0,NULL,'nmz','nawdm','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4834,0,NULL,'nna','nyangumarta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4835,0,NULL,'nnb','nande','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4836,0,NULL,'nnc','nancere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4837,0,NULL,'nnd','west ambae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4838,0,NULL,'nne','ngandyera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4839,0,NULL,'nnf','ngaing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4840,0,NULL,'nng','maring naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4841,0,NULL,'nnh','ngiemboon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4842,0,NULL,'nni','north nuaulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4843,0,NULL,'nnj','nyangatom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4844,0,NULL,'nnk','nankina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4845,0,NULL,'nnl','northern rengma naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4846,0,NULL,'nnm','namia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4847,0,NULL,'nnn','ngete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4848,0,NULL,'nnp','wancho naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4849,0,NULL,'nnq','ngindo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4850,0,NULL,'nnr','narungga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4851,0,NULL,'nns','ningye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4852,0,NULL,'nnt','nanticoke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4853,0,NULL,'nnu','dwang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4854,0,NULL,'nnv','nugunu (australia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4855,0,NULL,'nnw','southern nuni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4856,0,NULL,'nnx','ngong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4857,0,NULL,'nny','nyangga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4858,0,NULL,'nnz','nda''nda''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4859,0,NULL,'noa','woun meu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4860,0,NULL,'noc','nuk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4861,0,NULL,'nod','northern thai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4862,0,NULL,'noe','nimadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4863,0,NULL,'nof','nomane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4864,0,NULL,'nog','nogai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4865,0,NULL,'noh','nomu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4866,0,NULL,'noi','noiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4867,0,NULL,'noj','nonuya','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4868,0,NULL,'nok','nooksack','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4869,0,NULL,'nom','nocamán','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4870,0,NULL,'non','old norse','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4871,0,NULL,'noo','nootka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4872,0,NULL,'nop','numanggang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4873,0,NULL,'noq','ngongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4874,0,NULL,'nos','eastern nisu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4875,0,NULL,'not','nomatsiguenga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4876,0,NULL,'nou','ewage-notu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4877,0,NULL,'nov','novial','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4878,0,NULL,'now','nyambo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4879,0,NULL,'noy','noy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4880,0,NULL,'noz','nayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4881,0,NULL,'npa','nar phu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4882,0,NULL,'npb','nupbikha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4883,0,NULL,'nph','phom naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4884,0,NULL,'npl','southeastern puebla nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4885,0,NULL,'npn','mondropolon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4886,0,NULL,'npo','pochuri naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4887,0,NULL,'nps','nipsan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4888,0,NULL,'npu','puimei naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4889,0,NULL,'npy','napu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4890,0,NULL,'nqg','southern nago','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4891,0,NULL,'nqk','kura ede nago','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4892,0,NULL,'nqm','ndom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4893,0,NULL,'nqn','nen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4894,0,NULL,'nqo','n''ko','1149465600',NULL,NULL,NULL,'nkoo',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4894,0,NULL,'nqo','n’ko','1149465600',NULL,NULL,NULL,'nkoo',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4895,0,NULL,'nra','ngom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4896,0,NULL,'nrb','nara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4897,0,NULL,'nrc','noric','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4898,0,NULL,'nre','southern rengma naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4899,0,NULL,'nrg','narango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4900,0,NULL,'nri','chokri naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4901,0,NULL,'nrl','ngarluma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4902,0,NULL,'nrm','narom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4903,0,NULL,'nrn','norn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4904,0,NULL,'nrp','north picene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4905,0,NULL,'nrr','norra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4906,0,NULL,'nrt','northern kalapuya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4907,0,NULL,'nrx','ngurmbur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4908,0,NULL,'nrz','lala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4909,0,NULL,'nsa','sangtam naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4910,0,NULL,'nsc','nshi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4911,0,NULL,'nsd','southern nisu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4912,0,NULL,'nse','nsenga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4913,0,NULL,'nsg','ngasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4914,0,NULL,'nsh','ngoshie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4915,0,NULL,'nsi','nigerian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4916,0,NULL,'nsk','naskapi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4917,0,NULL,'nsl','norwegian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4918,0,NULL,'nsm','sumi naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4919,0,NULL,'nsn','nehan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4920,0,NULL,'nso','northern sotho','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4920,0,NULL,'nso','pedi','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4920,0,NULL,'nso','sepedi','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4921,0,NULL,'nsp','nepalese sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4922,0,NULL,'nsq','northern sierra miwok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4923,0,NULL,'nsr','maritime sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4924,0,NULL,'nss','nali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4925,0,NULL,'nst','tase naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4926,0,NULL,'nsu','sierra negra nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4927,0,NULL,'nsv','southwestern nisu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4928,0,NULL,'nsw','navut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4929,0,NULL,'nsx','nsongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4930,0,NULL,'nsy','nasal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4931,0,NULL,'nsz','nisenan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4932,0,NULL,'nte','nathembo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4933,0,NULL,'nti','natioro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4934,0,NULL,'ntj','ngaanyatjarra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4935,0,NULL,'ntk','ikoma-nata-isenye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4936,0,NULL,'ntm','nateni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4937,0,NULL,'nto','ntomba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4938,0,NULL,'ntp','northern tepehuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4939,0,NULL,'ntr','delo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4940,0,NULL,'nts','natagaimas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4941,0,NULL,'ntu','natügu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4942,0,NULL,'ntw','nottoway','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4943,0,NULL,'nty','mantsi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4944,0,NULL,'ntz','natanzi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4945,0,NULL,'nua','yuaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4946,0,NULL,'nub','nubian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(4947,0,NULL,'nuc','nukuini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4948,0,NULL,'nud','ngala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4949,0,NULL,'nue','ngundu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4950,0,NULL,'nuf','nusu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4951,0,NULL,'nug','nungali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4952,0,NULL,'nuh','ndunda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4953,0,NULL,'nui','ngumbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4954,0,NULL,'nuj','nyole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4955,0,NULL,'nul','nusa laut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4956,0,NULL,'num','niuafo''ou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4957,0,NULL,'nun','nung (myanmar)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4958,0,NULL,'nuo','nguôn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4959,0,NULL,'nup','nupe-nupe-tako','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4960,0,NULL,'nuq','nukumanu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4961,0,NULL,'nur','nukuria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4962,0,NULL,'nus','nuer','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4963,0,NULL,'nut','nung (viet nam)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4964,0,NULL,'nuu','ngbundu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4965,0,NULL,'nuv','northern nuni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4966,0,NULL,'nuw','nguluwan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4967,0,NULL,'nux','mehek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4968,0,NULL,'nuy','nunggubuyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4969,0,NULL,'nuz','tlamacazapa nahuatl','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4970,0,NULL,'nvh','nasarian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4971,0,NULL,'nvm','namiae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4972,0,NULL,'nwa','nawathinehena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4973,0,NULL,'nwb','nyabwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4974,0,NULL,'nwc','classical nepal bhasa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4974,0,NULL,'nwc','classical newari','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4974,0,NULL,'nwc','old newari','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4975,0,NULL,'nwe','ngwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4976,0,NULL,'nwi','southwest tanna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4977,0,NULL,'nwm','nyamusa-molo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4978,0,NULL,'nwr','nawaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4979,0,NULL,'nwx','middle newar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4980,0,NULL,'nwy','nottoway-meherrin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4981,0,NULL,'nxa','nauete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4982,0,NULL,'nxd','ngando (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4983,0,NULL,'nxe','nage','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4984,0,NULL,'nxg','ngad''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4985,0,NULL,'nxi','nindi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4986,0,NULL,'nxl','south nuaulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4987,0,NULL,'nxm','numidian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4988,0,NULL,'nxn','ngawun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4989,0,NULL,'nxr','ninggerum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4990,0,NULL,'nxu','narau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4991,0,NULL,'nxx','nafri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4992,0,NULL,'nyb','nyangbo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4993,0,NULL,'nyc','nyanga-li','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4994,0,NULL,'nyd','nyore','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(4994,0,NULL,'nyd','olunyole','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(4995,0,NULL,'nye','nyengo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4996,0,NULL,'nyf','giryama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4996,0,NULL,'nyf','kigiryama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4997,0,NULL,'nyg','nyindu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4998,0,NULL,'nyh','nyigina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(4999,0,NULL,'nyi','ama (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5000,0,NULL,'nyj','nyanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5001,0,NULL,'nyk','nyaneka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5002,0,NULL,'nyl','nyeu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5003,0,NULL,'nym','nyamwezi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5004,0,NULL,'nyn','nyankole','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5005,0,NULL,'nyo','nyoro','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5006,0,NULL,'nyp','nyang''i','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5007,0,NULL,'nyq','nayini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5008,0,NULL,'nyr','nyiha (malawi)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5009,0,NULL,'nys','nyunga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5010,0,NULL,'nyt','nyawaygi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5011,0,NULL,'nyu','nyungwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5012,0,NULL,'nyv','nyulnyul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5013,0,NULL,'nyw','nyaw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5014,0,NULL,'nyx','nganyaywana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5015,0,NULL,'nyy','nyakyusa-ngonde','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5016,0,NULL,'nza','tigon mbembe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5017,0,NULL,'nzb','njebi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5018,0,NULL,'nzi','nzima','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5019,0,NULL,'nzk','nzakara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5020,0,NULL,'nzm','zeme naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5021,0,NULL,'nzs','new zealand sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5022,0,NULL,'nzu','teke-nzikou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5023,0,NULL,'nzy','nzakambay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5024,0,NULL,'nzz','nanga dama dogon','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5025,0,NULL,'oaa','orok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5026,0,NULL,'oac','oroch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5027,0,NULL,'oar','ancient aramaic (up to 700 bce)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5027,0,NULL,'oar','old aramaic (up to 700 bce)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5028,0,NULL,'oav','old avar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5029,0,NULL,'obi','obispeño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5030,0,NULL,'obk','southern bontok','1268265600',NULL,NULL,NULL,NULL,'bnc',NULL,NULL); +INSERT INTO "iana_records" VALUES(5031,0,NULL,'obl','oblo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5032,0,NULL,'obm','moabite','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5033,0,NULL,'obo','obo manobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5034,0,NULL,'obr','old burmese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5035,0,NULL,'obt','old breton','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5036,0,NULL,'obu','obulom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5037,0,NULL,'oca','ocaina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5038,0,NULL,'och','old chinese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5039,0,NULL,'oco','old cornish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5040,0,NULL,'ocu','atzingo matlatzinca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5041,0,NULL,'oda','odut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5042,0,NULL,'odk','od','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5043,0,NULL,'odt','old dutch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5044,0,NULL,'odu','odual','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5045,0,NULL,'ofo','ofo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5046,0,NULL,'ofs','old frisian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5047,0,NULL,'ofu','efutop','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5048,0,NULL,'ogb','ogbia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5049,0,NULL,'ogc','ogbah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5050,0,NULL,'oge','old georgian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5051,0,NULL,'ogg','ogbogolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5052,0,NULL,'ogo','khana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5053,0,NULL,'ogu','ogbronuagum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5054,0,NULL,'oht','old hittite','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5055,0,NULL,'ohu','old hungarian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5056,0,NULL,'oia','oirata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5057,0,NULL,'oin','inebu one','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5058,0,NULL,'ojb','northwestern ojibwa','1248825600',NULL,NULL,NULL,NULL,'oj',NULL,NULL); +INSERT INTO "iana_records" VALUES(5059,0,NULL,'ojc','central ojibwa','1248825600',NULL,NULL,NULL,NULL,'oj',NULL,NULL); +INSERT INTO "iana_records" VALUES(5060,0,NULL,'ojg','eastern ojibwa','1248825600',NULL,NULL,NULL,NULL,'oj',NULL,NULL); +INSERT INTO "iana_records" VALUES(5061,0,NULL,'ojp','old japanese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5062,0,NULL,'ojs','severn ojibwa','1248825600',NULL,NULL,NULL,NULL,'oj',NULL,NULL); +INSERT INTO "iana_records" VALUES(5063,0,NULL,'ojv','ontong java','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5064,0,NULL,'ojw','western ojibwa','1248825600',NULL,NULL,NULL,NULL,'oj',NULL,NULL); +INSERT INTO "iana_records" VALUES(5065,0,NULL,'oka','okanagan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5066,0,NULL,'okb','okobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5067,0,NULL,'okd','okodia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5068,0,NULL,'oke','okpe (southwestern edo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5069,0,NULL,'okh','koresh-e rostam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5070,0,NULL,'oki','okiek','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(5071,0,NULL,'okj','oko-juwoi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5072,0,NULL,'okk','kwamtim one','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5073,0,NULL,'okl','old kentish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5074,0,NULL,'okm','middle korean (10th-16th cent.)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5075,0,NULL,'okn','oki-no-erabu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5076,0,NULL,'oko','old korean (3rd-9th cent.)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5077,0,NULL,'okr','kirike','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5078,0,NULL,'oks','oko-eni-osayen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5079,0,NULL,'oku','oku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5080,0,NULL,'okv','orokaiva','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5081,0,NULL,'okx','okpe (northwestern edo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5082,0,NULL,'ola','walungge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5083,0,NULL,'old','mochi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5084,0,NULL,'ole','olekha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5085,0,NULL,'olm','oloma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5086,0,NULL,'olo','livvi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5087,0,NULL,'olr','olrat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5088,0,NULL,'oma','omaha-ponca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5089,0,NULL,'omb','east ambae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5090,0,NULL,'omc','mochica','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5091,0,NULL,'ome','omejes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5092,0,NULL,'omg','omagua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5093,0,NULL,'omi','omi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5094,0,NULL,'omk','omok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5095,0,NULL,'oml','ombo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5096,0,NULL,'omn','minoan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5097,0,NULL,'omo','utarmbung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5098,0,NULL,'omp','old manipuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5099,0,NULL,'omq','oto-manguean languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5100,0,NULL,'omr','old marathi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5101,0,NULL,'omt','omotik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5102,0,NULL,'omu','omurano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5103,0,NULL,'omv','omotic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5104,0,NULL,'omw','south tairora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5105,0,NULL,'omx','old mon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5106,0,NULL,'ona','ona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5107,0,NULL,'onb','lingao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5108,0,NULL,'one','oneida','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5109,0,NULL,'ong','olo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5110,0,NULL,'oni','onin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5111,0,NULL,'onj','onjob','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5112,0,NULL,'onk','kabore one','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5113,0,NULL,'onn','onobasulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5114,0,NULL,'ono','onondaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5115,0,NULL,'onp','sartang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5116,0,NULL,'onr','northern one','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5117,0,NULL,'ons','ono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5118,0,NULL,'ont','ontenu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5119,0,NULL,'onu','unua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5120,0,NULL,'onw','old nubian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5121,0,NULL,'onx','onin based pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5122,0,NULL,'ood','tohono o''odham','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5123,0,NULL,'oog','ong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5124,0,NULL,'oon','Önge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5125,0,NULL,'oor','oorlams','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5126,0,NULL,'oos','old ossetic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5127,0,NULL,'opa','okpamheri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5128,0,NULL,'opk','kopkaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5129,0,NULL,'opm','oksapmin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5130,0,NULL,'opo','opao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5131,0,NULL,'opt','opata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5132,0,NULL,'opy','ofayé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5133,0,NULL,'ora','oroha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5134,0,NULL,'orc','orma','1248825600',NULL,NULL,NULL,NULL,'om',NULL,NULL); +INSERT INTO "iana_records" VALUES(5135,0,NULL,'ore','orejón','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5136,0,NULL,'org','oring','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5137,0,NULL,'orh','oroqen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5138,0,NULL,'orn','orang kanaq','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(5139,0,NULL,'oro','orokolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5140,0,NULL,'orr','oruma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5141,0,NULL,'ors','orang seletar','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(5142,0,NULL,'ort','adivasi oriya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5143,0,NULL,'oru','ormuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5144,0,NULL,'orv','old russian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5145,0,NULL,'orw','oro win','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5146,0,NULL,'orx','oro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5147,0,NULL,'orz','ormu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5148,0,NULL,'osa','osage','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5149,0,NULL,'osc','oscan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5150,0,NULL,'osi','osing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5151,0,NULL,'oso','ososo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5152,0,NULL,'osp','old spanish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5153,0,NULL,'ost','osatu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5154,0,NULL,'osu','southern one','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5155,0,NULL,'osx','old saxon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5156,0,NULL,'ota','ottoman turkish (1500-1928)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5157,0,NULL,'otb','old tibetan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5158,0,NULL,'otd','ot danum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5159,0,NULL,'ote','mezquital otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5160,0,NULL,'oti','oti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5161,0,NULL,'otk','old turkish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5162,0,NULL,'otl','tilapa otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5163,0,NULL,'otm','eastern highland otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5164,0,NULL,'otn','tenango otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5165,0,NULL,'oto','otomian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5166,0,NULL,'otq','querétaro otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5167,0,NULL,'otr','otoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5168,0,NULL,'ots','estado de méxico otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5169,0,NULL,'ott','temoaya otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5170,0,NULL,'otu','otuke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5171,0,NULL,'otw','ottawa','1248825600',NULL,NULL,NULL,NULL,'oj',NULL,NULL); +INSERT INTO "iana_records" VALUES(5172,0,NULL,'otx','texcatepec otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5173,0,NULL,'oty','old tamil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5174,0,NULL,'otz','ixtenco otomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5175,0,NULL,'oua','tagargrent','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5176,0,NULL,'oub','glio-oubi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5177,0,NULL,'oue','ounge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5178,0,NULL,'oui','old uighur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5179,0,NULL,'oum','ouma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5180,0,NULL,'oun','!o!ung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5181,0,NULL,'owi','owiniga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5182,0,NULL,'owl','old welsh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5183,0,NULL,'oyb','oy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5184,0,NULL,'oyd','oyda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5185,0,NULL,'oym','wayampi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5186,0,NULL,'oyy','oya''oya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5187,0,NULL,'ozm','koonzime','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5188,0,NULL,'paa','papuan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5189,0,NULL,'pab','parecís','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5190,0,NULL,'pac','pacoh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5191,0,NULL,'pad','paumarí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5192,0,NULL,'pae','pagibete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5193,0,NULL,'paf','paranawát','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5194,0,NULL,'pag','pangasinan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5195,0,NULL,'pah','tenharim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5196,0,NULL,'pai','pe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5197,0,NULL,'pak','parakanã','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5198,0,NULL,'pal','pahlavi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5199,0,NULL,'pam','kapampangan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5199,0,NULL,'pam','pampanga','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5200,0,NULL,'pao','northern paiute','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5201,0,NULL,'pap','papiamento','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5202,0,NULL,'paq','parya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5203,0,NULL,'par','panamint','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5203,0,NULL,'par','timbisha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5204,0,NULL,'pas','papasena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5205,0,NULL,'pat','papitalai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5206,0,NULL,'pau','palauan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5207,0,NULL,'pav','pakaásnovos','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5208,0,NULL,'paw','pawnee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5209,0,NULL,'pax','pankararé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5210,0,NULL,'pay','pech','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5211,0,NULL,'paz','pankararú','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5212,0,NULL,'pbb','páez','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5213,0,NULL,'pbc','patamona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5214,0,NULL,'pbe','mezontla popoloca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5215,0,NULL,'pbf','coyotepec popoloca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5216,0,NULL,'pbg','paraujano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5217,0,NULL,'pbh','e''ñapa woromaipu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5218,0,NULL,'pbi','parkwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5219,0,NULL,'pbl','mak (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5220,0,NULL,'pbn','kpasam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5221,0,NULL,'pbo','papel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5222,0,NULL,'pbp','badyara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5223,0,NULL,'pbr','pangwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5224,0,NULL,'pbs','central pame','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5225,0,NULL,'pbt','southern pashto','1248825600',NULL,NULL,NULL,NULL,'ps',NULL,NULL); +INSERT INTO "iana_records" VALUES(5226,0,NULL,'pbu','northern pashto','1248825600',NULL,NULL,NULL,NULL,'ps',NULL,NULL); +INSERT INTO "iana_records" VALUES(5227,0,NULL,'pbv','pnar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5228,0,NULL,'pby','pyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5229,0,NULL,'pbz','palu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5230,0,NULL,'pca','santa inés ahuatempan popoloca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5231,0,NULL,'pcb','pear','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5232,0,NULL,'pcc','bouyei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5233,0,NULL,'pcd','picard','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5234,0,NULL,'pce','ruching palaung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5235,0,NULL,'pcf','paliyan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5236,0,NULL,'pcg','paniya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5237,0,NULL,'pch','pardhan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5238,0,NULL,'pci','duruwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5239,0,NULL,'pcj','parenga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5240,0,NULL,'pck','paite chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5241,0,NULL,'pcl','pardhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5242,0,NULL,'pcm','nigerian pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5243,0,NULL,'pcn','piti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5244,0,NULL,'pcp','pacahuara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5245,0,NULL,'pcr','panang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5246,0,NULL,'pcw','pyapun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5247,0,NULL,'pda','anam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5248,0,NULL,'pdc','pennsylvania german','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5249,0,NULL,'pdi','pa di','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5250,0,NULL,'pdn','fedan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5250,0,NULL,'pdn','podena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5251,0,NULL,'pdo','padoe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5252,0,NULL,'pdt','plautdietsch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5253,0,NULL,'pdu','kayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5254,0,NULL,'pea','peranakan indonesian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5255,0,NULL,'peb','eastern pomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5256,0,NULL,'ped','mala (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5257,0,NULL,'pee','taje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5258,0,NULL,'pef','northeastern pomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5259,0,NULL,'peg','pengo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5260,0,NULL,'peh','bonan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5261,0,NULL,'pei','chichimeca-jonaz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5262,0,NULL,'pej','northern pomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5263,0,NULL,'pek','penchal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5264,0,NULL,'pel','pekal','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(5265,0,NULL,'pem','phende','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5266,0,NULL,'peo','old persian (ca. 600-400 b.c.)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5267,0,NULL,'pep','kunja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5268,0,NULL,'peq','southern pomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5269,0,NULL,'pes','iranian persian','1248825600',NULL,NULL,NULL,NULL,'fa',NULL,NULL); +INSERT INTO "iana_records" VALUES(5270,0,NULL,'pev','pémono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5271,0,NULL,'pex','petats','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5272,0,NULL,'pey','petjo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5273,0,NULL,'pez','eastern penan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5274,0,NULL,'pfa','pááfang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5275,0,NULL,'pfe','peere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5276,0,NULL,'pfl','pfaelzisch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5277,0,NULL,'pga','sudanese creole arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(5278,0,NULL,'pgg','pangwali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5279,0,NULL,'pgi','pagi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5280,0,NULL,'pgk','rerep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5281,0,NULL,'pgn','paelignian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5282,0,NULL,'pgs','pangseng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5283,0,NULL,'pgu','pagu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5284,0,NULL,'pgy','pongyong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5285,0,NULL,'pha','pa-hng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5286,0,NULL,'phd','phudagi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5287,0,NULL,'phg','phuong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5288,0,NULL,'phh','phukha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5289,0,NULL,'phi','philippine languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5290,0,NULL,'phk','phake','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5291,0,NULL,'phl','palula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5291,0,NULL,'phl','phalura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5292,0,NULL,'phm','phimbi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5293,0,NULL,'phn','phoenician','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5294,0,NULL,'pho','phunoi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5295,0,NULL,'phq','phana''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5296,0,NULL,'phr','pahari-potwari','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(5297,0,NULL,'pht','phu thai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5298,0,NULL,'phu','phuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5299,0,NULL,'phv','pahlavani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5300,0,NULL,'phw','phangduwali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5301,0,NULL,'pia','pima bajo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5302,0,NULL,'pib','yine','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5303,0,NULL,'pic','pinji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5304,0,NULL,'pid','piaroa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5305,0,NULL,'pie','piro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5306,0,NULL,'pif','pingelapese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5307,0,NULL,'pig','pisabo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5308,0,NULL,'pih','pitcairn-norfolk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5309,0,NULL,'pii','pini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5310,0,NULL,'pij','pijao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5311,0,NULL,'pil','yom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5312,0,NULL,'pim','powhatan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5313,0,NULL,'pin','piame','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5314,0,NULL,'pio','piapoco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5315,0,NULL,'pip','pero','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5316,0,NULL,'pir','piratapuyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5317,0,NULL,'pis','pijin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5318,0,NULL,'pit','pitta pitta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5319,0,NULL,'piu','pintupi-luritja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5320,0,NULL,'piv','pileni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5320,0,NULL,'piv','vaeakau-taumako','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5321,0,NULL,'piw','pimbwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5322,0,NULL,'pix','piu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5323,0,NULL,'piy','piya-kwonci','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5324,0,NULL,'piz','pije','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5325,0,NULL,'pjt','pitjantjatjara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5326,0,NULL,'pka','ardhamāgadhī prākrit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5327,0,NULL,'pkb','kipfokomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5327,0,NULL,'pkb','pokomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5328,0,NULL,'pkc','paekche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5329,0,NULL,'pkg','pak-tong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5330,0,NULL,'pkh','pankhu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5331,0,NULL,'pkn','pakanha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5332,0,NULL,'pko','pökoot','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(5333,0,NULL,'pkp','pukapuka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5334,0,NULL,'pkr','attapady kurumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5335,0,NULL,'pks','pakistan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5336,0,NULL,'pkt','maleng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5337,0,NULL,'pku','paku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5338,0,NULL,'pla','miani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5339,0,NULL,'plb','polonombauk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5340,0,NULL,'plc','central palawano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5341,0,NULL,'pld','polari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5342,0,NULL,'ple','palu''e','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5343,0,NULL,'plf','central malayo-polynesian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5344,0,NULL,'plg','pilagá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5345,0,NULL,'plh','paulohi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5346,0,NULL,'plj','polci','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5347,0,NULL,'plk','kohistani shina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5348,0,NULL,'pll','shwe palaung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5349,0,NULL,'pln','palenquero','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5350,0,NULL,'plo','oluta popoluca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5351,0,NULL,'plp','palpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5352,0,NULL,'plq','palaic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5353,0,NULL,'plr','palaka senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5354,0,NULL,'pls','san marcos tlalcoyalco popoloca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5355,0,NULL,'plt','plateau malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(5356,0,NULL,'plu','palikúr','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5357,0,NULL,'plv','southwest palawano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5358,0,NULL,'plw','brooke''s point palawano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5359,0,NULL,'ply','bolyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5360,0,NULL,'plz','paluan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5361,0,NULL,'pma','paama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5362,0,NULL,'pmb','pambia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5363,0,NULL,'pmc','palumata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5364,0,NULL,'pme','pwaamei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5365,0,NULL,'pmf','pamona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5366,0,NULL,'pmh','māhārāṣṭri prākrit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5367,0,NULL,'pmi','northern pumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5368,0,NULL,'pmj','southern pumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5369,0,NULL,'pmk','pamlico','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5370,0,NULL,'pml','lingua franca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5371,0,NULL,'pmm','pomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5372,0,NULL,'pmn','pam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5373,0,NULL,'pmo','pom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5374,0,NULL,'pmq','northern pame','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5375,0,NULL,'pmr','paynamar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5376,0,NULL,'pms','piemontese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5377,0,NULL,'pmt','tuamotuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5378,0,NULL,'pmu','mirpur panjabi','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(5379,0,NULL,'pmw','plains miwok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5380,0,NULL,'pmx','poumei naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5381,0,NULL,'pmy','papuan malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5382,0,NULL,'pmz','southern pame','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5383,0,NULL,'pna','punan bah-biau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5384,0,NULL,'pnb','western panjabi','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(5385,0,NULL,'pnc','pannei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5386,0,NULL,'pne','western penan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5387,0,NULL,'png','pongu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5388,0,NULL,'pnh','penrhyn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5389,0,NULL,'pni','aoheng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5390,0,NULL,'pnm','punan batu 1','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5391,0,NULL,'pnn','pinai-hagahai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5392,0,NULL,'pno','panobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5393,0,NULL,'pnp','pancana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5394,0,NULL,'pnq','pana (burkina faso)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5395,0,NULL,'pnr','panim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5396,0,NULL,'pns','ponosakan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5397,0,NULL,'pnt','pontic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5398,0,NULL,'pnu','jiongnai bunu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5399,0,NULL,'pnv','pinigura','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5400,0,NULL,'pnw','panytyima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5401,0,NULL,'pnx','phong-kniang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5402,0,NULL,'pny','pinyin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,'a niger-congo language spoken in cameroon; not to be confused with the pinyin romanization systems used for chinese and tibetan'); +INSERT INTO "iana_records" VALUES(5403,0,NULL,'pnz','pana (central african republic)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5404,0,NULL,'poc','poqomam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5405,0,NULL,'pod','ponares','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5406,0,NULL,'poe','san juan atzingo popoloca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5407,0,NULL,'pof','poke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5408,0,NULL,'pog','potiguára','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5409,0,NULL,'poh','poqomchi''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5410,0,NULL,'poi','highland popoluca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5411,0,NULL,'pok','pokangá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5412,0,NULL,'pom','southeastern pomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5413,0,NULL,'pon','pohnpeian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5414,0,NULL,'poo','central pomo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5415,0,NULL,'pop','pwapwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5416,0,NULL,'poq','texistepec popoluca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5417,0,NULL,'pos','sayula popoluca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5418,0,NULL,'pot','potawatomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5419,0,NULL,'pov','upper guinea crioulo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5420,0,NULL,'pow','san felipe otlaltepec popoloca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5421,0,NULL,'pox','polabian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5422,0,NULL,'poy','pogolo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5423,0,NULL,'poz','malayo-polynesian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5424,0,NULL,'ppa','pao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5425,0,NULL,'ppe','papi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5426,0,NULL,'ppi','paipai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5427,0,NULL,'ppk','uma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5428,0,NULL,'ppl','nicarao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5428,0,NULL,'ppl','pipil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5429,0,NULL,'ppm','papuma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5430,0,NULL,'ppn','papapana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5431,0,NULL,'ppo','folopa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5432,0,NULL,'ppp','pelende','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5433,0,NULL,'ppq','pei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5434,0,NULL,'ppr','piru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5435,0,NULL,'pps','san luís temalacayuca popoloca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5436,0,NULL,'ppt','pare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5437,0,NULL,'ppu','papora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5438,0,NULL,'pqa','pa''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5439,0,NULL,'pqe','eastern malayo-polynesian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5440,0,NULL,'pqm','malecite-passamaquoddy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5441,0,NULL,'pqw','western malayo-polynesian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5442,0,NULL,'pra','prakrit languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5443,0,NULL,'prb','lua''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5444,0,NULL,'prc','parachi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5445,0,NULL,'prd','parsi-dari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5446,0,NULL,'pre','principense','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5447,0,NULL,'prf','paranan','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5448,0,NULL,'prg','prussian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5449,0,NULL,'prh','porohanon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5450,0,NULL,'pri','paicî','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5451,0,NULL,'prk','parauk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5452,0,NULL,'prl','peruvian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5453,0,NULL,'prm','kibiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5454,0,NULL,'prn','prasuni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5455,0,NULL,'pro','old occitan (to 1500)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5455,0,NULL,'pro','old provençal (to 1500)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5456,0,NULL,'prp','parsi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5457,0,NULL,'prq','ashéninka perené','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5458,0,NULL,'prr','puri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5459,0,NULL,'prs','afghan persian','1248825600',NULL,NULL,NULL,NULL,'fa',NULL,NULL); +INSERT INTO "iana_records" VALUES(5459,0,NULL,'prs','dari','1248825600',NULL,NULL,NULL,NULL,'fa',NULL,NULL); +INSERT INTO "iana_records" VALUES(5460,0,NULL,'prt','phai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5461,0,NULL,'pru','puragi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5462,0,NULL,'prw','parawen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5463,0,NULL,'prx','purik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5464,0,NULL,'pry','pray 3','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5465,0,NULL,'prz','providencia sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5466,0,NULL,'psa','asue awyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5467,0,NULL,'psc','persian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5468,0,NULL,'psd','plains indian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5469,0,NULL,'pse','central malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(5470,0,NULL,'psg','penang sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5471,0,NULL,'psh','southwest pashayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5472,0,NULL,'psi','southeast pashayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5473,0,NULL,'psl','puerto rican sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5474,0,NULL,'psm','pauserna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5475,0,NULL,'psn','panasuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5476,0,NULL,'pso','polish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5477,0,NULL,'psp','philippine sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5478,0,NULL,'psq','pasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5479,0,NULL,'psr','portuguese sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5480,0,NULL,'pss','kaulong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5481,0,NULL,'pst','central pashto','1248825600',NULL,NULL,NULL,NULL,'ps',NULL,NULL); +INSERT INTO "iana_records" VALUES(5482,0,NULL,'psu','sauraseni prākrit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5483,0,NULL,'psw','port sandwich','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5484,0,NULL,'psy','piscataway','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5485,0,NULL,'pta','pai tavytera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5486,0,NULL,'pth','pataxó hã-ha-hãe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5487,0,NULL,'pti','pintiini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5488,0,NULL,'ptn','patani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5489,0,NULL,'pto','zo''é','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5490,0,NULL,'ptp','patep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5491,0,NULL,'ptr','piamatsina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5492,0,NULL,'ptt','enrekang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5493,0,NULL,'ptu','bambam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5494,0,NULL,'ptv','port vato','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5495,0,NULL,'ptw','pentlatch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5496,0,NULL,'pty','pathiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5497,0,NULL,'pua','western highland purepecha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5498,0,NULL,'pub','purum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5499,0,NULL,'puc','punan merap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5500,0,NULL,'pud','punan aput','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5501,0,NULL,'pue','puelche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5502,0,NULL,'puf','punan merah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5503,0,NULL,'pug','phuie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5504,0,NULL,'pui','puinave','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5505,0,NULL,'puj','punan tubu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5506,0,NULL,'puk','pu ko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5507,0,NULL,'pum','puma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5508,0,NULL,'puo','puoc','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5509,0,NULL,'pup','pulabu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5510,0,NULL,'puq','puquina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5511,0,NULL,'pur','puruborá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5512,0,NULL,'put','putoh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5513,0,NULL,'puu','punu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5514,0,NULL,'puw','puluwatese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5515,0,NULL,'pux','puare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5516,0,NULL,'puy','purisimeño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5517,0,NULL,'puz','purum naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5518,0,NULL,'pwa','pawaia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5519,0,NULL,'pwb','panawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5520,0,NULL,'pwg','gapapaiwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5521,0,NULL,'pwm','molbog','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5522,0,NULL,'pwn','paiwan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5523,0,NULL,'pwo','pwo western karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5524,0,NULL,'pwr','powari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5525,0,NULL,'pww','pwo northern karen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5526,0,NULL,'pxm','quetzaltepec mixe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5527,0,NULL,'pye','pye krumen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5528,0,NULL,'pym','fyam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5529,0,NULL,'pyn','poyanáwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5530,0,NULL,'pys','lengua de señas del paraguay','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5530,0,NULL,'pys','paraguayan sign language','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5531,0,NULL,'pyu','puyuma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5532,0,NULL,'pyx','pyu (myanmar)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5533,0,NULL,'pyy','pyen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5534,0,NULL,'pzn','para naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5535,0,NULL,'qaa..qtz','private use','1129420800',NULL,NULL,NULL,NULL,NULL,'private-use',NULL); +INSERT INTO "iana_records" VALUES(5536,0,NULL,'qua','quapaw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5537,0,NULL,'qub','huallaga huánuco quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5538,0,NULL,'quc','k''iche''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5538,0,NULL,'quc','quiché','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5539,0,NULL,'qud','calderón highland quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5540,0,NULL,'quf','lambayeque quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5541,0,NULL,'qug','chimborazo highland quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5542,0,NULL,'quh','south bolivian quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5543,0,NULL,'qui','quileute','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5544,0,NULL,'quk','chachapoyas quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5545,0,NULL,'qul','north bolivian quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5546,0,NULL,'qum','sipacapense','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5547,0,NULL,'qun','quinault','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5548,0,NULL,'qup','southern pastaza quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5549,0,NULL,'quq','quinqui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5550,0,NULL,'qur','yanahuanca pasco quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5551,0,NULL,'qus','santiago del estero quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5552,0,NULL,'quv','sacapulteco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5553,0,NULL,'quw','tena lowland quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5554,0,NULL,'qux','yauyos quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5555,0,NULL,'quy','ayacucho quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5556,0,NULL,'quz','cusco quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5557,0,NULL,'qva','ambo-pasco quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5558,0,NULL,'qvc','cajamarca quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5559,0,NULL,'qve','eastern apurímac quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5560,0,NULL,'qvh','huamalíes-dos de mayo huánuco quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5561,0,NULL,'qvi','imbabura highland quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5562,0,NULL,'qvj','loja highland quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5563,0,NULL,'qvl','cajatambo north lima quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5564,0,NULL,'qvm','margos-yarowilca-lauricocha quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5565,0,NULL,'qvn','north junín quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5566,0,NULL,'qvo','napo lowland quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5567,0,NULL,'qvp','pacaraos quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5568,0,NULL,'qvs','san martín quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5569,0,NULL,'qvw','huaylla wanca quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5570,0,NULL,'qvy','queyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5571,0,NULL,'qvz','northern pastaza quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5572,0,NULL,'qwa','corongo ancash quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5573,0,NULL,'qwc','classical quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5574,0,NULL,'qwe','quechuan (family)','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5575,0,NULL,'qwh','huaylas ancash quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5576,0,NULL,'qwm','kuman (russia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5577,0,NULL,'qws','sihuas ancash quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5578,0,NULL,'qwt','kwalhioqua-tlatskanai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5579,0,NULL,'qxa','chiquián ancash quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5580,0,NULL,'qxc','chincha quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5581,0,NULL,'qxh','panao huánuco quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5582,0,NULL,'qxl','salasaca highland quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5583,0,NULL,'qxn','northern conchucos ancash quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5584,0,NULL,'qxo','southern conchucos ancash quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5585,0,NULL,'qxp','puno quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5586,0,NULL,'qxq','qashqa''i','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5587,0,NULL,'qxr','cañar highland quichua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5588,0,NULL,'qxs','southern qiang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5589,0,NULL,'qxt','santa ana de tusi pasco quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5590,0,NULL,'qxu','arequipa-la unión quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5591,0,NULL,'qxw','jauja wanca quechua','1248825600',NULL,NULL,NULL,NULL,'qu',NULL,NULL); +INSERT INTO "iana_records" VALUES(5592,0,NULL,'qya','quenya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5593,0,NULL,'qyp','quiripi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5594,0,NULL,'raa','dungmali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5595,0,NULL,'rab','camling','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5596,0,NULL,'rac','rasawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5597,0,NULL,'rad','rade','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5598,0,NULL,'raf','western meohang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5599,0,NULL,'rag','logooli','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(5599,0,NULL,'rag','lulogooli','1248825600',NULL,NULL,NULL,NULL,'luy',NULL,NULL); +INSERT INTO "iana_records" VALUES(5600,0,NULL,'rah','rabha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5601,0,NULL,'rai','ramoaaina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5602,0,NULL,'raj','rajasthani','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(5603,0,NULL,'rak','tulu-bohuai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5604,0,NULL,'ral','ralte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5605,0,NULL,'ram','canela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5606,0,NULL,'ran','riantana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5607,0,NULL,'rao','rao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5608,0,NULL,'rap','rapanui','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5609,0,NULL,'raq','saam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5610,0,NULL,'rar','cook islands maori','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5610,0,NULL,'rar','rarotongan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5611,0,NULL,'ras','tegali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5612,0,NULL,'rat','razajerdi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5613,0,NULL,'rau','raute','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5614,0,NULL,'rav','sampang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5615,0,NULL,'raw','rawang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5616,0,NULL,'rax','rang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5617,0,NULL,'ray','rapa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5618,0,NULL,'raz','rahambuu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5619,0,NULL,'rbb','rumai palaung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5620,0,NULL,'rbk','northern bontok','1268265600',NULL,NULL,NULL,NULL,'bnc',NULL,NULL); +INSERT INTO "iana_records" VALUES(5621,0,NULL,'rbl','miraya bikol','1268265600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(5622,0,NULL,'rcf','réunion creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5623,0,NULL,'rdb','rudbari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5624,0,NULL,'rea','rerau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5625,0,NULL,'reb','rembong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5626,0,NULL,'ree','rejang kayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5627,0,NULL,'reg','kara (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5628,0,NULL,'rei','reli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5629,0,NULL,'rej','rejang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5630,0,NULL,'rel','rendille','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5631,0,NULL,'rem','remo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5632,0,NULL,'ren','rengao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5633,0,NULL,'rer','rer bare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5634,0,NULL,'res','reshe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5635,0,NULL,'ret','retta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5636,0,NULL,'rey','reyesano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5637,0,NULL,'rga','roria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5638,0,NULL,'rge','romano-greek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5639,0,NULL,'rgk','rangkas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5640,0,NULL,'rgn','romagnol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5641,0,NULL,'rgr','resígaro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5642,0,NULL,'rgs','southern roglai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5643,0,NULL,'rgu','ringgou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5644,0,NULL,'rhg','rohingya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5645,0,NULL,'rhp','yahang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5646,0,NULL,'ria','riang (india)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5647,0,NULL,'rie','rien','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5648,0,NULL,'rif','tarifit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5649,0,NULL,'ril','riang (myanmar)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5650,0,NULL,'rim','nyaturu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5651,0,NULL,'rin','nungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5652,0,NULL,'rir','ribun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5653,0,NULL,'rit','ritarungo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5654,0,NULL,'riu','riung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5655,0,NULL,'rjg','rajong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5656,0,NULL,'rji','raji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5657,0,NULL,'rjs','rajbanshi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5658,0,NULL,'rka','kraol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5659,0,NULL,'rkb','rikbaktsa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5660,0,NULL,'rkh','rakahanga-manihiki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5661,0,NULL,'rki','rakhine','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5662,0,NULL,'rkm','marka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5663,0,NULL,'rkt','kamta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5663,0,NULL,'rkt','rangpuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5664,0,NULL,'rma','rama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5665,0,NULL,'rmb','rembarunga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5666,0,NULL,'rmc','carpathian romani','1248825600',NULL,NULL,NULL,NULL,'rom',NULL,NULL); +INSERT INTO "iana_records" VALUES(5667,0,NULL,'rmd','traveller danish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5668,0,NULL,'rme','angloromani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5669,0,NULL,'rmf','kalo finnish romani','1248825600',NULL,NULL,NULL,NULL,'rom',NULL,NULL); +INSERT INTO "iana_records" VALUES(5670,0,NULL,'rmg','traveller norwegian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5671,0,NULL,'rmh','murkim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5672,0,NULL,'rmi','lomavren','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5673,0,NULL,'rmk','romkun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5674,0,NULL,'rml','baltic romani','1248825600',NULL,NULL,NULL,NULL,'rom',NULL,NULL); +INSERT INTO "iana_records" VALUES(5675,0,NULL,'rmm','roma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5676,0,NULL,'rmn','balkan romani','1248825600',NULL,NULL,NULL,NULL,'rom',NULL,NULL); +INSERT INTO "iana_records" VALUES(5677,0,NULL,'rmo','sinte romani','1248825600',NULL,NULL,NULL,NULL,'rom',NULL,NULL); +INSERT INTO "iana_records" VALUES(5678,0,NULL,'rmp','rempi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5679,0,NULL,'rmq','caló','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5680,0,NULL,'rmr','caló','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see emx, rmq'); +INSERT INTO "iana_records" VALUES(5681,0,NULL,'rms','romanian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5682,0,NULL,'rmt','domari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5683,0,NULL,'rmu','tavringer romani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5684,0,NULL,'rmv','romanova','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5685,0,NULL,'rmw','welsh romani','1248825600',NULL,NULL,NULL,NULL,'rom',NULL,NULL); +INSERT INTO "iana_records" VALUES(5686,0,NULL,'rmx','romam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5687,0,NULL,'rmy','vlax romani','1248825600',NULL,NULL,NULL,NULL,'rom',NULL,NULL); +INSERT INTO "iana_records" VALUES(5688,0,NULL,'rmz','marma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5689,0,NULL,'rna','runa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5690,0,NULL,'rnd','ruund','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5691,0,NULL,'rng','ronga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5692,0,NULL,'rnl','ranglong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5693,0,NULL,'rnn','roon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5694,0,NULL,'rnp','rongpo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5695,0,NULL,'rnw','rungwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5696,0,NULL,'roa','romance languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5697,0,NULL,'rob','tae''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5698,0,NULL,'roc','cacgia roglai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5699,0,NULL,'rod','rogo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5700,0,NULL,'roe','ronji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5701,0,NULL,'rof','rombo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5702,0,NULL,'rog','northern roglai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5703,0,NULL,'rol','romblomanon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5704,0,NULL,'rom','romany','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(5705,0,NULL,'roo','rotokas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5706,0,NULL,'rop','kriol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5707,0,NULL,'ror','rongga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5708,0,NULL,'rou','runga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5709,0,NULL,'row','dela-oenale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5710,0,NULL,'rpn','repanbitip','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5711,0,NULL,'rpt','rapting','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5712,0,NULL,'rri','ririo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5713,0,NULL,'rro','waima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5714,0,NULL,'rsb','romano-serbian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5715,0,NULL,'rsi','rennellese sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5716,0,NULL,'rsl','russian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5717,0,NULL,'rth','ratahan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5718,0,NULL,'rtm','rotuman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5719,0,NULL,'rtw','rathawi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5720,0,NULL,'rub','gungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5721,0,NULL,'ruc','ruuli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5722,0,NULL,'rue','rusyn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5723,0,NULL,'ruf','luguru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5724,0,NULL,'rug','roviana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5725,0,NULL,'ruh','ruga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5726,0,NULL,'rui','rufiji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5727,0,NULL,'ruk','che','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5728,0,NULL,'ruo','istro romanian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5729,0,NULL,'rup','aromanian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5729,0,NULL,'rup','arumanian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5729,0,NULL,'rup','macedo-romanian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5730,0,NULL,'ruq','megleno romanian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5731,0,NULL,'rut','rutul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5732,0,NULL,'ruu','lanas lobu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5733,0,NULL,'ruy','mala (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5734,0,NULL,'ruz','ruma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5735,0,NULL,'rwa','rawo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5736,0,NULL,'rwk','rwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5737,0,NULL,'rwm','amba (uganda)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5738,0,NULL,'rwo','rawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5739,0,NULL,'rwr','marwari (india)','1248825600',NULL,NULL,NULL,NULL,'mwr',NULL,NULL); +INSERT INTO "iana_records" VALUES(5740,0,NULL,'ryn','northern amami-oshima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5741,0,NULL,'rys','yaeyama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5742,0,NULL,'ryu','central okinawan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5743,0,NULL,'saa','saba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5744,0,NULL,'sab','buglere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5745,0,NULL,'sac','meskwaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5746,0,NULL,'sad','sandawe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5747,0,NULL,'sae','sabanê','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5748,0,NULL,'saf','safaliba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5749,0,NULL,'sah','yakut','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5750,0,NULL,'sai','south american indian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5751,0,NULL,'saj','sahu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5752,0,NULL,'sak','sake','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5753,0,NULL,'sal','salishan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5754,0,NULL,'sam','samaritan aramaic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5755,0,NULL,'sao','sause','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5756,0,NULL,'sap','sanapaná','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5757,0,NULL,'saq','samburu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5758,0,NULL,'sar','saraveca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5759,0,NULL,'sas','sasak','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5760,0,NULL,'sat','santali','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5761,0,NULL,'sau','saleman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5762,0,NULL,'sav','saafi-saafi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5763,0,NULL,'saw','sawi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5764,0,NULL,'sax','sa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5765,0,NULL,'say','saya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5766,0,NULL,'saz','saurashtra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5767,0,NULL,'sba','ngambay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5768,0,NULL,'sbb','simbo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5769,0,NULL,'sbc','kele (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5770,0,NULL,'sbd','southern samo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5771,0,NULL,'sbe','saliba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5772,0,NULL,'sbf','shabo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5773,0,NULL,'sbg','seget','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5774,0,NULL,'sbh','sori-harengan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5775,0,NULL,'sbi','seti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5776,0,NULL,'sbj','surbakhal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5777,0,NULL,'sbk','safwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5778,0,NULL,'sbl','botolan sambal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5779,0,NULL,'sbm','sagala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5780,0,NULL,'sbn','sindhi bhil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5781,0,NULL,'sbo','sabüm','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5782,0,NULL,'sbp','sangu (tanzania)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5783,0,NULL,'sbq','sileibi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5784,0,NULL,'sbr','sembakung murut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5785,0,NULL,'sbs','subiya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5786,0,NULL,'sbt','kimki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5787,0,NULL,'sbu','stod bhoti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5788,0,NULL,'sbv','sabine','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5789,0,NULL,'sbw','simba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5790,0,NULL,'sbx','seberuang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5791,0,NULL,'sby','soli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5792,0,NULL,'sbz','sara kaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5793,0,NULL,'sca','sansu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5794,0,NULL,'scb','chut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5795,0,NULL,'sce','dongxiang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5796,0,NULL,'scf','san miguel creole french','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5797,0,NULL,'scg','sanggau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5798,0,NULL,'sch','sakachep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5799,0,NULL,'sci','sri lankan creole malay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5800,0,NULL,'sck','sadri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5801,0,NULL,'scl','shina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5802,0,NULL,'scn','sicilian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5803,0,NULL,'sco','scots','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5804,0,NULL,'scp','helambu sherpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5805,0,NULL,'scq','sa''och','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5806,0,NULL,'scs','north slavey','1248825600',NULL,NULL,NULL,NULL,'den',NULL,NULL); +INSERT INTO "iana_records" VALUES(5807,0,NULL,'scu','shumcho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5808,0,NULL,'scv','sheni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5809,0,NULL,'scw','sha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5810,0,NULL,'scx','sicel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5811,0,NULL,'sda','toraja-sa''dan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5812,0,NULL,'sdb','shabak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5813,0,NULL,'sdc','sassarese sardinian','1248825600',NULL,NULL,NULL,NULL,'sc',NULL,NULL); +INSERT INTO "iana_records" VALUES(5814,0,NULL,'sde','surubu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5815,0,NULL,'sdf','sarli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5816,0,NULL,'sdg','savi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5817,0,NULL,'sdh','southern kurdish','1248825600',NULL,NULL,NULL,NULL,'ku',NULL,NULL); +INSERT INTO "iana_records" VALUES(5818,0,NULL,'sdj','suundi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5819,0,NULL,'sdk','sos kundi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5820,0,NULL,'sdl','saudi arabian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5821,0,NULL,'sdm','semandang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5822,0,NULL,'sdn','gallurese sardinian','1248825600',NULL,NULL,NULL,NULL,'sc',NULL,NULL); +INSERT INTO "iana_records" VALUES(5823,0,NULL,'sdo','bukar-sadung bidayuh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5824,0,NULL,'sdp','sherdukpen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5825,0,NULL,'sdr','oraon sadri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5826,0,NULL,'sds','sened','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5827,0,NULL,'sdt','shuadit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5828,0,NULL,'sdu','sarudu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5829,0,NULL,'sdv','eastern sudanic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5830,0,NULL,'sdx','sibu melanau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5831,0,NULL,'sdz','sallands','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5832,0,NULL,'sea','semai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5833,0,NULL,'seb','shempire senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5834,0,NULL,'sec','sechelt','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5835,0,NULL,'sed','sedang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5836,0,NULL,'see','seneca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5837,0,NULL,'sef','cebaara senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5838,0,NULL,'seg','segeju','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5839,0,NULL,'seh','sena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5840,0,NULL,'sei','seri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5841,0,NULL,'sej','sene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5842,0,NULL,'sek','sekani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5843,0,NULL,'sel','selkup','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5844,0,NULL,'sem','semitic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5845,0,NULL,'sen','nanerigé sénoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5846,0,NULL,'seo','suarmin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5847,0,NULL,'sep','sìcìté sénoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5848,0,NULL,'seq','senara sénoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5849,0,NULL,'ser','serrano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5850,0,NULL,'ses','koyraboro senni songhai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5851,0,NULL,'set','sentani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5852,0,NULL,'seu','serui-laut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5853,0,NULL,'sev','nyarafolo senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5854,0,NULL,'sew','sewa bay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5855,0,NULL,'sey','secoya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5856,0,NULL,'sez','senthang chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5857,0,NULL,'sfb','french belgian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5857,0,NULL,'sfb','langue des signes de belgique francophone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5858,0,NULL,'sfm','small flowery miao','1248825600',NULL,NULL,NULL,NULL,'hmn',NULL,NULL); +INSERT INTO "iana_records" VALUES(5859,0,NULL,'sfs','south african sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5860,0,NULL,'sfw','sehwi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5861,0,NULL,'sga','old irish (to 900)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5862,0,NULL,'sgb','mag-antsi ayta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5863,0,NULL,'sgc','kipsigis','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(5864,0,NULL,'sgd','surigaonon','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5865,0,NULL,'sge','segai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5866,0,NULL,'sgg','swiss-german sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5867,0,NULL,'sgh','shughni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5868,0,NULL,'sgi','suga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5869,0,NULL,'sgk','sangkong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5870,0,NULL,'sgl','sanglechi-ishkashimi','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see isk, sgy'); +INSERT INTO "iana_records" VALUES(5871,0,NULL,'sgm','singa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5872,0,NULL,'sgn','sign languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5873,0,NULL,'sgo','songa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5874,0,NULL,'sgp','singpho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5875,0,NULL,'sgr','sangisari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5876,0,NULL,'sgt','brokpake','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5877,0,NULL,'sgu','salas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5878,0,NULL,'sgw','sebat bet gurage','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5879,0,NULL,'sgx','sierra leone sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5880,0,NULL,'sgy','sanglechi','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5881,0,NULL,'sgz','sursurunga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5882,0,NULL,'sha','shall-zwall','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5883,0,NULL,'shb','ninam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5884,0,NULL,'shc','sonde','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5885,0,NULL,'shd','kundal shahi','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5886,0,NULL,'she','sheko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5887,0,NULL,'shg','shua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5888,0,NULL,'shh','shoshoni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5889,0,NULL,'shi','tachelhit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5890,0,NULL,'shj','shatt','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5891,0,NULL,'shk','shilluk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5892,0,NULL,'shl','shendu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5893,0,NULL,'shm','shahrudi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5894,0,NULL,'shn','shan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5895,0,NULL,'sho','shanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5896,0,NULL,'shp','shipibo-conibo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5897,0,NULL,'shq','sala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5898,0,NULL,'shr','shi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5899,0,NULL,'shs','shuswap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5900,0,NULL,'sht','shasta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5901,0,NULL,'shu','chadian arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(5902,0,NULL,'shv','shehri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5903,0,NULL,'shw','shwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5904,0,NULL,'shx','she','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5905,0,NULL,'shy','tachawit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5906,0,NULL,'shz','syenara senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5907,0,NULL,'sia','akkala sami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5908,0,NULL,'sib','sebop','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5909,0,NULL,'sid','sidamo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5910,0,NULL,'sie','simaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5911,0,NULL,'sif','siamou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5912,0,NULL,'sig','paasaal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5913,0,NULL,'sih','zire','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5914,0,NULL,'sii','shom peng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5915,0,NULL,'sij','numbami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5916,0,NULL,'sik','sikiana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5917,0,NULL,'sil','tumulung sisaala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5918,0,NULL,'sim','mende (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5919,0,NULL,'sio','siouan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5920,0,NULL,'sip','sikkimese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5921,0,NULL,'siq','sonia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5922,0,NULL,'sir','siri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5923,0,NULL,'sis','siuslaw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5924,0,NULL,'sit','sino-tibetan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5925,0,NULL,'siu','sinagen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5926,0,NULL,'siv','sumariup','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5927,0,NULL,'siw','siwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5928,0,NULL,'six','sumau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5929,0,NULL,'siy','sivandi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5930,0,NULL,'siz','siwi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5931,0,NULL,'sja','epena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5932,0,NULL,'sjb','sajau basap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5933,0,NULL,'sjd','kildin sami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5934,0,NULL,'sje','pite sami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5935,0,NULL,'sjg','assangori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5936,0,NULL,'sjk','kemi sami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5937,0,NULL,'sjl','miji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5937,0,NULL,'sjl','sajalong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5938,0,NULL,'sjm','mapun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5939,0,NULL,'sjn','sindarin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5940,0,NULL,'sjo','xibe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5941,0,NULL,'sjp','surjapuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5942,0,NULL,'sjr','siar-lak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5943,0,NULL,'sjs','senhaja de srair','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5944,0,NULL,'sjt','ter sami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5945,0,NULL,'sju','ume sami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5946,0,NULL,'sjw','shawnee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5947,0,NULL,'ska','skagit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5948,0,NULL,'skb','saek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5949,0,NULL,'skc','sauk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5950,0,NULL,'skd','southern sierra miwok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5951,0,NULL,'ske','seke (vanuatu)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5952,0,NULL,'skf','sakirabiá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5953,0,NULL,'skg','sakalava malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(5954,0,NULL,'skh','sikule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5955,0,NULL,'ski','sika','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5956,0,NULL,'skj','seke (nepal)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5957,0,NULL,'skk','sok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5958,0,NULL,'skm','sakam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5959,0,NULL,'skn','kolibugan subanon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5960,0,NULL,'sko','seko tengah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5961,0,NULL,'skp','sekapan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5962,0,NULL,'skq','sininkere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5963,0,NULL,'skr','seraiki','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(5964,0,NULL,'sks','maia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5965,0,NULL,'skt','sakata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5966,0,NULL,'sku','sakao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5967,0,NULL,'skv','skou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5968,0,NULL,'skw','skepi creole dutch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5969,0,NULL,'skx','seko padang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5970,0,NULL,'sky','sikaiana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5971,0,NULL,'skz','sekar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5972,0,NULL,'sla','slavic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(5973,0,NULL,'slc','sáliba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5974,0,NULL,'sld','sissala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5975,0,NULL,'sle','sholaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5976,0,NULL,'slf','swiss-italian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5977,0,NULL,'slg','selungai murut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5978,0,NULL,'slh','southern puget sound salish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5979,0,NULL,'sli','lower silesian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5980,0,NULL,'slj','salumá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5981,0,NULL,'sll','salt-yui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5982,0,NULL,'slm','pangutaran sama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5983,0,NULL,'sln','salinan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5984,0,NULL,'slp','lamaholot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5985,0,NULL,'slq','salchuq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5986,0,NULL,'slr','salar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5987,0,NULL,'sls','singapore sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5988,0,NULL,'slt','sila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5989,0,NULL,'slu','selaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5990,0,NULL,'slw','sialum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5991,0,NULL,'slx','salampasu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5992,0,NULL,'sly','selayar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5993,0,NULL,'slz','ma''ya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5994,0,NULL,'sma','southern sami','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5995,0,NULL,'smb','simbari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5996,0,NULL,'smc','som','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5997,0,NULL,'smd','sama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5998,0,NULL,'smf','auwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(5999,0,NULL,'smg','simbali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6000,0,NULL,'smh','samei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6001,0,NULL,'smi','sami languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6002,0,NULL,'smj','lule sami','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6003,0,NULL,'smk','bolinao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6004,0,NULL,'sml','central sama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6005,0,NULL,'smm','musasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6006,0,NULL,'smn','inari sami','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6007,0,NULL,'smp','samaritan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6008,0,NULL,'smq','samo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6009,0,NULL,'smr','simeulue','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6010,0,NULL,'sms','skolt sami','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6011,0,NULL,'smt','simte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6012,0,NULL,'smu','somray','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6013,0,NULL,'smv','samvedi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6014,0,NULL,'smw','sumbawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6015,0,NULL,'smx','samba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6016,0,NULL,'smy','semnani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6017,0,NULL,'smz','simeku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6018,0,NULL,'snb','sebuyau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6019,0,NULL,'snc','sinaugoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6020,0,NULL,'sne','bau bidayuh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6021,0,NULL,'snf','noon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6022,0,NULL,'sng','sanga (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6023,0,NULL,'snh','shinabo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6024,0,NULL,'sni','sensi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6025,0,NULL,'snj','riverain sango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6026,0,NULL,'snk','soninke','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6027,0,NULL,'snl','sangil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6028,0,NULL,'snm','southern ma''di','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6029,0,NULL,'snn','siona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6030,0,NULL,'sno','snohomish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6031,0,NULL,'snp','siane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6032,0,NULL,'snq','sangu (gabon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6033,0,NULL,'snr','sihan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6034,0,NULL,'sns','nahavaq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6034,0,NULL,'sns','south west bay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6035,0,NULL,'snu','senggi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6035,0,NULL,'snu','viid','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6036,0,NULL,'snv','sa''ban','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6037,0,NULL,'snw','selee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6038,0,NULL,'snx','sam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6039,0,NULL,'sny','saniyo-hiyewe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6040,0,NULL,'snz','sinsauru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6041,0,NULL,'soa','thai song','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6042,0,NULL,'sob','sobei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6043,0,NULL,'soc','so (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6044,0,NULL,'sod','songoora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6045,0,NULL,'soe','songomeno','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6046,0,NULL,'sog','sogdian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6047,0,NULL,'soh','aka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6048,0,NULL,'soi','sonha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6049,0,NULL,'soj','soi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6050,0,NULL,'sok','sokoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6051,0,NULL,'sol','solos','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6052,0,NULL,'son','songhai languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6053,0,NULL,'soo','songo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6054,0,NULL,'sop','songe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6055,0,NULL,'soq','kanasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6056,0,NULL,'sor','somrai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6057,0,NULL,'sos','seeku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6058,0,NULL,'sou','southern thai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6059,0,NULL,'sov','sonsorol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6060,0,NULL,'sow','sowanda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6061,0,NULL,'sox','so (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6062,0,NULL,'soy','miyobe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6063,0,NULL,'soz','temi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6064,0,NULL,'spb','sepa (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6065,0,NULL,'spc','sapé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6066,0,NULL,'spd','saep','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6067,0,NULL,'spe','sepa (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6068,0,NULL,'spg','sian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6069,0,NULL,'spi','saponi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6070,0,NULL,'spk','sengo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6071,0,NULL,'spl','selepet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6072,0,NULL,'spm','sepen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6073,0,NULL,'spo','spokane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6074,0,NULL,'spp','supyire senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6075,0,NULL,'spq','loreto-ucayali spanish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6076,0,NULL,'spr','saparua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6077,0,NULL,'sps','saposa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6078,0,NULL,'spt','spiti bhoti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6079,0,NULL,'spu','sapuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6080,0,NULL,'spx','south picene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6081,0,NULL,'spy','sabaot','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(6082,0,NULL,'sqa','shama-sambuga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6083,0,NULL,'sqh','shau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6084,0,NULL,'sqj','albanian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6085,0,NULL,'sqm','suma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6086,0,NULL,'sqn','susquehannock','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6087,0,NULL,'sqo','sorkhei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6088,0,NULL,'sqq','sou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6089,0,NULL,'sqr','siculo arabic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6090,0,NULL,'sqs','sri lankan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6091,0,NULL,'sqt','soqotri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6092,0,NULL,'squ','squamish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6093,0,NULL,'sra','saruga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6094,0,NULL,'srb','sora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6095,0,NULL,'src','logudorese sardinian','1248825600',NULL,NULL,NULL,NULL,'sc',NULL,NULL); +INSERT INTO "iana_records" VALUES(6096,0,NULL,'sre','sara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6097,0,NULL,'srf','nafi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6098,0,NULL,'srg','sulod','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6099,0,NULL,'srh','sarikoli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6100,0,NULL,'sri','siriano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6101,0,NULL,'srk','serudung murut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6102,0,NULL,'srl','isirawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6103,0,NULL,'srm','saramaccan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6104,0,NULL,'srn','sranan tongo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6105,0,NULL,'sro','campidanese sardinian','1248825600',NULL,NULL,NULL,NULL,'sc',NULL,NULL); +INSERT INTO "iana_records" VALUES(6106,0,NULL,'srq','sirionó','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6107,0,NULL,'srr','serer','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6108,0,NULL,'srs','sarsi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6109,0,NULL,'srt','sauri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6110,0,NULL,'sru','suruí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6111,0,NULL,'srv','southern sorsoganon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6112,0,NULL,'srw','serua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6113,0,NULL,'srx','sirmauri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6114,0,NULL,'sry','sera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6115,0,NULL,'srz','shahmirzadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6116,0,NULL,'ssa','nilo-saharan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6117,0,NULL,'ssb','southern sama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6118,0,NULL,'ssc','suba-simbiti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6119,0,NULL,'ssd','siroi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6120,0,NULL,'sse','balangingi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6120,0,NULL,'sse','bangingih sama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6121,0,NULL,'ssf','thao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6122,0,NULL,'ssg','seimat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6123,0,NULL,'ssh','shihhi arabic','1248825600',NULL,NULL,NULL,NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(6124,0,NULL,'ssi','sansi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6125,0,NULL,'ssj','sausi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6126,0,NULL,'ssk','sunam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6127,0,NULL,'ssl','western sisaala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6128,0,NULL,'ssm','semnam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6129,0,NULL,'ssn','waata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6130,0,NULL,'sso','sissano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6131,0,NULL,'ssp','spanish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6132,0,NULL,'ssq','so''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6133,0,NULL,'ssr','swiss-french sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6134,0,NULL,'sss','sô','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6135,0,NULL,'sst','sinasina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6136,0,NULL,'ssu','susuami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6137,0,NULL,'ssv','shark bay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6138,0,NULL,'ssx','samberigi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6139,0,NULL,'ssy','saho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6140,0,NULL,'ssz','sengseng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6141,0,NULL,'sta','settla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6142,0,NULL,'stb','northern subanen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6143,0,NULL,'std','sentinel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6144,0,NULL,'ste','liana-seti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6145,0,NULL,'stf','seta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6146,0,NULL,'stg','trieng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6147,0,NULL,'sth','shelta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6148,0,NULL,'sti','bulo stieng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6149,0,NULL,'stj','matya samo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6150,0,NULL,'stk','arammba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6151,0,NULL,'stl','stellingwerfs','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6152,0,NULL,'stm','setaman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6153,0,NULL,'stn','owa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6154,0,NULL,'sto','stoney','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6155,0,NULL,'stp','southeastern tepehuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6156,0,NULL,'stq','saterfriesisch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6157,0,NULL,'str','straits salish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6158,0,NULL,'sts','shumashti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6159,0,NULL,'stt','budeh stieng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6160,0,NULL,'stu','samtao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6161,0,NULL,'stv','silt''e','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6162,0,NULL,'stw','satawalese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6163,0,NULL,'sua','sulka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6164,0,NULL,'sub','suku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6165,0,NULL,'suc','western subanon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6166,0,NULL,'sue','suena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6167,0,NULL,'sug','suganga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6168,0,NULL,'sui','suki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6169,0,NULL,'suj','shubi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6170,0,NULL,'suk','sukuma','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6171,0,NULL,'sul','surigaonon','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see sgd, tgn'); +INSERT INTO "iana_records" VALUES(6172,0,NULL,'sum','sumo-mayangna','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see ulw, yan'); +INSERT INTO "iana_records" VALUES(6173,0,NULL,'suq','suri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6174,0,NULL,'sur','mwaghavul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6175,0,NULL,'sus','susu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6176,0,NULL,'sut','subtiaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6177,0,NULL,'suv','sulung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6178,0,NULL,'suw','sumbwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6179,0,NULL,'sux','sumerian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6180,0,NULL,'suy','suyá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6181,0,NULL,'suz','sunwar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6182,0,NULL,'sva','svan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6183,0,NULL,'svb','ulau-suain','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6184,0,NULL,'svc','vincentian creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6185,0,NULL,'sve','serili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6186,0,NULL,'svk','slovakian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6187,0,NULL,'svr','savara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6188,0,NULL,'svs','savosavo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6189,0,NULL,'svx','skalvian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6190,0,NULL,'swb','maore comorian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6191,0,NULL,'swc','congo swahili','1248825600',NULL,NULL,NULL,NULL,'sw',NULL,NULL); +INSERT INTO "iana_records" VALUES(6192,0,NULL,'swf','sere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6193,0,NULL,'swg','swabian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6194,0,NULL,'swh','kiswahili','1248825600',NULL,NULL,NULL,NULL,'sw',NULL,NULL); +INSERT INTO "iana_records" VALUES(6194,0,NULL,'swh','swahili (individual language)','1248825600',NULL,NULL,NULL,NULL,'sw',NULL,NULL); +INSERT INTO "iana_records" VALUES(6195,0,NULL,'swi','sui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6196,0,NULL,'swj','sira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6197,0,NULL,'swk','malawi sena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6198,0,NULL,'swl','swedish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6199,0,NULL,'swm','samosa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6200,0,NULL,'swn','sawknah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6201,0,NULL,'swo','shanenawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6202,0,NULL,'swp','suau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6203,0,NULL,'swq','sharwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6204,0,NULL,'swr','saweru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6205,0,NULL,'sws','seluwasan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6206,0,NULL,'swt','sawila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6207,0,NULL,'swu','suwawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6208,0,NULL,'swv','shekhawati','1248825600',NULL,NULL,NULL,NULL,'mwr',NULL,NULL); +INSERT INTO "iana_records" VALUES(6209,0,NULL,'sww','sowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6210,0,NULL,'swx','suruahá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6211,0,NULL,'swy','sarua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6212,0,NULL,'sxb','suba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6213,0,NULL,'sxc','sicanian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6214,0,NULL,'sxe','sighu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6215,0,NULL,'sxg','shixing','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6216,0,NULL,'sxk','southern kalapuya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6217,0,NULL,'sxl','selian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6218,0,NULL,'sxm','samre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6219,0,NULL,'sxn','sangir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6220,0,NULL,'sxo','sorothaptic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6221,0,NULL,'sxr','saaroa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6222,0,NULL,'sxs','sasaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6223,0,NULL,'sxu','upper saxon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6224,0,NULL,'sxw','saxwe gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6225,0,NULL,'sya','siang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6226,0,NULL,'syb','central subanen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6227,0,NULL,'syc','classical syriac','1175558400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6228,0,NULL,'syd','samoyedic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6229,0,NULL,'syi','seki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6230,0,NULL,'syk','sukur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6231,0,NULL,'syl','sylheti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6232,0,NULL,'sym','maya samo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6233,0,NULL,'syn','senaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6234,0,NULL,'syo','suoy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6235,0,NULL,'syr','syriac','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(6236,0,NULL,'sys','sinyar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6237,0,NULL,'syw','kagate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6238,0,NULL,'syy','al-sayyid bedouin sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6239,0,NULL,'sza','semelai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6240,0,NULL,'szb','ngalum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6241,0,NULL,'szc','semaq beri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6242,0,NULL,'szd','seru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6243,0,NULL,'sze','seze','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6244,0,NULL,'szg','sengele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6245,0,NULL,'szl','silesian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6246,0,NULL,'szn','sula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6247,0,NULL,'szp','suabo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6248,0,NULL,'szv','isu (fako division)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6249,0,NULL,'szw','sawai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6250,0,NULL,'taa','lower tanana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6251,0,NULL,'tab','tabassaran','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6252,0,NULL,'tac','lowland tarahumara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6253,0,NULL,'tad','tause','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6254,0,NULL,'tae','tariana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6255,0,NULL,'taf','tapirapé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6256,0,NULL,'tag','tagoi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6257,0,NULL,'tai','tai languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6258,0,NULL,'taj','eastern tamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6259,0,NULL,'tak','tala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6260,0,NULL,'tal','tal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6261,0,NULL,'tan','tangale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6262,0,NULL,'tao','yami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6263,0,NULL,'tap','taabwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6264,0,NULL,'taq','tamasheq','1248825600',NULL,NULL,NULL,NULL,'tmh',NULL,NULL); +INSERT INTO "iana_records" VALUES(6265,0,NULL,'tar','central tarahumara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6266,0,NULL,'tas','tay boi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6267,0,NULL,'tau','upper tanana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6268,0,NULL,'tav','tatuyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6269,0,NULL,'taw','tai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6270,0,NULL,'tax','tamki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6271,0,NULL,'tay','atayal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6272,0,NULL,'taz','tocho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6273,0,NULL,'tba','aikanã','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6274,0,NULL,'tbb','tapeba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6275,0,NULL,'tbc','takia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6276,0,NULL,'tbd','kaki ae','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6277,0,NULL,'tbe','tanimbili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6278,0,NULL,'tbf','mandara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6279,0,NULL,'tbg','north tairora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6280,0,NULL,'tbh','thurawal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6281,0,NULL,'tbi','gaam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6282,0,NULL,'tbj','tiang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6283,0,NULL,'tbk','calamian tagbanwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6284,0,NULL,'tbl','tboli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6285,0,NULL,'tbm','tagbu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6286,0,NULL,'tbn','barro negro tunebo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6287,0,NULL,'tbo','tawala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6288,0,NULL,'tbp','diebroud','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6288,0,NULL,'tbp','taworta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6289,0,NULL,'tbq','tibeto-burman languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6290,0,NULL,'tbr','tumtum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6291,0,NULL,'tbs','tanguat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6292,0,NULL,'tbt','tembo (kitembo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6293,0,NULL,'tbu','tubar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6294,0,NULL,'tbv','tobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6295,0,NULL,'tbw','tagbanwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6296,0,NULL,'tbx','kapin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6297,0,NULL,'tby','tabaru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6298,0,NULL,'tbz','ditammari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6299,0,NULL,'tca','ticuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6300,0,NULL,'tcb','tanacross','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6301,0,NULL,'tcc','datooga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6302,0,NULL,'tcd','tafi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6303,0,NULL,'tce','southern tutchone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6304,0,NULL,'tcf','malinaltepec me''phaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6304,0,NULL,'tcf','malinaltepec tlapanec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6305,0,NULL,'tcg','tamagario','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6306,0,NULL,'tch','turks and caicos creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6307,0,NULL,'tci','wára','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6308,0,NULL,'tck','tchitchege','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6309,0,NULL,'tcl','taman (myanmar)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6310,0,NULL,'tcm','tanahmerah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6311,0,NULL,'tcn','tichurong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6312,0,NULL,'tco','taungyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6313,0,NULL,'tcp','tawr chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6314,0,NULL,'tcq','kaiy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6315,0,NULL,'tcs','torres strait creole','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6316,0,NULL,'tct','t''en','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6317,0,NULL,'tcu','southeastern tarahumara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6318,0,NULL,'tcw','tecpatlán totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6319,0,NULL,'tcx','toda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6320,0,NULL,'tcy','tulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6321,0,NULL,'tcz','thado chin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6322,0,NULL,'tda','tagdal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6323,0,NULL,'tdb','panchpargania','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6324,0,NULL,'tdc','emberá-tadó','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6325,0,NULL,'tdd','tai nüa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6326,0,NULL,'tde','tiranige diga dogon','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6327,0,NULL,'tdf','talieng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6328,0,NULL,'tdg','western tamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6329,0,NULL,'tdh','thulung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6330,0,NULL,'tdi','tomadino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6331,0,NULL,'tdj','tajio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6332,0,NULL,'tdk','tambas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6333,0,NULL,'tdl','sur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6334,0,NULL,'tdn','tondano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6335,0,NULL,'tdo','teme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6336,0,NULL,'tdq','tita','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6337,0,NULL,'tdr','todrah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6338,0,NULL,'tds','doutai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6339,0,NULL,'tdt','tetun dili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6340,0,NULL,'tdu','tempasuk dusun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6341,0,NULL,'tdv','toro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6342,0,NULL,'tdx','tandroy-mahafaly malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(6343,0,NULL,'tdy','tadyawan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6344,0,NULL,'tea','temiar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6345,0,NULL,'teb','tetete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6346,0,NULL,'tec','terik','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(6347,0,NULL,'ted','tepo krumen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6348,0,NULL,'tee','huehuetla tepehua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6349,0,NULL,'tef','teressa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6350,0,NULL,'teg','teke-tege','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6351,0,NULL,'teh','tehuelche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6352,0,NULL,'tei','torricelli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6353,0,NULL,'tek','ibali teke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6354,0,NULL,'tem','timne','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6355,0,NULL,'ten','tama (colombia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6356,0,NULL,'teo','teso','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6357,0,NULL,'tep','tepecano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6358,0,NULL,'teq','temein','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6359,0,NULL,'ter','tereno','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6360,0,NULL,'tes','tengger','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6361,0,NULL,'tet','tetum','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6362,0,NULL,'teu','soo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6363,0,NULL,'tev','teor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6364,0,NULL,'tew','tewa (usa)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6365,0,NULL,'tex','tennet','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6366,0,NULL,'tey','tulishi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6367,0,NULL,'tfi','tofin gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6368,0,NULL,'tfn','tanaina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6369,0,NULL,'tfo','tefaro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6370,0,NULL,'tfr','teribe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6371,0,NULL,'tft','ternate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6372,0,NULL,'tga','sagalla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6373,0,NULL,'tgb','tobilung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6374,0,NULL,'tgc','tigak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6375,0,NULL,'tgd','ciwogai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6376,0,NULL,'tge','eastern gorkha tamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6377,0,NULL,'tgf','chalikha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6378,0,NULL,'tgg','tangga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6379,0,NULL,'tgh','tobagonian creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6380,0,NULL,'tgi','lawunuia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6381,0,NULL,'tgn','tandaganon','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6382,0,NULL,'tgo','sudest','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6383,0,NULL,'tgp','tangoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6384,0,NULL,'tgq','tring','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6385,0,NULL,'tgr','tareng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6386,0,NULL,'tgs','nume','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6387,0,NULL,'tgt','central tagbanwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6388,0,NULL,'tgu','tanggu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6389,0,NULL,'tgv','tingui-boto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6390,0,NULL,'tgw','tagwana senoufo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6391,0,NULL,'tgx','tagish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6392,0,NULL,'tgy','togoyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6393,0,NULL,'thc','tai hang tong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6394,0,NULL,'thd','thayore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6395,0,NULL,'the','chitwania tharu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6396,0,NULL,'thf','thangmi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6397,0,NULL,'thh','northern tarahumara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6398,0,NULL,'thi','tai long','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6399,0,NULL,'thk','kitharaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6399,0,NULL,'thk','tharaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6400,0,NULL,'thl','dangaura tharu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6401,0,NULL,'thm','aheu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6402,0,NULL,'thn','thachanadan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6403,0,NULL,'thp','thompson','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6404,0,NULL,'thq','kochila tharu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6405,0,NULL,'thr','rana tharu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6406,0,NULL,'ths','thakali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6407,0,NULL,'tht','tahltan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6408,0,NULL,'thu','thuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6409,0,NULL,'thv','tahaggart tamahaq','1248825600',NULL,NULL,NULL,NULL,'tmh',NULL,NULL); +INSERT INTO "iana_records" VALUES(6410,0,NULL,'thw','thudam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6411,0,NULL,'thx','the','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6412,0,NULL,'thy','tha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6413,0,NULL,'thz','tayart tamajeq','1248825600',NULL,NULL,NULL,NULL,'tmh',NULL,NULL); +INSERT INTO "iana_records" VALUES(6414,0,NULL,'tia','tidikelt tamazight','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6415,0,NULL,'tic','tira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6416,0,NULL,'tid','tidong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6417,0,NULL,'tie','tingal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6418,0,NULL,'tif','tifal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6419,0,NULL,'tig','tigre','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6420,0,NULL,'tih','timugon murut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6421,0,NULL,'tii','tiene','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6422,0,NULL,'tij','tilung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6423,0,NULL,'tik','tikar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6424,0,NULL,'til','tillamook','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6425,0,NULL,'tim','timbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6426,0,NULL,'tin','tindi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6427,0,NULL,'tio','teop','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6428,0,NULL,'tip','trimuris','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6429,0,NULL,'tiq','tiéfo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6430,0,NULL,'tis','masadiit itneg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6431,0,NULL,'tit','tinigua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6432,0,NULL,'tiu','adasen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6433,0,NULL,'tiv','tiv','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6434,0,NULL,'tiw','tiwi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6435,0,NULL,'tix','southern tiwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6436,0,NULL,'tiy','tiruray','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6437,0,NULL,'tiz','tai hongjin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6438,0,NULL,'tja','tajuasohn','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6439,0,NULL,'tjg','tunjung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6440,0,NULL,'tji','northern tujia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6441,0,NULL,'tjm','timucua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6442,0,NULL,'tjn','tonjon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6443,0,NULL,'tjo','temacine tamazight','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6444,0,NULL,'tjs','southern tujia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6445,0,NULL,'tju','tjurruru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6446,0,NULL,'tka','truká','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6447,0,NULL,'tkb','buksa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6448,0,NULL,'tkd','tukudede','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6449,0,NULL,'tke','takwane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6450,0,NULL,'tkf','tukumanféd','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6451,0,NULL,'tkk','takpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6452,0,NULL,'tkl','tokelau','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6453,0,NULL,'tkm','takelma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6454,0,NULL,'tkn','toku-no-shima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6455,0,NULL,'tkp','tikopia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6456,0,NULL,'tkq','tee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6457,0,NULL,'tkr','tsakhur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6458,0,NULL,'tks','takestani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6459,0,NULL,'tkt','kathoriya tharu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6460,0,NULL,'tku','upper necaxa totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6461,0,NULL,'tkw','teanu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6462,0,NULL,'tkx','tangko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6463,0,NULL,'tkz','takua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6464,0,NULL,'tla','southwestern tepehuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6465,0,NULL,'tlb','tobelo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6466,0,NULL,'tlc','yecuatla totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6467,0,NULL,'tld','talaud','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6468,0,NULL,'tlf','telefol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6469,0,NULL,'tlg','tofanma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6470,0,NULL,'tlh','klingon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6470,0,NULL,'tlh','tlhingan-hol','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6471,0,NULL,'tli','tlingit','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6472,0,NULL,'tlj','talinga-bwisi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6473,0,NULL,'tlk','taloki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6474,0,NULL,'tll','tetela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6475,0,NULL,'tlm','tolomako','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6476,0,NULL,'tln','talondo''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6477,0,NULL,'tlo','talodi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6478,0,NULL,'tlp','filomena mata-coahuitlán totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6479,0,NULL,'tlq','tai loi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6480,0,NULL,'tlr','talise','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6481,0,NULL,'tls','tambotalo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6482,0,NULL,'tlt','teluti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6483,0,NULL,'tlu','tulehu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6484,0,NULL,'tlv','taliabu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6485,0,NULL,'tlw','south wemale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6486,0,NULL,'tlx','khehek','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6487,0,NULL,'tly','talysh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6488,0,NULL,'tma','tama (chad)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6489,0,NULL,'tmb','avava','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6489,0,NULL,'tmb','katbol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6490,0,NULL,'tmc','tumak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6491,0,NULL,'tmd','haruai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6492,0,NULL,'tme','tremembé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6493,0,NULL,'tmf','toba-maskoy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6494,0,NULL,'tmg','ternateño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6495,0,NULL,'tmh','tamashek','1129420800',NULL,NULL,NULL,'latn',NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(6496,0,NULL,'tmi','tutuba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6497,0,NULL,'tmj','samarokena','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6498,0,NULL,'tmk','northwestern tamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6499,0,NULL,'tml','tamnim citak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6500,0,NULL,'tmm','tai thanh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6501,0,NULL,'tmn','taman (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6502,0,NULL,'tmo','temoq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6503,0,NULL,'tmp','tai mène','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6504,0,NULL,'tmq','tumleo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6505,0,NULL,'tmr','jewish babylonian aramaic (ca. 200-1200 ce)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6506,0,NULL,'tms','tima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6507,0,NULL,'tmt','tasmate','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6508,0,NULL,'tmu','iau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6509,0,NULL,'tmv','tembo (motembo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6510,0,NULL,'tmw','temuan','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(6511,0,NULL,'tmy','tami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6512,0,NULL,'tmz','tamanaku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6513,0,NULL,'tna','tacana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6514,0,NULL,'tnb','western tunebo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6515,0,NULL,'tnc','tanimuca-retuarã','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6516,0,NULL,'tnd','angosturas tunebo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6517,0,NULL,'tne','tinoc kallahan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6518,0,NULL,'tnf','tangshewi','1248825600',1268265600,'prs',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6519,0,NULL,'tng','tobanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6520,0,NULL,'tnh','maiani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6521,0,NULL,'tni','tandia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6522,0,NULL,'tnk','kwamera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6523,0,NULL,'tnl','lenakel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6524,0,NULL,'tnm','tabla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6525,0,NULL,'tnn','north tanna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6526,0,NULL,'tno','toromono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6527,0,NULL,'tnp','whitesands','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6528,0,NULL,'tnq','taino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6529,0,NULL,'tnr','bedik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6530,0,NULL,'tns','tenis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6531,0,NULL,'tnt','tontemboan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6532,0,NULL,'tnu','tay khang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6533,0,NULL,'tnv','tangchangya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6534,0,NULL,'tnw','tonsawang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6535,0,NULL,'tnx','tanema','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6536,0,NULL,'tny','tongwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6537,0,NULL,'tnz','tonga (thailand)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6538,0,NULL,'tob','toba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6539,0,NULL,'toc','coyutla totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6540,0,NULL,'tod','toma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6541,0,NULL,'toe','tomedes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6542,0,NULL,'tof','gizrra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6543,0,NULL,'tog','tonga (nyasa)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6544,0,NULL,'toh','gitonga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6545,0,NULL,'toi','tonga (zambia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6546,0,NULL,'toj','tojolabal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6547,0,NULL,'tol','tolowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6548,0,NULL,'tom','tombulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6549,0,NULL,'too','xicotepec de juárez totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6550,0,NULL,'top','papantla totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6551,0,NULL,'toq','toposa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6552,0,NULL,'tor','togbo-vara banda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6553,0,NULL,'tos','highland totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6554,0,NULL,'tou','tho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6555,0,NULL,'tov','upper taromi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6556,0,NULL,'tow','jemez','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6557,0,NULL,'tox','tobian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6558,0,NULL,'toy','topoiyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6559,0,NULL,'toz','to','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6560,0,NULL,'tpa','taupota','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6561,0,NULL,'tpc','azoyú me''phaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6561,0,NULL,'tpc','azoyú tlapanec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6562,0,NULL,'tpe','tippera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6563,0,NULL,'tpf','tarpia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6564,0,NULL,'tpg','kula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6565,0,NULL,'tpi','tok pisin','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6566,0,NULL,'tpj','tapieté','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6567,0,NULL,'tpk','tupinikin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6568,0,NULL,'tpl','tlacoapa me''phaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6568,0,NULL,'tpl','tlacoapa tlapanec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6569,0,NULL,'tpm','tampulma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6570,0,NULL,'tpn','tupinambá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6571,0,NULL,'tpo','tai pao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6572,0,NULL,'tpp','pisaflores tepehua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6573,0,NULL,'tpq','tukpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6574,0,NULL,'tpr','tuparí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6575,0,NULL,'tpt','tlachichilco tepehua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6576,0,NULL,'tpu','tampuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6577,0,NULL,'tpv','tanapag','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6578,0,NULL,'tpw','tupí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6579,0,NULL,'tpx','acatepec me''phaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6579,0,NULL,'tpx','acatepec tlapanec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6580,0,NULL,'tpy','trumai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6581,0,NULL,'tpz','tinputz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6582,0,NULL,'tqb','tembé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6583,0,NULL,'tql','lehali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6584,0,NULL,'tqm','turumsa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6585,0,NULL,'tqn','tenino','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6586,0,NULL,'tqo','toaripi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6587,0,NULL,'tqp','tomoip','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6588,0,NULL,'tqq','tunni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6589,0,NULL,'tqr','torona','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6590,0,NULL,'tqt','western totonac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6591,0,NULL,'tqu','touo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6592,0,NULL,'tqw','tonkawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6593,0,NULL,'tra','tirahi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6594,0,NULL,'trb','terebu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6595,0,NULL,'trc','copala triqui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6596,0,NULL,'trd','turi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6597,0,NULL,'tre','east tarangan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6598,0,NULL,'trf','trinidadian creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6599,0,NULL,'trg','lishán didán','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6600,0,NULL,'trh','turaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6601,0,NULL,'tri','trió','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6602,0,NULL,'trj','toram','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6603,0,NULL,'trk','turkic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6604,0,NULL,'trl','traveller scottish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6605,0,NULL,'trm','tregami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6606,0,NULL,'trn','trinitario','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6607,0,NULL,'tro','tarao naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6608,0,NULL,'trp','kok borok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6609,0,NULL,'trq','san martín itunyoso triqui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6610,0,NULL,'trr','taushiro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6611,0,NULL,'trs','chicahuaxtla triqui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6612,0,NULL,'trt','tunggare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6613,0,NULL,'tru','turoyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6614,0,NULL,'trv','taroko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6615,0,NULL,'trw','torwali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6616,0,NULL,'trx','tringgus-sembaan bidayuh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6617,0,NULL,'try','turung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6618,0,NULL,'trz','torá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6619,0,NULL,'tsa','tsaangi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6620,0,NULL,'tsb','tsamai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6621,0,NULL,'tsc','tswa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6622,0,NULL,'tsd','tsakonian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6623,0,NULL,'tse','tunisian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6624,0,NULL,'tsf','southwestern tamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6625,0,NULL,'tsg','tausug','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6626,0,NULL,'tsh','tsuvan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6627,0,NULL,'tsi','tsimshian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6628,0,NULL,'tsj','tshangla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6629,0,NULL,'tsk','tseku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6630,0,NULL,'tsl','ts''ün-lao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6631,0,NULL,'tsm','turkish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6631,0,NULL,'tsm','türk İşaret dili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6632,0,NULL,'tsp','northern toussian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6633,0,NULL,'tsq','thai sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6634,0,NULL,'tsr','akei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6635,0,NULL,'tss','taiwan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6636,0,NULL,'tsu','tsou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6637,0,NULL,'tsv','tsogo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6638,0,NULL,'tsw','tsishingini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6639,0,NULL,'tsx','mubami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6640,0,NULL,'tsy','tebul sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6641,0,NULL,'tsz','purepecha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6642,0,NULL,'tta','tutelo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6643,0,NULL,'ttb','gaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6644,0,NULL,'ttc','tektiteko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6645,0,NULL,'ttd','tauade','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6646,0,NULL,'tte','bwanabwana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6647,0,NULL,'ttf','tuotomb','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6648,0,NULL,'ttg','tutong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6649,0,NULL,'tth','upper ta''oih','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6650,0,NULL,'tti','tobati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6651,0,NULL,'ttj','tooro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6652,0,NULL,'ttk','totoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6653,0,NULL,'ttl','totela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6654,0,NULL,'ttm','northern tutchone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6655,0,NULL,'ttn','towei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6656,0,NULL,'tto','lower ta''oih','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6657,0,NULL,'ttp','tombelala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6658,0,NULL,'ttq','tawallammat tamajaq','1248825600',NULL,NULL,NULL,NULL,'tmh',NULL,NULL); +INSERT INTO "iana_records" VALUES(6659,0,NULL,'ttr','tera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6660,0,NULL,'tts','northeastern thai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6661,0,NULL,'ttt','muslim tat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6662,0,NULL,'ttu','torau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6663,0,NULL,'ttv','titan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6664,0,NULL,'ttw','long wat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6665,0,NULL,'tty','sikaritai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6666,0,NULL,'ttz','tsum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6667,0,NULL,'tua','wiarumus','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6668,0,NULL,'tub','tübatulabal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6669,0,NULL,'tuc','mutu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6670,0,NULL,'tud','tuxá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6671,0,NULL,'tue','tuyuca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6672,0,NULL,'tuf','central tunebo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6673,0,NULL,'tug','tunia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6674,0,NULL,'tuh','taulil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6675,0,NULL,'tui','tupuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6676,0,NULL,'tuj','tugutil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6677,0,NULL,'tul','tula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6678,0,NULL,'tum','tumbuka','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6679,0,NULL,'tun','tunica','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6680,0,NULL,'tuo','tucano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6681,0,NULL,'tup','tupi languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6682,0,NULL,'tuq','tedaga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6683,0,NULL,'tus','tuscarora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6684,0,NULL,'tut','altaic languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6685,0,NULL,'tuu','tututni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6686,0,NULL,'tuv','turkana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6687,0,NULL,'tuw','tungus languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6688,0,NULL,'tux','tuxináwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6689,0,NULL,'tuy','tugen','1248825600',NULL,NULL,NULL,NULL,'kln',NULL,NULL); +INSERT INTO "iana_records" VALUES(6690,0,NULL,'tuz','turka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6691,0,NULL,'tva','vaghua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6692,0,NULL,'tvd','tsuvadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6693,0,NULL,'tve','te''un','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6694,0,NULL,'tvk','southeast ambrym','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6695,0,NULL,'tvl','tuvalu','1129420800',NULL,NULL,NULL,'latn',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6696,0,NULL,'tvm','tela-masbuar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6697,0,NULL,'tvn','tavoyan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6698,0,NULL,'tvo','tidore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6699,0,NULL,'tvs','taveta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6700,0,NULL,'tvt','tutsa naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6701,0,NULL,'tvw','sedoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6702,0,NULL,'tvy','timor pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6703,0,NULL,'twa','twana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6704,0,NULL,'twb','western tawbuid','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6705,0,NULL,'twc','teshenawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6706,0,NULL,'twd','twents','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6707,0,NULL,'twe','tewa (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6708,0,NULL,'twf','northern tiwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6709,0,NULL,'twg','tereweng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6710,0,NULL,'twh','tai dón','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6711,0,NULL,'twl','tawara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6712,0,NULL,'twm','tawang monpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6713,0,NULL,'twn','twendi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6714,0,NULL,'two','tswapong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6715,0,NULL,'twp','ere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6716,0,NULL,'twq','tasawaq','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6717,0,NULL,'twr','southwestern tarahumara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6718,0,NULL,'twt','turiwára','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6719,0,NULL,'twu','termanu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6720,0,NULL,'tww','tuwari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6721,0,NULL,'twx','tewe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6722,0,NULL,'twy','tawoyan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6723,0,NULL,'txa','tombonuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6724,0,NULL,'txb','tokharian b','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6725,0,NULL,'txc','tsetsaut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6726,0,NULL,'txe','totoli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6727,0,NULL,'txg','tangut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6728,0,NULL,'txh','thracian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6729,0,NULL,'txi','ikpeng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6730,0,NULL,'txm','tomini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6731,0,NULL,'txn','west tarangan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6732,0,NULL,'txo','toto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6733,0,NULL,'txq','tii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6734,0,NULL,'txr','tartessian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6735,0,NULL,'txs','tonsea','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6736,0,NULL,'txt','citak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6737,0,NULL,'txu','kayapó','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6738,0,NULL,'txx','tatana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6739,0,NULL,'txy','tanosy malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(6740,0,NULL,'tya','tauya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6741,0,NULL,'tye','kyenga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6742,0,NULL,'tyh','o''du','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6743,0,NULL,'tyi','teke-tsaayi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6744,0,NULL,'tyj','tai do','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6745,0,NULL,'tyl','thu lao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6746,0,NULL,'tyn','kombai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6747,0,NULL,'typ','thaypan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6748,0,NULL,'tyr','tai daeng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6749,0,NULL,'tys','tày sa pa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6750,0,NULL,'tyt','tày tac','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6751,0,NULL,'tyu','kua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6752,0,NULL,'tyv','tuvinian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6753,0,NULL,'tyx','teke-tyee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6754,0,NULL,'tyz','tày','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6755,0,NULL,'tza','tanzanian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6756,0,NULL,'tzh','tzeltal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6757,0,NULL,'tzj','tz''utujil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6758,0,NULL,'tzm','central atlas tamazight','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6759,0,NULL,'tzn','tugun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6760,0,NULL,'tzo','tzotzil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6761,0,NULL,'tzx','tabriak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6762,0,NULL,'uam','uamué','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6763,0,NULL,'uan','kuan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6764,0,NULL,'uar','tairuma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6765,0,NULL,'uba','ubang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6766,0,NULL,'ubi','ubi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6767,0,NULL,'ubl','buhi''non bikol','1268265600',NULL,NULL,NULL,NULL,'bik',NULL,NULL); +INSERT INTO "iana_records" VALUES(6768,0,NULL,'ubr','ubir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6769,0,NULL,'ubu','umbu-ungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6770,0,NULL,'uby','ubykh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6771,0,NULL,'uda','uda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6772,0,NULL,'ude','udihe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6773,0,NULL,'udg','muduga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6774,0,NULL,'udi','udi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6775,0,NULL,'udj','ujir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6776,0,NULL,'udl','wuzlam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6777,0,NULL,'udm','udmurt','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6778,0,NULL,'udu','uduk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6779,0,NULL,'ues','kioko','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6780,0,NULL,'ufi','ufim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6781,0,NULL,'uga','ugaritic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6782,0,NULL,'ugb','kuku-ugbanh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6783,0,NULL,'uge','ughele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6784,0,NULL,'ugn','ugandan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6785,0,NULL,'ugo','ugong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6786,0,NULL,'ugy','uruguayan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6787,0,NULL,'uha','uhami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6788,0,NULL,'uhn','damal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6789,0,NULL,'uis','uisai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6790,0,NULL,'uiv','iyive','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6791,0,NULL,'uji','tanjijili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6792,0,NULL,'uka','kaburi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6793,0,NULL,'ukg','ukuriguma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6794,0,NULL,'ukh','ukhwejo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6795,0,NULL,'ukl','ukrainian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6796,0,NULL,'ukp','ukpe-bayobiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6797,0,NULL,'ukq','ukwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6798,0,NULL,'uks','kaapor sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6798,0,NULL,'uks','urubú-kaapor sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6799,0,NULL,'uku','ukue','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6800,0,NULL,'ukw','ukwuani-aboh-ndoni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6801,0,NULL,'ula','fungwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6802,0,NULL,'ulb','ulukwumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6803,0,NULL,'ulc','ulch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6804,0,NULL,'ulf','afra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6804,0,NULL,'ulf','usku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6805,0,NULL,'uli','ulithian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6806,0,NULL,'ulk','meriam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6807,0,NULL,'ull','ullatan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6808,0,NULL,'ulm','ulumanda''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6809,0,NULL,'uln','unserdeutsch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6810,0,NULL,'ulu','uma'' lung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6811,0,NULL,'ulw','ulwa','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6812,0,NULL,'uma','umatilla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6813,0,NULL,'umb','umbundu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6814,0,NULL,'umc','marrucinian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6815,0,NULL,'umd','umbindhamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6816,0,NULL,'umg','umbuygamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6817,0,NULL,'umi','ukit','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6818,0,NULL,'umm','umon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6819,0,NULL,'umn','makyan naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6820,0,NULL,'umo','umotína','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6821,0,NULL,'ump','umpila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6822,0,NULL,'umr','umbugarla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6823,0,NULL,'ums','pendau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6824,0,NULL,'umu','munsee','1248825600',NULL,NULL,NULL,NULL,'del',NULL,NULL); +INSERT INTO "iana_records" VALUES(6825,0,NULL,'una','north watut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6826,0,NULL,'und','undetermined','1129420800',NULL,NULL,NULL,NULL,NULL,'special',NULL); +INSERT INTO "iana_records" VALUES(6827,0,NULL,'une','uneme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6828,0,NULL,'ung','ngarinyin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6829,0,NULL,'unk','enawené-nawé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6830,0,NULL,'unm','unami','1248825600',NULL,NULL,NULL,NULL,'del',NULL,NULL); +INSERT INTO "iana_records" VALUES(6831,0,NULL,'unp','worora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6832,0,NULL,'unr','mundari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6833,0,NULL,'unx','munda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6834,0,NULL,'unz','unde kaili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6835,0,NULL,'uok','uokha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6836,0,NULL,'upi','umeda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6837,0,NULL,'upv','uripiv-wala-rano-atchin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6838,0,NULL,'ura','urarina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6839,0,NULL,'urb','kaapor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6839,0,NULL,'urb','urubú-kaapor','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6840,0,NULL,'urc','urningangg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6841,0,NULL,'ure','uru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6842,0,NULL,'urf','uradhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6843,0,NULL,'urg','urigina','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6844,0,NULL,'urh','urhobo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6845,0,NULL,'uri','urim','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6846,0,NULL,'urj','uralic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6847,0,NULL,'urk','urak lawoi''','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(6848,0,NULL,'url','urali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6849,0,NULL,'urm','urapmin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6850,0,NULL,'urn','uruangnirin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6851,0,NULL,'uro','ura (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6852,0,NULL,'urp','uru-pa-in','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6853,0,NULL,'urr','lehalurup','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6853,0,NULL,'urr','löyöp','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6854,0,NULL,'urt','urat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6855,0,NULL,'uru','urumi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6856,0,NULL,'urv','uruava','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6857,0,NULL,'urw','sop','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6858,0,NULL,'urx','urimo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6859,0,NULL,'ury','orya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6860,0,NULL,'urz','uru-eu-wau-wau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6861,0,NULL,'usa','usarufa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6862,0,NULL,'ush','ushojo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6863,0,NULL,'usi','usui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6864,0,NULL,'usk','usaghade','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6865,0,NULL,'usp','uspanteco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6866,0,NULL,'usu','uya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6867,0,NULL,'uta','otank','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6868,0,NULL,'ute','ute-southern paiute','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6869,0,NULL,'utp','amba (solomon islands)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6870,0,NULL,'utr','etulo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6871,0,NULL,'utu','utu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6872,0,NULL,'uum','urum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6873,0,NULL,'uun','kulon-pazeh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6874,0,NULL,'uur','ura (vanuatu)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6875,0,NULL,'uuu','u','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6876,0,NULL,'uve','west uvean','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6877,0,NULL,'uvh','uri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6878,0,NULL,'uvl','lote','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6879,0,NULL,'uwa','kuku-uwanh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6880,0,NULL,'uya','doko-uyanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6881,0,NULL,'uzn','northern uzbek','1248825600',NULL,NULL,NULL,NULL,'uz',NULL,NULL); +INSERT INTO "iana_records" VALUES(6882,0,NULL,'uzs','southern uzbek','1248825600',NULL,NULL,NULL,NULL,'uz',NULL,NULL); +INSERT INTO "iana_records" VALUES(6883,0,NULL,'vaa','vaagri booli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6884,0,NULL,'vae','vale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6885,0,NULL,'vaf','vafsi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6886,0,NULL,'vag','vagla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6887,0,NULL,'vah','varhadi-nagpuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6888,0,NULL,'vai','vai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6889,0,NULL,'vaj','vasekela bushman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6890,0,NULL,'val','vehes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6891,0,NULL,'vam','vanimo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6892,0,NULL,'van','valman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6893,0,NULL,'vao','vao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6894,0,NULL,'vap','vaiphei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6895,0,NULL,'var','huarijio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6896,0,NULL,'vas','vasavi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6897,0,NULL,'vau','vanuma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6898,0,NULL,'vav','varli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6899,0,NULL,'vay','wayu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6900,0,NULL,'vbb','southeast babar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6901,0,NULL,'vbk','southwestern bontok','1268265600',NULL,NULL,NULL,NULL,'bnc',NULL,NULL); +INSERT INTO "iana_records" VALUES(6902,0,NULL,'vec','venetian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6903,0,NULL,'ved','veddah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6904,0,NULL,'vel','veluws','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6905,0,NULL,'vem','vemgo-mabas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6906,0,NULL,'veo','ventureño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6907,0,NULL,'vep','veps','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6908,0,NULL,'ver','mom jango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6909,0,NULL,'vgr','vaghri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6910,0,NULL,'vgt','flemish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6910,0,NULL,'vgt','vlaamse gebarentaal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6911,0,NULL,'vic','virgin islands creole english','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6912,0,NULL,'vid','vidunda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6913,0,NULL,'vif','vili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6914,0,NULL,'vig','viemo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6915,0,NULL,'vil','vilela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6916,0,NULL,'vin','vinza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6917,0,NULL,'vis','vishavan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6918,0,NULL,'vit','viti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6919,0,NULL,'viv','iduna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6920,0,NULL,'vka','kariyarra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6921,0,NULL,'vki','ija-zuba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6922,0,NULL,'vkj','kujarge','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6923,0,NULL,'vkk','kaur','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(6924,0,NULL,'vkl','kulisusu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6925,0,NULL,'vkm','kamakan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6926,0,NULL,'vko','kodeoha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6927,0,NULL,'vkp','korlai creole portuguese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6928,0,NULL,'vkt','tenggarong kutai malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(6929,0,NULL,'vku','kurrama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6930,0,NULL,'vlp','valpei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6931,0,NULL,'vls','vlaams','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6932,0,NULL,'vma','martuyhunira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6933,0,NULL,'vmb','mbabaram','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6934,0,NULL,'vmc','juxtlahuaca mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6935,0,NULL,'vmd','mudu koraga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6936,0,NULL,'vme','east masela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6937,0,NULL,'vmf','mainfränkisch','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6938,0,NULL,'vmg','minigir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6939,0,NULL,'vmh','maraghei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6940,0,NULL,'vmi','miwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6941,0,NULL,'vmj','ixtayutla mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6942,0,NULL,'vmk','makhuwa-shirima','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6943,0,NULL,'vml','malgana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6944,0,NULL,'vmm','mitlatongo mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6945,0,NULL,'vmp','soyaltepec mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6946,0,NULL,'vmq','soyaltepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6947,0,NULL,'vmr','marenje','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6948,0,NULL,'vms','moksela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6949,0,NULL,'vmu','muluridyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6950,0,NULL,'vmv','valley maidu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6951,0,NULL,'vmw','makhuwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6952,0,NULL,'vmx','tamazola mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6953,0,NULL,'vmy','ayautla mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6954,0,NULL,'vmz','mazatlán mazatec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6955,0,NULL,'vnk','lovono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6955,0,NULL,'vnk','vano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6956,0,NULL,'vnm','neve''ei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6956,0,NULL,'vnm','vinmavis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6957,0,NULL,'vnp','vunapu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6958,0,NULL,'vor','voro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6959,0,NULL,'vot','votic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6960,0,NULL,'vra','vera''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6961,0,NULL,'vro','võro','1248825600',NULL,NULL,NULL,NULL,'et',NULL,NULL); +INSERT INTO "iana_records" VALUES(6962,0,NULL,'vrs','varisi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6963,0,NULL,'vrt','banam bay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6963,0,NULL,'vrt','burmbar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6964,0,NULL,'vsi','moldova sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6965,0,NULL,'vsl','venezuelan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6966,0,NULL,'vsv','llengua de signes valenciana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6966,0,NULL,'vsv','valencian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6967,0,NULL,'vto','vitou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6968,0,NULL,'vum','vumbu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6969,0,NULL,'vun','vunjo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6970,0,NULL,'vut','vute','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6971,0,NULL,'vwa','awa (china)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6972,0,NULL,'waa','walla walla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6973,0,NULL,'wab','wab','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6974,0,NULL,'wac','wasco-wishram','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6975,0,NULL,'wad','wandamen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6976,0,NULL,'wae','walser','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6977,0,NULL,'waf','wakoná','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6978,0,NULL,'wag','wa''ema','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6979,0,NULL,'wah','watubela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6980,0,NULL,'wai','wares','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6981,0,NULL,'waj','waffa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6982,0,NULL,'wak','wakashan languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(6983,0,NULL,'wal','wolaitta','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6983,0,NULL,'wal','wolaytta','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6984,0,NULL,'wam','wampanoag','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6985,0,NULL,'wan','wan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6986,0,NULL,'wao','wappo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6987,0,NULL,'wap','wapishana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6988,0,NULL,'waq','wageman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6989,0,NULL,'war','waray (philippines)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6990,0,NULL,'was','washo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6991,0,NULL,'wat','kaninuwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6992,0,NULL,'wau','waurá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6993,0,NULL,'wav','waka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6994,0,NULL,'waw','waiwai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6995,0,NULL,'wax','watam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6996,0,NULL,'way','wayana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6997,0,NULL,'waz','wampur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6998,0,NULL,'wba','warao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(6999,0,NULL,'wbb','wabo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7000,0,NULL,'wbe','waritai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7001,0,NULL,'wbf','wara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7002,0,NULL,'wbh','wanda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7003,0,NULL,'wbi','vwanji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7004,0,NULL,'wbj','alagwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7005,0,NULL,'wbk','waigali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7006,0,NULL,'wbl','wakhi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7007,0,NULL,'wbm','wa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7008,0,NULL,'wbp','warlpiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7009,0,NULL,'wbq','waddar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7010,0,NULL,'wbr','wagdi','1248825600',NULL,NULL,NULL,NULL,'raj',NULL,NULL); +INSERT INTO "iana_records" VALUES(7011,0,NULL,'wbt','wanman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7012,0,NULL,'wbv','wajarri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7013,0,NULL,'wbw','woi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7014,0,NULL,'wca','yanomámi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7015,0,NULL,'wci','waci gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7016,0,NULL,'wdd','wandji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7017,0,NULL,'wdg','wadaginam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7018,0,NULL,'wdj','wadjiginy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7019,0,NULL,'wdu','wadjigu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7020,0,NULL,'wea','wewaw','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7021,0,NULL,'wec','wè western','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7022,0,NULL,'wed','wedau','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7023,0,NULL,'weh','weh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7024,0,NULL,'wei','were','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7025,0,NULL,'wem','weme gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7026,0,NULL,'wen','sorbian languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7027,0,NULL,'weo','north wemale','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7028,0,NULL,'wep','westphalien','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7029,0,NULL,'wer','weri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7030,0,NULL,'wes','cameroon pidgin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7031,0,NULL,'wet','perai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7032,0,NULL,'weu','welaung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7033,0,NULL,'wew','wejewa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7034,0,NULL,'wfg','yafi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7034,0,NULL,'wfg','zorop','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7035,0,NULL,'wga','wagaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7036,0,NULL,'wgb','wagawaga','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7037,0,NULL,'wgg','wangganguru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7038,0,NULL,'wgi','wahgi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7039,0,NULL,'wgo','waigeo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7040,0,NULL,'wgw','wagawaga','1248825600',1268265600,NULL,NULL,NULL,NULL,NULL,'see wgb, ylb'); +INSERT INTO "iana_records" VALUES(7041,0,NULL,'wgy','warrgamay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7042,0,NULL,'wha','manusela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7043,0,NULL,'whg','north wahgi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7044,0,NULL,'whk','wahau kenyah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7045,0,NULL,'whu','wahau kayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7046,0,NULL,'wib','southern toussian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7047,0,NULL,'wic','wichita','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7048,0,NULL,'wie','wik-epa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7049,0,NULL,'wif','wik-keyangan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7050,0,NULL,'wig','wik-ngathana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7051,0,NULL,'wih','wik-me''anha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7052,0,NULL,'wii','minidien','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7053,0,NULL,'wij','wik-iiyanh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7054,0,NULL,'wik','wikalkan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7055,0,NULL,'wil','wilawila','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7056,0,NULL,'wim','wik-mungkan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7057,0,NULL,'win','ho-chunk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7058,0,NULL,'wir','wiraféd','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7059,0,NULL,'wit','wintu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7060,0,NULL,'wiu','wiru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7061,0,NULL,'wiv','muduapa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7062,0,NULL,'wiw','wirangu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7063,0,NULL,'wiy','wiyot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7064,0,NULL,'wja','waja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7065,0,NULL,'wji','warji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7066,0,NULL,'wka','kw''adza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7067,0,NULL,'wkb','kumbaran','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7068,0,NULL,'wkd','mo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7068,0,NULL,'wkd','wakde','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7069,0,NULL,'wkl','kalanadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7070,0,NULL,'wku','kunduvadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7071,0,NULL,'wkw','wakawaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7072,0,NULL,'wla','walio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7073,0,NULL,'wlc','mwali comorian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7074,0,NULL,'wle','wolane','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7075,0,NULL,'wlg','kunbarlang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7076,0,NULL,'wli','waioli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7077,0,NULL,'wlk','wailaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7078,0,NULL,'wll','wali (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7079,0,NULL,'wlm','middle welsh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7080,0,NULL,'wlo','wolio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7081,0,NULL,'wlr','wailapa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7082,0,NULL,'wls','wallisian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7083,0,NULL,'wlu','wuliwuli','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7084,0,NULL,'wlv','wichí lhamtés vejoz','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7085,0,NULL,'wlw','walak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7086,0,NULL,'wlx','wali (ghana)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7087,0,NULL,'wly','waling','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7088,0,NULL,'wma','mawa (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7089,0,NULL,'wmb','wambaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7090,0,NULL,'wmc','wamas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7091,0,NULL,'wmd','mamaindé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7092,0,NULL,'wme','wambule','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7093,0,NULL,'wmh','waima''a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7094,0,NULL,'wmi','wamin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7095,0,NULL,'wmm','maiwa (indonesia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7096,0,NULL,'wmn','waamwang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7097,0,NULL,'wmo','wom (papua new guinea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7098,0,NULL,'wms','wambon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7099,0,NULL,'wmt','walmajarri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7100,0,NULL,'wmw','mwani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7101,0,NULL,'wmx','womo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7102,0,NULL,'wnb','wanambre','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7103,0,NULL,'wnc','wantoat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7104,0,NULL,'wnd','wandarang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7105,0,NULL,'wne','waneci','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7106,0,NULL,'wng','wanggom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7107,0,NULL,'wni','ndzwani comorian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7108,0,NULL,'wnk','wanukaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7109,0,NULL,'wnm','wanggamala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7110,0,NULL,'wno','wano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7111,0,NULL,'wnp','wanap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7112,0,NULL,'wnu','usan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7113,0,NULL,'woa','tyaraity','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7114,0,NULL,'wob','wè northern','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7115,0,NULL,'woc','wogeo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7116,0,NULL,'wod','wolani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7117,0,NULL,'woe','woleaian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7118,0,NULL,'wof','gambian wolof','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7119,0,NULL,'wog','wogamusin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7120,0,NULL,'woi','kamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7121,0,NULL,'wok','longto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7122,0,NULL,'wom','wom (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7123,0,NULL,'won','wongo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7124,0,NULL,'woo','manombai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7125,0,NULL,'wor','woria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7126,0,NULL,'wos','hanga hundi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7127,0,NULL,'wow','wawonii','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7128,0,NULL,'woy','weyto','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7129,0,NULL,'wpc','maco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7130,0,NULL,'wra','warapu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7131,0,NULL,'wrb','warluwara','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7132,0,NULL,'wrd','warduji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7133,0,NULL,'wrg','warungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7134,0,NULL,'wrh','wiradhuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7135,0,NULL,'wri','wariyangga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7136,0,NULL,'wrl','warlmanpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7137,0,NULL,'wrm','warumungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7138,0,NULL,'wrn','warnang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7139,0,NULL,'wrp','waropen','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7140,0,NULL,'wrr','wardaman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7141,0,NULL,'wrs','waris','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7142,0,NULL,'wru','waru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7143,0,NULL,'wrv','waruna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7144,0,NULL,'wrw','gugu warra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7145,0,NULL,'wrx','wae rana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7146,0,NULL,'wry','merwari','1248825600',NULL,NULL,NULL,NULL,'mwr',NULL,NULL); +INSERT INTO "iana_records" VALUES(7147,0,NULL,'wrz','waray (australia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7148,0,NULL,'wsa','warembori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7149,0,NULL,'wsi','wusi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7150,0,NULL,'wsk','waskia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7151,0,NULL,'wsr','owenia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7152,0,NULL,'wss','wasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7153,0,NULL,'wsu','wasu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7154,0,NULL,'wsv','wotapuri-katarqalai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7155,0,NULL,'wtf','dumpu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7156,0,NULL,'wti','berta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7157,0,NULL,'wtk','watakataui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7158,0,NULL,'wtm','mewati','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7159,0,NULL,'wtw','wotu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7160,0,NULL,'wua','wikngenchera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7161,0,NULL,'wub','wunambal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7162,0,NULL,'wud','wudu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7163,0,NULL,'wuh','wutunhua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7164,0,NULL,'wul','silimo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7165,0,NULL,'wum','wumbvu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7166,0,NULL,'wun','bungu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7167,0,NULL,'wur','wurrugu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7168,0,NULL,'wut','wutung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7169,0,NULL,'wuu','wu chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7170,0,NULL,'wuv','wuvulu-aua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7171,0,NULL,'wux','wulna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7172,0,NULL,'wuy','wauyai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7173,0,NULL,'wwa','waama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7174,0,NULL,'wwo','dorig','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7174,0,NULL,'wwo','wetamut','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7175,0,NULL,'wwr','warrwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7176,0,NULL,'www','wawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7177,0,NULL,'wxa','waxianghua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7178,0,NULL,'wya','wyandot','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7179,0,NULL,'wyb','wangaaybuwan-ngiyambaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7180,0,NULL,'wym','wymysorys','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7181,0,NULL,'wyr','wayoró','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7182,0,NULL,'wyy','western fijian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7183,0,NULL,'xaa','andalusian arabic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7184,0,NULL,'xab','sambe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7185,0,NULL,'xac','kachari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7186,0,NULL,'xad','adai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7187,0,NULL,'xae','aequian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7188,0,NULL,'xag','aghwan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7189,0,NULL,'xai','kaimbé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7190,0,NULL,'xal','kalmyk','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7190,0,NULL,'xal','oirat','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7191,0,NULL,'xam','/xam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7192,0,NULL,'xan','xamtanga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7193,0,NULL,'xao','khao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7194,0,NULL,'xap','apalachee','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7195,0,NULL,'xaq','aquitanian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7196,0,NULL,'xar','karami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7197,0,NULL,'xas','kamas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7198,0,NULL,'xat','katawixi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7199,0,NULL,'xau','kauwera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7200,0,NULL,'xav','xavánte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7201,0,NULL,'xaw','kawaiisu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7202,0,NULL,'xay','kayan mahakam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7203,0,NULL,'xba','kamba (brazil)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7204,0,NULL,'xbb','lower burdekin','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7205,0,NULL,'xbc','bactrian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7206,0,NULL,'xbi','kombio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7207,0,NULL,'xbm','middle breton','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7208,0,NULL,'xbn','kenaboi','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7209,0,NULL,'xbo','bolgarian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7210,0,NULL,'xbr','kambera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7211,0,NULL,'xbw','kambiwá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7212,0,NULL,'xbx','kabixí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7213,0,NULL,'xcb','cumbric','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7214,0,NULL,'xcc','camunic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7215,0,NULL,'xce','celtiberian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7216,0,NULL,'xcg','cisalpine gaulish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7217,0,NULL,'xch','chemakum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7217,0,NULL,'xch','chimakum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7218,0,NULL,'xcl','classical armenian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7219,0,NULL,'xcm','comecrudo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7220,0,NULL,'xcn','cotoname','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7221,0,NULL,'xco','chorasmian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7222,0,NULL,'xcr','carian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7223,0,NULL,'xct','classical tibetan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7224,0,NULL,'xcu','curonian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7225,0,NULL,'xcv','chuvantsy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7226,0,NULL,'xcw','coahuilteco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7227,0,NULL,'xcy','cayuse','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7228,0,NULL,'xdc','dacian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7229,0,NULL,'xdm','edomite','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7230,0,NULL,'xdy','malayic dayak','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7231,0,NULL,'xeb','eblan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7232,0,NULL,'xed','hdi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7233,0,NULL,'xeg','//xegwi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7234,0,NULL,'xel','kelo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7235,0,NULL,'xem','kembayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7236,0,NULL,'xep','epi-olmec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7237,0,NULL,'xer','xerénte','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7238,0,NULL,'xes','kesawai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7239,0,NULL,'xet','xetá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7240,0,NULL,'xeu','keoru-ahia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7241,0,NULL,'xfa','faliscan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7242,0,NULL,'xga','galatian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7243,0,NULL,'xgf','gabrielino-fernandeño','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7244,0,NULL,'xgl','galindan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7245,0,NULL,'xgn','mongolian languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7246,0,NULL,'xgr','garza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7247,0,NULL,'xha','harami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7248,0,NULL,'xhc','hunnic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7249,0,NULL,'xhd','hadrami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7250,0,NULL,'xhe','khetrani','1248825600',NULL,NULL,NULL,NULL,'lah',NULL,NULL); +INSERT INTO "iana_records" VALUES(7251,0,NULL,'xhr','hernican','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7252,0,NULL,'xht','hattic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7253,0,NULL,'xhu','hurrian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7254,0,NULL,'xhv','khua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7255,0,NULL,'xia','xiandao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7256,0,NULL,'xib','iberian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7257,0,NULL,'xii','xiri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7258,0,NULL,'xil','illyrian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7259,0,NULL,'xin','xinca','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7260,0,NULL,'xip','xipináwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7261,0,NULL,'xir','xiriâna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7262,0,NULL,'xiv','indus valley language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7263,0,NULL,'xiy','xipaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7264,0,NULL,'xka','kalkoti','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7265,0,NULL,'xkb','northern nago','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7266,0,NULL,'xkc','kho''ini','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7267,0,NULL,'xkd','mendalam kayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7268,0,NULL,'xke','kereho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7269,0,NULL,'xkf','khengkha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7270,0,NULL,'xkg','kagoro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7271,0,NULL,'xkh','karahawyana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7272,0,NULL,'xki','kenyan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7273,0,NULL,'xkj','kajali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7274,0,NULL,'xkk','kaco''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7275,0,NULL,'xkl','mainstream kenyah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7276,0,NULL,'xkn','kayan river kayan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7277,0,NULL,'xko','kiorr','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7278,0,NULL,'xkp','kabatei','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7279,0,NULL,'xkq','koroni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7280,0,NULL,'xkr','xakriabá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7281,0,NULL,'xks','kumbewaha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7282,0,NULL,'xkt','kantosi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7283,0,NULL,'xku','kaamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7284,0,NULL,'xkv','kgalagadi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7285,0,NULL,'xkw','kembra','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7286,0,NULL,'xkx','karore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7287,0,NULL,'xky','uma'' lasan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7288,0,NULL,'xkz','kurtokha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7289,0,NULL,'xla','kamula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7290,0,NULL,'xlb','loup b','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7291,0,NULL,'xlc','lycian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7292,0,NULL,'xld','lydian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7293,0,NULL,'xle','lemnian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7294,0,NULL,'xlg','ligurian (ancient)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7295,0,NULL,'xli','liburnian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7296,0,NULL,'xln','alanic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7297,0,NULL,'xlo','loup a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7298,0,NULL,'xlp','lepontic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7299,0,NULL,'xls','lusitanian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7300,0,NULL,'xlu','cuneiform luwian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7301,0,NULL,'xly','elymian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7302,0,NULL,'xma','mushungulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7303,0,NULL,'xmb','mbonga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7304,0,NULL,'xmc','makhuwa-marrevone','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7305,0,NULL,'xmd','mbedam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7306,0,NULL,'xme','median','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7307,0,NULL,'xmf','mingrelian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7308,0,NULL,'xmg','mengaka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7309,0,NULL,'xmh','kuku-muminh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7310,0,NULL,'xmj','majera','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7311,0,NULL,'xmk','ancient macedonian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7312,0,NULL,'xml','malaysian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7313,0,NULL,'xmm','manado malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7314,0,NULL,'xmn','manichaean middle persian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7315,0,NULL,'xmo','morerebi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7316,0,NULL,'xmp','kuku-mu''inh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7317,0,NULL,'xmq','kuku-mangk','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7318,0,NULL,'xmr','meroitic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7319,0,NULL,'xms','moroccan sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7320,0,NULL,'xmt','matbat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7321,0,NULL,'xmu','kamu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7322,0,NULL,'xmv','antankarana malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(7323,0,NULL,'xmw','tsimihety malagasy','1248825600',NULL,NULL,NULL,NULL,'mg',NULL,NULL); +INSERT INTO "iana_records" VALUES(7324,0,NULL,'xmx','maden','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7325,0,NULL,'xmy','mayaguduna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7326,0,NULL,'xmz','mori bawah','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7327,0,NULL,'xna','ancient north arabian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7328,0,NULL,'xnb','kanakanabu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7329,0,NULL,'xnd','na-dene languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7330,0,NULL,'xng','middle mongolian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7331,0,NULL,'xnh','kuanhua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7332,0,NULL,'xnn','northern kankanay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7333,0,NULL,'xno','anglo-norman','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7334,0,NULL,'xnr','kangri','1248825600',NULL,NULL,NULL,NULL,'doi',NULL,NULL); +INSERT INTO "iana_records" VALUES(7335,0,NULL,'xns','kanashi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7336,0,NULL,'xnt','narragansett','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7337,0,NULL,'xoc','o''chi''chi''','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7338,0,NULL,'xod','kokoda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7339,0,NULL,'xog','soga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7340,0,NULL,'xoi','kominimung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7341,0,NULL,'xok','xokleng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7342,0,NULL,'xom','komo (sudan)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7343,0,NULL,'xon','konkomba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7344,0,NULL,'xoo','xukurú','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7345,0,NULL,'xop','kopar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7346,0,NULL,'xor','korubo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7347,0,NULL,'xow','kowaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7348,0,NULL,'xpc','pecheneg','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7349,0,NULL,'xpe','liberia kpelle','1248825600',NULL,NULL,NULL,NULL,'kpe',NULL,NULL); +INSERT INTO "iana_records" VALUES(7350,0,NULL,'xpg','phrygian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7351,0,NULL,'xpi','pictish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7352,0,NULL,'xpk','kulina pano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7353,0,NULL,'xpm','pumpokol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7354,0,NULL,'xpn','kapinawá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7355,0,NULL,'xpo','pochutec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7356,0,NULL,'xpp','puyo-paekche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7357,0,NULL,'xpq','mohegan-pequot','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7358,0,NULL,'xpr','parthian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7359,0,NULL,'xps','pisidian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7360,0,NULL,'xpu','punic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7361,0,NULL,'xpy','puyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7362,0,NULL,'xqa','karakhanid','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7363,0,NULL,'xqt','qatabanian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7364,0,NULL,'xra','krahô','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7365,0,NULL,'xrb','eastern karaboro','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7366,0,NULL,'xre','kreye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7367,0,NULL,'xri','krikati-timbira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7368,0,NULL,'xrm','armazic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7369,0,NULL,'xrn','arin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7370,0,NULL,'xrr','raetic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7371,0,NULL,'xrt','aranama-tamique','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7372,0,NULL,'xru','marriammu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7373,0,NULL,'xrw','karawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7374,0,NULL,'xsa','sabaean','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7375,0,NULL,'xsb','tinà sambal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7376,0,NULL,'xsc','scythian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7377,0,NULL,'xsd','sidetic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7378,0,NULL,'xse','sempan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7379,0,NULL,'xsh','shamang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7380,0,NULL,'xsi','sio','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7381,0,NULL,'xsj','subi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7382,0,NULL,'xsl','south slavey','1248825600',NULL,NULL,NULL,NULL,'den',NULL,NULL); +INSERT INTO "iana_records" VALUES(7383,0,NULL,'xsm','kasem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7384,0,NULL,'xsn','sanga (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7385,0,NULL,'xso','solano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7386,0,NULL,'xsp','silopi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7387,0,NULL,'xsq','makhuwa-saka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7388,0,NULL,'xsr','sherpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7389,0,NULL,'xss','assan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7390,0,NULL,'xsu','sanumá','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7391,0,NULL,'xsv','sudovian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7392,0,NULL,'xsy','saisiyat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7393,0,NULL,'xta','alcozauca mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7394,0,NULL,'xtb','chazumba mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7395,0,NULL,'xtc','katcha-kadugli-miri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7396,0,NULL,'xtd','diuxi-tilantongo mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7397,0,NULL,'xte','ketengban','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7398,0,NULL,'xtg','transalpine gaulish','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7399,0,NULL,'xti','sinicahua mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7400,0,NULL,'xtj','san juan teita mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7401,0,NULL,'xtl','tijaltepec mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7402,0,NULL,'xtm','magdalena peñasco mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7403,0,NULL,'xtn','northern tlaxiaco mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7404,0,NULL,'xto','tokharian a','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7405,0,NULL,'xtp','san miguel piedras mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7406,0,NULL,'xtq','tumshuqese','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7407,0,NULL,'xtr','early tripuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7408,0,NULL,'xts','sindihui mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7409,0,NULL,'xtt','tacahua mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7410,0,NULL,'xtu','cuyamecalco mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7411,0,NULL,'xtw','tawandê','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7412,0,NULL,'xty','yoloxochitl mixtec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7413,0,NULL,'xtz','tasmanian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7414,0,NULL,'xua','alu kurumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7415,0,NULL,'xub','betta kurumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7416,0,NULL,'xug','kunigami','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7417,0,NULL,'xuj','jennu kurumba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7418,0,NULL,'xum','umbrian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7419,0,NULL,'xuo','kuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7420,0,NULL,'xup','upper umpqua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7421,0,NULL,'xur','urartian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7422,0,NULL,'xut','kuthant','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7423,0,NULL,'xuu','kxoe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7424,0,NULL,'xve','venetic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7425,0,NULL,'xvi','kamviri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7426,0,NULL,'xvn','vandalic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7427,0,NULL,'xvo','volscian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7428,0,NULL,'xvs','vestinian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7429,0,NULL,'xwa','kwaza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7430,0,NULL,'xwc','woccon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7431,0,NULL,'xwe','xwela gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7432,0,NULL,'xwg','kwegu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7433,0,NULL,'xwl','western xwla gbe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7434,0,NULL,'xwo','written oirat','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7435,0,NULL,'xwr','kwerba mamberamo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7436,0,NULL,'xxb','boro (ghana)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7437,0,NULL,'xxk','ke''o','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7438,0,NULL,'xxr','koropó','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7439,0,NULL,'xxt','tambora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7440,0,NULL,'xyl','yalakalore','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7441,0,NULL,'xzh','zhang-zhung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7442,0,NULL,'xzm','zemgalian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7443,0,NULL,'xzp','ancient zapotec','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7444,0,NULL,'yaa','yaminahua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7445,0,NULL,'yab','yuhup','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7446,0,NULL,'yac','pass valley yali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7447,0,NULL,'yad','yagua','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7448,0,NULL,'yae','pumé','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7449,0,NULL,'yaf','yaka (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7450,0,NULL,'yag','yámana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7451,0,NULL,'yah','yazgulyam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7452,0,NULL,'yai','yagnobi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7453,0,NULL,'yaj','banda-yangere','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7454,0,NULL,'yak','yakama','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7455,0,NULL,'yal','yalunka','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7456,0,NULL,'yam','yamba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7457,0,NULL,'yan','mayangna','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7458,0,NULL,'yao','yao','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7459,0,NULL,'yap','yapese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7460,0,NULL,'yaq','yaqui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7461,0,NULL,'yar','yabarana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7462,0,NULL,'yas','nugunu (cameroon)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7463,0,NULL,'yat','yambeta','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7464,0,NULL,'yau','yuwana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7465,0,NULL,'yav','yangben','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7466,0,NULL,'yaw','yawalapití','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7467,0,NULL,'yax','yauma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7468,0,NULL,'yay','agwagwune','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7469,0,NULL,'yaz','lokaa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7470,0,NULL,'yba','yala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7471,0,NULL,'ybb','yemba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7472,0,NULL,'ybd','yangbye','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7473,0,NULL,'ybe','west yugur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7474,0,NULL,'ybh','yakha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7475,0,NULL,'ybi','yamphu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7476,0,NULL,'ybj','hasha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7477,0,NULL,'ybk','bokha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7478,0,NULL,'ybl','yukuben','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7479,0,NULL,'ybm','yaben','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7480,0,NULL,'ybn','yabaâna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7481,0,NULL,'ybo','yabong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7482,0,NULL,'ybx','yawiyo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7483,0,NULL,'yby','yaweyuha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7484,0,NULL,'ych','chesu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7485,0,NULL,'ycl','lolopo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7486,0,NULL,'ycn','yucuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7487,0,NULL,'ycp','chepya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7488,0,NULL,'ydd','eastern yiddish','1248825600',NULL,NULL,NULL,NULL,'yi',NULL,NULL); +INSERT INTO "iana_records" VALUES(7489,0,NULL,'yde','yangum dey','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7490,0,NULL,'ydg','yidgha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7491,0,NULL,'ydk','yoidik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7492,0,NULL,'yds','yiddish sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7493,0,NULL,'yea','ravula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7494,0,NULL,'yec','yeniche','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7495,0,NULL,'yee','yimas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7496,0,NULL,'yei','yeni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7497,0,NULL,'yej','yevanic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7498,0,NULL,'yel','yela','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7499,0,NULL,'yen','yendang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7500,0,NULL,'yer','tarok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7501,0,NULL,'yes','yeskwa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7502,0,NULL,'yet','yetfa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7503,0,NULL,'yeu','yerukula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7504,0,NULL,'yev','yapunda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7505,0,NULL,'yey','yeyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7506,0,NULL,'ygl','yangum gel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7507,0,NULL,'ygm','yagomi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7508,0,NULL,'ygp','gepo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7509,0,NULL,'ygr','yagaria','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7510,0,NULL,'ygw','yagwoia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7511,0,NULL,'yha','baha buyang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7512,0,NULL,'yhd','judeo-iraqi arabic','1248825600',NULL,NULL,NULL,NULL,'jrb',NULL,NULL); +INSERT INTO "iana_records" VALUES(7513,0,NULL,'yhl','hlepho phowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7514,0,NULL,'yia','yinggarda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7515,0,NULL,'yif','ache','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7516,0,NULL,'yig','wusa nasu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7517,0,NULL,'yih','western yiddish','1248825600',NULL,NULL,NULL,NULL,'yi',NULL,NULL); +INSERT INTO "iana_records" VALUES(7518,0,NULL,'yii','yidiny','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7519,0,NULL,'yij','yindjibarndi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7520,0,NULL,'yik','dongshanba lalo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7521,0,NULL,'yil','yindjilandji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7522,0,NULL,'yim','yimchungru naga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7523,0,NULL,'yin','yinchia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7524,0,NULL,'yip','pholo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7525,0,NULL,'yiq','miqie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7526,0,NULL,'yir','north awyu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7527,0,NULL,'yis','yis','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7528,0,NULL,'yit','eastern lalu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7529,0,NULL,'yiu','awu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7530,0,NULL,'yiv','northern nisu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7531,0,NULL,'yix','axi yi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7532,0,NULL,'yiy','yir yoront','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7533,0,NULL,'yiz','azhe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7534,0,NULL,'yka','yakan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7535,0,NULL,'ykg','northern yukaghir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7536,0,NULL,'yki','yoke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7537,0,NULL,'ykk','yakaikeke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7538,0,NULL,'ykl','khlula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7539,0,NULL,'ykm','kap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7540,0,NULL,'yko','yasa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7541,0,NULL,'ykr','yekora','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7542,0,NULL,'ykt','kathu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7543,0,NULL,'yky','yakoma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7544,0,NULL,'yla','yaul','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7545,0,NULL,'ylb','yaleba','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7546,0,NULL,'yle','yele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7547,0,NULL,'ylg','yelogu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7548,0,NULL,'yli','angguruk yali','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7549,0,NULL,'yll','yil','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7550,0,NULL,'ylm','limi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7551,0,NULL,'yln','langnian buyang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7552,0,NULL,'ylo','naluo yi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7553,0,NULL,'ylr','yalarnnga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7554,0,NULL,'ylu','aribwaung','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7555,0,NULL,'yly','nyâlayu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7556,0,NULL,'yma','yamphe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7557,0,NULL,'ymb','yambes','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7558,0,NULL,'ymc','southern muji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7559,0,NULL,'ymd','muda','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7560,0,NULL,'yme','yameo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7561,0,NULL,'ymg','yamongeri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7562,0,NULL,'ymh','mili','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7563,0,NULL,'ymi','moji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7564,0,NULL,'ymk','makwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7565,0,NULL,'yml','iamalele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7566,0,NULL,'ymm','maay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7567,0,NULL,'ymn','sunum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7567,0,NULL,'ymn','yamna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7568,0,NULL,'ymo','yangum mon','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7569,0,NULL,'ymp','yamap','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7570,0,NULL,'ymq','qila muji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7571,0,NULL,'ymr','malasar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7572,0,NULL,'yms','mysian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7573,0,NULL,'ymt','mator-taygi-karagas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7574,0,NULL,'ymx','northern muji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7575,0,NULL,'ymz','muzi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7576,0,NULL,'yna','aluo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7577,0,NULL,'ynd','yandruwandha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7578,0,NULL,'yne','lang''e','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7579,0,NULL,'yng','yango','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7580,0,NULL,'ynh','yangho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7581,0,NULL,'ynk','naukan yupik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7582,0,NULL,'ynl','yangulam','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7583,0,NULL,'ynn','yana','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7584,0,NULL,'yno','yong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7585,0,NULL,'yns','yansi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7586,0,NULL,'ynu','yahuna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7587,0,NULL,'yob','yoba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7588,0,NULL,'yog','yogad','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7589,0,NULL,'yoi','yonaguni','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7590,0,NULL,'yok','yokuts','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7591,0,NULL,'yol','yola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7592,0,NULL,'yom','yombe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7593,0,NULL,'yon','yonggom','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7594,0,NULL,'yos','yos','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7595,0,NULL,'yox','yoron','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7596,0,NULL,'yoy','yoy','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7597,0,NULL,'ypa','phala','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7598,0,NULL,'ypb','labo phowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7599,0,NULL,'ypg','phola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7600,0,NULL,'yph','phupha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7601,0,NULL,'ypk','yupik languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7602,0,NULL,'ypm','phuma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7603,0,NULL,'ypn','ani phowa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7604,0,NULL,'ypo','alo phola','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7605,0,NULL,'ypp','phupa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7606,0,NULL,'ypz','phuza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7607,0,NULL,'yra','yerakai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7608,0,NULL,'yrb','yareba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7609,0,NULL,'yre','yaouré','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7610,0,NULL,'yri','yarí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7611,0,NULL,'yrk','nenets','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7612,0,NULL,'yrl','nhengatu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7613,0,NULL,'yrn','yerong','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7614,0,NULL,'yrs','yarsun','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7615,0,NULL,'yrw','yarawata','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7616,0,NULL,'ysc','yassic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7617,0,NULL,'ysd','samatao','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7618,0,NULL,'ysl','yugoslavian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7619,0,NULL,'ysn','sani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7620,0,NULL,'yso','nisi (china)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7621,0,NULL,'ysp','southern lolopo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7622,0,NULL,'ysr','sirenik yupik','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7623,0,NULL,'yss','yessan-mayo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7624,0,NULL,'ysy','sanie','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7625,0,NULL,'yta','talu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7626,0,NULL,'ytl','tanglang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7627,0,NULL,'ytp','thopho','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7628,0,NULL,'ytw','yout wam','1268265600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7629,0,NULL,'yua','yucatec maya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7629,0,NULL,'yua','yucateco','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7630,0,NULL,'yub','yugambal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7631,0,NULL,'yuc','yuchi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7632,0,NULL,'yud','judeo-tripolitanian arabic','1248825600',NULL,NULL,NULL,NULL,'jrb',NULL,NULL); +INSERT INTO "iana_records" VALUES(7633,0,NULL,'yue','yue chinese','1248825600',NULL,NULL,NULL,NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7634,0,NULL,'yuf','havasupai-walapai-yavapai','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7635,0,NULL,'yug','yug','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7636,0,NULL,'yui','yurutí','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7637,0,NULL,'yuj','karkar-yuri','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7638,0,NULL,'yuk','yuki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7639,0,NULL,'yul','yulu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7640,0,NULL,'yum','quechan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7641,0,NULL,'yun','bena (nigeria)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7642,0,NULL,'yup','yukpa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7643,0,NULL,'yuq','yuqui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7644,0,NULL,'yur','yurok','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7645,0,NULL,'yut','yopno','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7646,0,NULL,'yuu','yugh','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7647,0,NULL,'yuw','yau (morobe province)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7648,0,NULL,'yux','southern yukaghir','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7649,0,NULL,'yuy','east yugur','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7650,0,NULL,'yuz','yuracare','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7651,0,NULL,'yva','yawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7652,0,NULL,'yvt','yavitero','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7653,0,NULL,'ywa','kalou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7654,0,NULL,'ywl','western lalu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7655,0,NULL,'ywn','yawanawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7656,0,NULL,'ywq','wuding-luquan yi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7657,0,NULL,'ywr','yawuru','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7658,0,NULL,'ywt','xishanba lalo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7659,0,NULL,'ywu','wumeng nasu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7660,0,NULL,'yww','yawarawarga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7661,0,NULL,'yyu','yau (sandaun province)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7662,0,NULL,'yyz','ayizi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7663,0,NULL,'yzg','e''ma buyang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7664,0,NULL,'yzk','zokhuo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7665,0,NULL,'zaa','sierra de juárez zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7666,0,NULL,'zab','san juan guelavía zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7667,0,NULL,'zac','ocotlán zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7668,0,NULL,'zad','cajonos zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7669,0,NULL,'zae','yareni zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7670,0,NULL,'zaf','ayoquesco zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7671,0,NULL,'zag','zaghawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7672,0,NULL,'zah','zangwal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7673,0,NULL,'zai','isthmus zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7674,0,NULL,'zaj','zaramo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7675,0,NULL,'zak','zanaki','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7676,0,NULL,'zal','zauzou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7677,0,NULL,'zam','miahuatlán zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7678,0,NULL,'zao','ozolotepec zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7679,0,NULL,'zap','zapotec','1129420800',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(7680,0,NULL,'zaq','aloápam zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7681,0,NULL,'zar','rincón zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7682,0,NULL,'zas','santo domingo albarradas zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7683,0,NULL,'zat','tabaa zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7684,0,NULL,'zau','zangskari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7685,0,NULL,'zav','yatzachi zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7686,0,NULL,'zaw','mitla zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7687,0,NULL,'zax','xadani zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7688,0,NULL,'zay','zayse-zergulla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7688,0,NULL,'zay','zaysete','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7689,0,NULL,'zaz','zari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7690,0,NULL,'zbc','central berawan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7691,0,NULL,'zbe','east berawan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7692,0,NULL,'zbl','bliss','1187654400',NULL,NULL,NULL,'blis',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7692,0,NULL,'zbl','blissymbolics','1187654400',NULL,NULL,NULL,'blis',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7692,0,NULL,'zbl','blissymbols','1187654400',NULL,NULL,NULL,'blis',NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7693,0,NULL,'zbt','batui','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7694,0,NULL,'zbw','west berawan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7695,0,NULL,'zca','coatecas altas zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7696,0,NULL,'zch','central hongshuihe zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7697,0,NULL,'zdj','ngazidja comorian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7698,0,NULL,'zea','zeeuws','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7699,0,NULL,'zeg','zenag','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7700,0,NULL,'zeh','eastern hongshuihe zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7701,0,NULL,'zen','zenaga','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7702,0,NULL,'zga','kinga','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7703,0,NULL,'zgb','guibei zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7704,0,NULL,'zgm','minz zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7705,0,NULL,'zgn','guibian zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7706,0,NULL,'zgr','magori','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7707,0,NULL,'zhb','zhaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7708,0,NULL,'zhd','dai zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7709,0,NULL,'zhi','zhire','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7710,0,NULL,'zhn','nong zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7711,0,NULL,'zhw','zhoa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7712,0,NULL,'zhx','chinese (family)','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7713,0,NULL,'zia','zia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7714,0,NULL,'zib','zimbabwe sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7715,0,NULL,'zik','zimakani','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7716,0,NULL,'zim','mesme','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7717,0,NULL,'zin','zinza','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7718,0,NULL,'zir','ziriya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7719,0,NULL,'ziw','zigula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7720,0,NULL,'ziz','zizilivakan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7721,0,NULL,'zka','kaimbulawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7722,0,NULL,'zkb','koibal','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7723,0,NULL,'zkg','koguryo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7724,0,NULL,'zkh','khorezmian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7725,0,NULL,'zkk','karankawa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7726,0,NULL,'zko','kott','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7727,0,NULL,'zkp','são paulo kaingáng','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7728,0,NULL,'zkr','zakhring','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7729,0,NULL,'zkt','kitan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7730,0,NULL,'zku','kaurna','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7731,0,NULL,'zkv','krevinian','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7732,0,NULL,'zkz','khazar','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7733,0,NULL,'zle','east slavic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7734,0,NULL,'zlj','liujiang zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7735,0,NULL,'zlm','malay (individual language)','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7736,0,NULL,'zln','lianshan zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7737,0,NULL,'zlq','liuqian zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7738,0,NULL,'zls','south slavic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7739,0,NULL,'zlw','west slavic languages','1248825600',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7740,0,NULL,'zma','manda (australia)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7741,0,NULL,'zmb','zimba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7742,0,NULL,'zmc','margany','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7743,0,NULL,'zmd','maridan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7744,0,NULL,'zme','mangerr','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7745,0,NULL,'zmf','mfinu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7746,0,NULL,'zmg','marti ke','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7747,0,NULL,'zmh','makolkol','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7748,0,NULL,'zmi','negeri sembilan malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7749,0,NULL,'zmj','maridjabin','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7750,0,NULL,'zmk','mandandanyi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7751,0,NULL,'zml','madngele','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7752,0,NULL,'zmm','marimanindji','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7753,0,NULL,'zmn','mbangwe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7754,0,NULL,'zmo','molo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7755,0,NULL,'zmp','mpuono','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7756,0,NULL,'zmq','mituku','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7757,0,NULL,'zmr','maranunggu','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7758,0,NULL,'zms','mbesa','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7759,0,NULL,'zmt','maringarr','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7760,0,NULL,'zmu','muruwari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7761,0,NULL,'zmv','mbariman-gudhinma','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7762,0,NULL,'zmw','mbo (democratic republic of congo)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7763,0,NULL,'zmx','bomitaba','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7764,0,NULL,'zmy','mariyedi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7765,0,NULL,'zmz','mbandja','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7766,0,NULL,'zna','zan gula','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7767,0,NULL,'znd','zande languages','1129420800',NULL,NULL,NULL,NULL,NULL,'collection',NULL); +INSERT INTO "iana_records" VALUES(7768,0,NULL,'zne','zande (individual language)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7769,0,NULL,'zng','mang','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7770,0,NULL,'znk','manangkari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7771,0,NULL,'zns','mangas','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7772,0,NULL,'zoc','copainalá zoque','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7773,0,NULL,'zoh','chimalapa zoque','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7774,0,NULL,'zom','zou','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7775,0,NULL,'zoo','asunción mixtepec zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7776,0,NULL,'zoq','tabasco zoque','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7777,0,NULL,'zor','rayón zoque','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7778,0,NULL,'zos','francisco león zoque','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7779,0,NULL,'zpa','lachiguiri zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7780,0,NULL,'zpb','yautepec zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7781,0,NULL,'zpc','choapan zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7782,0,NULL,'zpd','southeastern ixtlán zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7783,0,NULL,'zpe','petapa zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7784,0,NULL,'zpf','san pedro quiatoni zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7785,0,NULL,'zpg','guevea de humboldt zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7786,0,NULL,'zph','totomachapan zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7787,0,NULL,'zpi','santa maría quiegolani zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7788,0,NULL,'zpj','quiavicuzas zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7789,0,NULL,'zpk','tlacolulita zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7790,0,NULL,'zpl','lachixío zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7791,0,NULL,'zpm','mixtepec zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7792,0,NULL,'zpn','santa inés yatzechi zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7793,0,NULL,'zpo','amatlán zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7794,0,NULL,'zpp','el alto zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7795,0,NULL,'zpq','zoogocho zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7796,0,NULL,'zpr','santiago xanica zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7797,0,NULL,'zps','coatlán zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7798,0,NULL,'zpt','san vicente coatlán zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7799,0,NULL,'zpu','yalálag zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7800,0,NULL,'zpv','chichicapan zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7801,0,NULL,'zpw','zaniza zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7802,0,NULL,'zpx','san baltazar loxicha zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7803,0,NULL,'zpy','mazaltepec zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7804,0,NULL,'zpz','texmelucan zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7805,0,NULL,'zqe','qiubei zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7806,0,NULL,'zra','kara (korea)','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7807,0,NULL,'zrg','mirgan','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7808,0,NULL,'zrn','zerenkel','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7809,0,NULL,'zro','záparo','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7810,0,NULL,'zrp','zarphatic','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7811,0,NULL,'zrs','mairasi','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7812,0,NULL,'zsa','sarasira','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7813,0,NULL,'zsk','kaskean','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7814,0,NULL,'zsl','zambian sign language','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7815,0,NULL,'zsm','standard malay','1248825600',NULL,NULL,NULL,NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7816,0,NULL,'zsr','southern rincon zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7817,0,NULL,'zsu','sukurum','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7818,0,NULL,'zte','elotepec zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7819,0,NULL,'ztg','xanaguía zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7820,0,NULL,'ztl','lapaguía-guivini zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7821,0,NULL,'ztm','san agustín mixtepec zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7822,0,NULL,'ztn','santa catarina albarradas zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7823,0,NULL,'ztp','loxicha zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7824,0,NULL,'ztq','quioquitani-quierí zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7825,0,NULL,'zts','tilquiapan zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7826,0,NULL,'ztt','tejalapan zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7827,0,NULL,'ztu','güilá zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7828,0,NULL,'ztx','zaachila zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7829,0,NULL,'zty','yatee zapotec','1248825600',NULL,NULL,NULL,NULL,'zap',NULL,NULL); +INSERT INTO "iana_records" VALUES(7830,0,NULL,'zua','zeem','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7831,0,NULL,'zuh','tokano','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7832,0,NULL,'zum','kumzari','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7833,0,NULL,'zun','zuni','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7834,0,NULL,'zuy','zumaya','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7835,0,NULL,'zwa','zay','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7836,0,NULL,'zxx','no linguistic content','1141776000',NULL,NULL,NULL,NULL,NULL,'special',NULL); +INSERT INTO "iana_records" VALUES(7836,0,NULL,'zxx','not applicable','1141776000',NULL,NULL,NULL,NULL,NULL,'special',NULL); +INSERT INTO "iana_records" VALUES(7837,0,NULL,'zyb','yongbei zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7838,0,NULL,'zyg','yang zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7839,0,NULL,'zyj','youjiang zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7840,0,NULL,'zyn','yongnan zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7841,0,NULL,'zyp','zyphe','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7842,0,NULL,'zza','dimili','1156377600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(7842,0,NULL,'zza','dimli (macrolanguage)','1156377600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(7842,0,NULL,'zza','kirdki','1156377600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(7842,0,NULL,'zza','kirmanjki (macrolanguage)','1156377600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(7842,0,NULL,'zza','zaza','1156377600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(7842,0,NULL,'zza','zazaki','1156377600',NULL,NULL,NULL,NULL,NULL,'macrolanguage',NULL); +INSERT INTO "iana_records" VALUES(7843,6,NULL,'zzj','zuojiang zhuang','1248825600',NULL,NULL,NULL,NULL,'za',NULL,NULL); +INSERT INTO "iana_records" VALUES(7844,6,NULL,'aao','algerian saharan arabic','1248825600',NULL,'aao','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7845,6,NULL,'abh','tajiki arabic','1248825600',NULL,'abh','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7846,6,NULL,'abv','baharna arabic','1248825600',NULL,'abv','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7847,6,NULL,'acm','mesopotamian arabic','1248825600',NULL,'acm','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7848,6,NULL,'acq','ta''izzi-adeni arabic','1248825600',NULL,'acq','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7849,6,NULL,'acw','hijazi arabic','1248825600',NULL,'acw','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7850,6,NULL,'acx','omani arabic','1248825600',NULL,'acx','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7851,6,NULL,'acy','cypriot arabic','1248825600',NULL,'acy','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7852,6,NULL,'adf','dhofari arabic','1248825600',NULL,'adf','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7853,6,NULL,'ads','adamorobe sign language','1248825600',NULL,'ads','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7854,6,NULL,'aeb','tunisian arabic','1248825600',NULL,'aeb','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7855,6,NULL,'aec','saidi arabic','1248825600',NULL,'aec','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7856,6,NULL,'aed','argentine sign language','1248825600',NULL,'aed','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7857,6,NULL,'aen','armenian sign language','1248825600',NULL,'aen','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7858,6,NULL,'afb','gulf arabic','1248825600',NULL,'afb','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7859,6,NULL,'afg','afghan sign language','1248825600',NULL,'afg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7860,6,NULL,'ajp','south levantine arabic','1248825600',NULL,'ajp','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7861,6,NULL,'apc','north levantine arabic','1248825600',NULL,'apc','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7862,6,NULL,'apd','sudanese arabic','1248825600',NULL,'apd','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7863,6,NULL,'arb','standard arabic','1248825600',NULL,'arb','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7864,6,NULL,'arq','algerian arabic','1248825600',NULL,'arq','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7865,6,NULL,'ars','najdi arabic','1248825600',NULL,'ars','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7866,6,NULL,'ary','moroccan arabic','1248825600',NULL,'ary','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7867,6,NULL,'arz','egyptian arabic','1248825600',NULL,'arz','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7868,6,NULL,'ase','american sign language','1248825600',NULL,'ase','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7869,6,NULL,'asf','australian sign language','1248825600',NULL,'asf','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7870,6,NULL,'asp','algerian sign language','1248825600',NULL,'asp','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7871,6,NULL,'asq','austrian sign language','1248825600',NULL,'asq','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7872,6,NULL,'asw','australian aborigines sign language','1248825600',NULL,'asw','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7873,6,NULL,'auz','uzbeki arabic','1248825600',NULL,'auz','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7874,6,NULL,'avl','eastern egyptian bedawi arabic','1248825600',NULL,'avl','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7875,6,NULL,'ayh','hadrami arabic','1248825600',NULL,'ayh','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7876,6,NULL,'ayl','libyan arabic','1248825600',NULL,'ayl','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7877,6,NULL,'ayn','sanaani arabic','1248825600',NULL,'ayn','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7878,6,NULL,'ayp','north mesopotamian arabic','1248825600',NULL,'ayp','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7879,6,NULL,'bbz','babalia creole arabic','1248825600',NULL,'bbz','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(7880,6,NULL,'bfi','british sign language','1248825600',NULL,'bfi','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7881,6,NULL,'bfk','ban khor sign language','1248825600',NULL,'bfk','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7882,6,NULL,'bjn','banjar','1248825600',NULL,'bjn','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7883,6,NULL,'bog','bamako sign language','1248825600',NULL,'bog','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7884,6,NULL,'bqn','bulgarian sign language','1248825600',NULL,'bqn','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7885,6,NULL,'bqy','bengkala sign language','1248825600',NULL,'bqy','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7886,6,NULL,'btj','bacanese malay','1248825600',NULL,'btj','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7887,6,NULL,'bve','berau malay','1248825600',NULL,'bve','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7888,6,NULL,'bvl','bolivian sign language','1248825600',NULL,'bvl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7889,6,NULL,'bvu','bukit malay','1248825600',NULL,'bvu','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7890,6,NULL,'bzs','brazilian sign language','1248825600',NULL,'bzs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7891,6,NULL,'cdo','min dong chinese','1248825600',NULL,'cdo','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7892,6,NULL,'cds','chadian sign language','1248825600',NULL,'cds','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7893,6,NULL,'cjy','jinyu chinese','1248825600',NULL,'cjy','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7894,6,NULL,'cmn','mandarin chinese','1248825600',NULL,'cmn','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7895,6,NULL,'coa','cocos islands malay','1248825600',NULL,'coa','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7896,6,NULL,'cpx','pu-xian chinese','1248825600',NULL,'cpx','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7897,6,NULL,'csc','catalan sign language','1248825600',NULL,'csc','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7897,6,NULL,'csc','lengua de señas catalana','1248825600',NULL,'csc','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7897,6,NULL,'csc','llengua de signes catalana','1248825600',NULL,'csc','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7898,6,NULL,'csd','chiangmai sign language','1248825600',NULL,'csd','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7899,6,NULL,'cse','czech sign language','1248825600',NULL,'cse','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7900,6,NULL,'csf','cuba sign language','1248825600',NULL,'csf','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7901,6,NULL,'csg','chilean sign language','1248825600',NULL,'csg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7902,6,NULL,'csl','chinese sign language','1248825600',NULL,'csl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7903,6,NULL,'csn','colombian sign language','1248825600',NULL,'csn','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7904,6,NULL,'csq','croatia sign language','1248825600',NULL,'csq','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7905,6,NULL,'csr','costa rican sign language','1248825600',NULL,'csr','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7906,6,NULL,'czh','huizhou chinese','1248825600',NULL,'czh','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7907,6,NULL,'czo','min zhong chinese','1248825600',NULL,'czo','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7908,6,NULL,'doq','dominican sign language','1248825600',NULL,'doq','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7909,6,NULL,'dse','dutch sign language','1248825600',NULL,'dse','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7910,6,NULL,'dsl','danish sign language','1248825600',NULL,'dsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7911,6,NULL,'dup','duano','1248825600',NULL,'dup','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7912,6,NULL,'ecs','ecuadorian sign language','1248825600',NULL,'ecs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7913,6,NULL,'esl','egypt sign language','1248825600',NULL,'esl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7914,6,NULL,'esn','salvadoran sign language','1248825600',NULL,'esn','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7915,6,NULL,'eso','estonian sign language','1248825600',NULL,'eso','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7916,6,NULL,'eth','ethiopian sign language','1248825600',NULL,'eth','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7917,6,NULL,'fcs','quebec sign language','1248825600',NULL,'fcs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7918,6,NULL,'fse','finnish sign language','1248825600',NULL,'fse','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7919,6,NULL,'fsl','french sign language','1248825600',NULL,'fsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7920,6,NULL,'fss','finland-swedish sign language','1248825600',NULL,'fss','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7920,6,NULL,'fss','finlandssvenskt teckenspråk','1248825600',NULL,'fss','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7920,6,NULL,'fss','suomenruotsalainen viittomakieli','1248825600',NULL,'fss','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7921,6,NULL,'gan','gan chinese','1248825600',NULL,'gan','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7922,6,NULL,'gom','goan konkani','1248825600',NULL,'gom','kok',NULL,'kok',NULL,NULL); +INSERT INTO "iana_records" VALUES(7923,6,NULL,'gse','ghanaian sign language','1248825600',NULL,'gse','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7924,6,NULL,'gsg','german sign language','1248825600',NULL,'gsg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7925,6,NULL,'gsm','guatemalan sign language','1248825600',NULL,'gsm','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7926,6,NULL,'gss','greek sign language','1248825600',NULL,'gss','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7927,6,NULL,'gus','guinean sign language','1248825600',NULL,'gus','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7928,6,NULL,'hab','hanoi sign language','1248825600',NULL,'hab','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7929,6,NULL,'haf','haiphong sign language','1248825600',NULL,'haf','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7930,6,NULL,'hak','hakka chinese','1248825600',NULL,'hak','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7931,6,NULL,'hds','honduras sign language','1248825600',NULL,'hds','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7932,6,NULL,'hji','haji','1248825600',NULL,'hji','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7933,6,NULL,'hks','heung kong sau yue','1248825600',NULL,'hks','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7933,6,NULL,'hks','hong kong sign language','1248825600',NULL,'hks','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7934,6,NULL,'hos','ho chi minh city sign language','1248825600',NULL,'hos','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7935,6,NULL,'hps','hawai''i pidgin sign language','1248825600',NULL,'hps','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7936,6,NULL,'hsh','hungarian sign language','1248825600',NULL,'hsh','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7937,6,NULL,'hsl','hausa sign language','1248825600',NULL,'hsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7938,6,NULL,'hsn','xiang chinese','1248825600',NULL,'hsn','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7939,6,NULL,'icl','icelandic sign language','1248825600',NULL,'icl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7940,6,NULL,'ils','international sign','1248825600',NULL,'ils','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7941,6,NULL,'inl','indonesian sign language','1248825600',NULL,'inl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7942,6,NULL,'ins','indian sign language','1248825600',NULL,'ins','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7943,6,NULL,'ise','italian sign language','1248825600',NULL,'ise','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7944,6,NULL,'isg','irish sign language','1248825600',NULL,'isg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7945,6,NULL,'isr','israeli sign language','1248825600',NULL,'isr','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7946,6,NULL,'jak','jakun','1248825600',NULL,'jak','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7947,6,NULL,'jax','jambi malay','1248825600',NULL,'jax','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7948,6,NULL,'jcs','jamaican country sign language','1248825600',NULL,'jcs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7949,6,NULL,'jhs','jhankot sign language','1248825600',NULL,'jhs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7950,6,NULL,'jls','jamaican sign language','1268265600',NULL,'jls','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7951,6,NULL,'jos','jordanian sign language','1248825600',NULL,'jos','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7952,6,NULL,'jsl','japanese sign language','1248825600',NULL,'jsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7953,6,NULL,'jus','jumla sign language','1248825600',NULL,'jus','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7954,6,NULL,'kgi','selangor sign language','1248825600',NULL,'kgi','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7955,6,NULL,'knn','konkani (individual language)','1248825600',NULL,'knn','kok',NULL,'kok',NULL,NULL); +INSERT INTO "iana_records" VALUES(7956,6,NULL,'kvb','kubu','1248825600',NULL,'kvb','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7957,6,NULL,'kvk','korean sign language','1248825600',NULL,'kvk','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7958,6,NULL,'kvr','kerinci','1248825600',NULL,'kvr','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7959,6,NULL,'kxd','brunei','1248825600',NULL,'kxd','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7960,6,NULL,'lbs','libyan sign language','1248825600',NULL,'lbs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7961,6,NULL,'lce','loncong','1248825600',NULL,'lce','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7962,6,NULL,'lcf','lubu','1248825600',NULL,'lcf','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7963,6,NULL,'liw','col','1248825600',NULL,'liw','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7964,6,NULL,'lls','lithuanian sign language','1248825600',NULL,'lls','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7965,6,NULL,'lsg','lyons sign language','1248825600',NULL,'lsg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7966,6,NULL,'lsl','latvian sign language','1248825600',NULL,'lsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7967,6,NULL,'lso','laos sign language','1248825600',NULL,'lso','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7968,6,NULL,'lsp','lengua de señas panameñas','1248825600',NULL,'lsp','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7968,6,NULL,'lsp','panamanian sign language','1248825600',NULL,'lsp','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7969,6,NULL,'lst','trinidad and tobago sign language','1248825600',NULL,'lst','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7970,6,NULL,'lsy','mauritian sign language','1268265600',NULL,'lsy','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7971,6,NULL,'ltg','latgalian','1268265600',NULL,'ltg','lv',NULL,'lv',NULL,NULL); +INSERT INTO "iana_records" VALUES(7972,6,NULL,'lvs','standard latvian','1268265600',NULL,'lvs','lv',NULL,'lv',NULL,NULL); +INSERT INTO "iana_records" VALUES(7973,6,NULL,'lzh','literary chinese','1248825600',NULL,'lzh','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7974,6,NULL,'max','north moluccan malay','1248825600',NULL,'max','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7975,6,NULL,'mdl','maltese sign language','1248825600',NULL,'mdl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7976,6,NULL,'meo','kedah malay','1248825600',NULL,'meo','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7977,6,NULL,'mfa','pattani malay','1248825600',NULL,'mfa','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7978,6,NULL,'mfb','bangka','1248825600',NULL,'mfb','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7979,6,NULL,'mfs','mexican sign language','1248825600',NULL,'mfs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7980,6,NULL,'min','minangkabau','1248825600',NULL,'min','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7981,6,NULL,'mnp','min bei chinese','1248825600',NULL,'mnp','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7982,6,NULL,'mqg','kota bangun kutai malay','1248825600',NULL,'mqg','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7983,6,NULL,'mre','martha''s vineyard sign language','1248825600',NULL,'mre','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7984,6,NULL,'msd','yucatec maya sign language','1248825600',NULL,'msd','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7985,6,NULL,'msi','sabah malay','1248825600',NULL,'msi','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7986,6,NULL,'msr','mongolian sign language','1248825600',NULL,'msr','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7987,6,NULL,'mui','musi','1248825600',NULL,'mui','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(7988,6,NULL,'mzc','madagascar sign language','1248825600',NULL,'mzc','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7989,6,NULL,'mzg','monastic sign language','1248825600',NULL,'mzg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7990,6,NULL,'mzy','mozambican sign language','1248825600',NULL,'mzy','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7991,6,NULL,'nan','min nan chinese','1248825600',NULL,'nan','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(7992,6,NULL,'nbs','namibian sign language','1248825600',NULL,'nbs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7993,6,NULL,'ncs','nicaraguan sign language','1248825600',NULL,'ncs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7994,6,NULL,'nsi','nigerian sign language','1248825600',NULL,'nsi','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7995,6,NULL,'nsl','norwegian sign language','1248825600',NULL,'nsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7996,6,NULL,'nsp','nepalese sign language','1248825600',NULL,'nsp','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7997,6,NULL,'nsr','maritime sign language','1248825600',NULL,'nsr','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7998,6,NULL,'nzs','new zealand sign language','1248825600',NULL,'nzs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(7999,6,NULL,'okl','old kentish sign language','1248825600',NULL,'okl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8000,6,NULL,'orn','orang kanaq','1248825600',NULL,'orn','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8001,6,NULL,'ors','orang seletar','1248825600',NULL,'ors','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8002,6,NULL,'pel','pekal','1248825600',NULL,'pel','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8003,6,NULL,'pga','sudanese creole arabic','1248825600',NULL,'pga','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(8004,6,NULL,'pks','pakistan sign language','1248825600',NULL,'pks','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8005,6,NULL,'prl','peruvian sign language','1248825600',NULL,'prl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8006,6,NULL,'prz','providencia sign language','1248825600',NULL,'prz','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8007,6,NULL,'psc','persian sign language','1248825600',NULL,'psc','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8008,6,NULL,'psd','plains indian sign language','1248825600',NULL,'psd','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8009,6,NULL,'pse','central malay','1248825600',NULL,'pse','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8010,6,NULL,'psg','penang sign language','1248825600',NULL,'psg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8011,6,NULL,'psl','puerto rican sign language','1248825600',NULL,'psl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8012,6,NULL,'pso','polish sign language','1248825600',NULL,'pso','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8013,6,NULL,'psp','philippine sign language','1248825600',NULL,'psp','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8014,6,NULL,'psr','portuguese sign language','1248825600',NULL,'psr','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8015,6,NULL,'pys','lengua de señas del paraguay','1268265600',NULL,'pys','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8015,6,NULL,'pys','paraguayan sign language','1268265600',NULL,'pys','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8016,6,NULL,'rms','romanian sign language','1248825600',NULL,'rms','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8017,6,NULL,'rsi','rennellese sign language','1248825600',NULL,'rsi','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8018,6,NULL,'rsl','russian sign language','1248825600',NULL,'rsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8019,6,NULL,'sdl','saudi arabian sign language','1248825600',NULL,'sdl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8020,6,NULL,'sfb','french belgian sign language','1248825600',NULL,'sfb','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8020,6,NULL,'sfb','langue des signes de belgique francophone','1248825600',NULL,'sfb','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8021,6,NULL,'sfs','south african sign language','1248825600',NULL,'sfs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8022,6,NULL,'sgg','swiss-german sign language','1248825600',NULL,'sgg','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8023,6,NULL,'sgx','sierra leone sign language','1248825600',NULL,'sgx','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8024,6,NULL,'shu','chadian arabic','1248825600',NULL,'shu','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(8025,6,NULL,'slf','swiss-italian sign language','1248825600',NULL,'slf','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8026,6,NULL,'sls','singapore sign language','1248825600',NULL,'sls','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8027,6,NULL,'sqs','sri lankan sign language','1248825600',NULL,'sqs','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8028,6,NULL,'ssh','shihhi arabic','1248825600',NULL,'ssh','ar',NULL,'ar',NULL,NULL); +INSERT INTO "iana_records" VALUES(8029,6,NULL,'ssp','spanish sign language','1248825600',NULL,'ssp','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8030,6,NULL,'ssr','swiss-french sign language','1248825600',NULL,'ssr','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8031,6,NULL,'svk','slovakian sign language','1248825600',NULL,'svk','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8032,6,NULL,'swc','congo swahili','1248825600',NULL,'swc','sw',NULL,'sw',NULL,NULL); +INSERT INTO "iana_records" VALUES(8033,6,NULL,'swh','kiswahili','1248825600',NULL,'swh','sw',NULL,'sw',NULL,NULL); +INSERT INTO "iana_records" VALUES(8033,6,NULL,'swh','swahili (individual language)','1248825600',NULL,'swh','sw',NULL,'sw',NULL,NULL); +INSERT INTO "iana_records" VALUES(8034,6,NULL,'swl','swedish sign language','1248825600',NULL,'swl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8035,6,NULL,'syy','al-sayyid bedouin sign language','1248825600',NULL,'syy','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8036,6,NULL,'tmw','temuan','1248825600',NULL,'tmw','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8037,6,NULL,'tse','tunisian sign language','1248825600',NULL,'tse','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8038,6,NULL,'tsm','turkish sign language','1248825600',NULL,'tsm','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8038,6,NULL,'tsm','türk İşaret dili','1248825600',NULL,'tsm','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8039,6,NULL,'tsq','thai sign language','1248825600',NULL,'tsq','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8040,6,NULL,'tss','taiwan sign language','1248825600',NULL,'tss','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8041,6,NULL,'tsy','tebul sign language','1248825600',NULL,'tsy','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8042,6,NULL,'tza','tanzanian sign language','1248825600',NULL,'tza','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8043,6,NULL,'ugn','ugandan sign language','1248825600',NULL,'ugn','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8044,6,NULL,'ugy','uruguayan sign language','1248825600',NULL,'ugy','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8045,6,NULL,'ukl','ukrainian sign language','1248825600',NULL,'ukl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8046,6,NULL,'uks','kaapor sign language','1248825600',NULL,'uks','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8046,6,NULL,'uks','urubú-kaapor sign language','1248825600',NULL,'uks','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8047,6,NULL,'urk','urak lawoi''','1248825600',NULL,'urk','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8048,6,NULL,'uzn','northern uzbek','1248825600',NULL,'uzn','uz',NULL,'uz',NULL,NULL); +INSERT INTO "iana_records" VALUES(8049,6,NULL,'uzs','southern uzbek','1248825600',NULL,'uzs','uz',NULL,'uz',NULL,NULL); +INSERT INTO "iana_records" VALUES(8050,6,NULL,'vgt','flemish sign language','1248825600',NULL,'vgt','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8050,6,NULL,'vgt','vlaamse gebarentaal','1248825600',NULL,'vgt','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8051,6,NULL,'vkk','kaur','1248825600',NULL,'vkk','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8052,6,NULL,'vkt','tenggarong kutai malay','1248825600',NULL,'vkt','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8053,6,NULL,'vsi','moldova sign language','1248825600',NULL,'vsi','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8054,6,NULL,'vsl','venezuelan sign language','1248825600',NULL,'vsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8055,6,NULL,'vsv','llengua de signes valenciana','1248825600',NULL,'vsv','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8055,6,NULL,'vsv','valencian sign language','1248825600',NULL,'vsv','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8056,6,NULL,'wuu','wu chinese','1248825600',NULL,'wuu','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(8057,6,NULL,'xki','kenyan sign language','1248825600',NULL,'xki','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8058,6,NULL,'xml','malaysian sign language','1248825600',NULL,'xml','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8059,6,NULL,'xmm','manado malay','1248825600',NULL,'xmm','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8060,6,NULL,'xms','moroccan sign language','1248825600',NULL,'xms','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8061,6,NULL,'yds','yiddish sign language','1248825600',NULL,'yds','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8062,6,NULL,'ysl','yugoslavian sign language','1248825600',NULL,'ysl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8063,6,NULL,'yue','yue chinese','1248825600',NULL,'yue','zh',NULL,'zh',NULL,NULL); +INSERT INTO "iana_records" VALUES(8064,6,NULL,'zib','zimbabwe sign language','1248825600',NULL,'zib','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8065,6,NULL,'zlm','malay (individual language)','1248825600',NULL,'zlm','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8066,6,NULL,'zmi','negeri sembilan malay','1248825600',NULL,'zmi','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8067,6,NULL,'zsl','zambian sign language','1248825600',NULL,'zsl','sgn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8068,1,NULL,'zsm','standard malay','1248825600',NULL,'zsm','ms',NULL,'ms',NULL,NULL); +INSERT INTO "iana_records" VALUES(8069,1,NULL,'arab','arabic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8070,1,NULL,'armi','imperial aramaic','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8071,1,NULL,'armn','armenian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8072,1,NULL,'avst','avestan','1185580800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8073,1,NULL,'bali','balinese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8074,1,NULL,'bamu','bamum','1248912000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8075,1,NULL,'bass','bassa vah','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8076,1,NULL,'batk','batak','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8077,1,NULL,'beng','bengali','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8078,1,NULL,'blis','blissymbols','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8079,1,NULL,'bopo','bopomofo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8080,1,NULL,'brah','brahmi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8081,1,NULL,'brai','braille','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8082,1,NULL,'bugi','buginese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8083,1,NULL,'buhd','buhid','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8084,1,NULL,'cakm','chakma','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8085,1,NULL,'cans','unified canadian aboriginal syllabics','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8086,1,NULL,'cari','carian','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8087,1,NULL,'cham','cham','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8088,1,NULL,'cher','cherokee','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8089,1,NULL,'cirt','cirth','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8090,1,NULL,'copt','coptic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8091,1,NULL,'cprt','cypriot','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8092,1,NULL,'cyrl','cyrillic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8093,1,NULL,'cyrs','cyrillic (old church slavonic variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8094,1,NULL,'deva','devanagari','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8094,1,NULL,'deva','nagari','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8095,1,NULL,'dsrt','deseret','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8095,1,NULL,'dsrt','mormon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8096,1,NULL,'egyd','egyptian demotic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8097,1,NULL,'egyh','egyptian hieratic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8098,1,NULL,'egyp','egyptian hieroglyphs','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8099,1,NULL,'ethi','ethiopic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8099,1,NULL,'ethi','ge''ez','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8099,1,NULL,'ethi','geʻez','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8100,1,NULL,'geok','khutsuri (asomtavruli and nuskhuri)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8101,1,NULL,'geor','georgian (mkhedruli)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8102,1,NULL,'glag','glagolitic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8103,1,NULL,'goth','gothic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8104,1,NULL,'gran','grantha','1260316800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8105,1,NULL,'grek','greek','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8106,1,NULL,'gujr','gujarati','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8107,1,NULL,'guru','gurmukhi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8108,1,NULL,'hang','hangeul','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8108,1,NULL,'hang','hangul','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8108,1,NULL,'hang','hangŭl','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8109,1,NULL,'hani','han','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8109,1,NULL,'hani','hanja','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8109,1,NULL,'hani','hanzi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8109,1,NULL,'hani','kanji','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8110,1,NULL,'hano','hanunoo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8110,1,NULL,'hano','hanunóo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8111,1,NULL,'hans','han (simplified variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8112,1,NULL,'hant','han (traditional variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8113,1,NULL,'hebr','hebrew','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8114,1,NULL,'hira','hiragana','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8115,1,NULL,'hmng','pahawh hmong','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8116,1,NULL,'hrkt','(alias for hiragana + katakana)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8117,1,NULL,'hung','old hungarian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8118,1,NULL,'inds','harappan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8118,1,NULL,'inds','indus','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8119,1,NULL,'ital','old italic (etruscan, oscan, etc.)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8120,1,NULL,'java','javanese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8121,1,NULL,'jpan','japanese (alias for han + hiragana + katakana)','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8122,1,NULL,'kali','kayah li','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8123,1,NULL,'kana','katakana','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8124,1,NULL,'khar','kharoshthi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8125,1,NULL,'khmr','khmer','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8126,1,NULL,'knda','kannada','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8127,1,NULL,'kore','korean (alias for hangul + han)','1183593600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8128,1,NULL,'kpel','kpelle','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8129,1,NULL,'kthi','kaithi','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8130,1,NULL,'lana','lanna','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8130,1,NULL,'lana','tai tham','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8131,1,NULL,'laoo','lao','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8132,1,NULL,'latf','latin (fraktur variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8133,1,NULL,'latg','latin (gaelic variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8134,1,NULL,'latn','latin','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8135,1,NULL,'lepc','lepcha','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8135,1,NULL,'lepc','róng','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8136,1,NULL,'limb','limbu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8137,1,NULL,'lina','linear a','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8138,1,NULL,'linb','linear b','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8139,1,NULL,'lisu','fraser','1236902400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8139,1,NULL,'lisu','lisu','1236902400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8140,1,NULL,'loma','loma','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8141,1,NULL,'lyci','lycian','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8142,1,NULL,'lydi','lydian','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8143,1,NULL,'mand','mandaean','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8143,1,NULL,'mand','mandaic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8144,1,NULL,'mani','manichaean','1185580800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8145,1,NULL,'maya','mayan hieroglyphs','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8146,1,NULL,'mend','mende','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8147,1,NULL,'merc','meroitic cursive','1260316800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8148,1,NULL,'mero','meroitic hieroglyphs','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8149,1,NULL,'mlym','malayalam','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8150,1,NULL,'mong','mongolian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8151,1,NULL,'moon','moon','1169769600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8151,1,NULL,'moon','moon code','1169769600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8151,1,NULL,'moon','moon script','1169769600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8151,1,NULL,'moon','moon type','1169769600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8152,1,NULL,'mtei','meetei','1169769600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8152,1,NULL,'mtei','meitei mayek','1169769600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8152,1,NULL,'mtei','meithei','1169769600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8153,1,NULL,'mymr','burmese','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8153,1,NULL,'mymr','myanmar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8154,1,NULL,'narb','ancient north arabian','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8154,1,NULL,'narb','old north arabian','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8155,1,NULL,'nbat','nabataean','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8156,1,NULL,'nkgb','''na-''khi ²ggŏ-¹baw','1236902400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8156,1,NULL,'nkgb','nakhi geba','1236902400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8156,1,NULL,'nkgb','naxi geba','1236902400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8157,1,NULL,'nkoo','n''ko','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8157,1,NULL,'nkoo','n’ko','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8158,1,NULL,'ogam','ogham','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8159,1,NULL,'olck','ol','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8159,1,NULL,'olck','ol cemet''','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8159,1,NULL,'olck','ol chiki','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8159,1,NULL,'olck','santali','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8160,1,NULL,'orkh','old turkic','1248912000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8160,1,NULL,'orkh','orkhon runic','1248912000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8161,1,NULL,'orya','oriya','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8162,1,NULL,'osma','osmanya','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8163,1,NULL,'palm','palmyrene','1270857600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8164,1,NULL,'perm','old permic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8165,1,NULL,'phag','phags-pa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8166,1,NULL,'phli','inscriptional pahlavi','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8167,1,NULL,'phlp','psalter pahlavi','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8168,1,NULL,'phlv','book pahlavi','1185580800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8169,1,NULL,'phnx','phoenician','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8170,1,NULL,'plrd','miao','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8170,1,NULL,'plrd','pollard','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8171,1,NULL,'prti','inscriptional parthian','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8172,1,NULL,'qaaa..qabx','private use','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8173,1,NULL,'rjng','kaganga','1161043200',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8173,1,NULL,'rjng','redjang','1161043200',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8173,1,NULL,'rjng','rejang','1161043200',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8174,1,NULL,'roro','rongorongo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8175,1,NULL,'runr','runic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8176,1,NULL,'samr','samaritan','1185580800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8177,1,NULL,'sara','sarati','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8178,1,NULL,'sarb','old south arabian','1248912000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8179,1,NULL,'saur','saurashtra','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8180,1,NULL,'sgnw','signwriting','1161043200',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8181,1,NULL,'shaw','shavian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8181,1,NULL,'shaw','shaw','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8182,1,NULL,'sinh','sinhala','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8183,1,NULL,'sund','sundanese','1153440000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8184,1,NULL,'sylo','syloti nagri','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8185,1,NULL,'syrc','syriac','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8186,1,NULL,'syre','syriac (estrangelo variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8187,1,NULL,'syrj','syriac (western variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8188,1,NULL,'syrn','syriac (eastern variant)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8189,1,NULL,'tagb','tagbanwa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8190,1,NULL,'tale','tai le','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8191,1,NULL,'talu','new tai lue','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8192,1,NULL,'taml','tamil','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8193,1,NULL,'tavt','tai viet','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8194,1,NULL,'telu','telugu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8195,1,NULL,'teng','tengwar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8196,1,NULL,'tfng','berber','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8196,1,NULL,'tfng','tifinagh','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8197,1,NULL,'tglg','alibata','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8197,1,NULL,'tglg','baybayin','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8197,1,NULL,'tglg','tagalog','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8198,1,NULL,'thaa','thaana','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8199,1,NULL,'thai','thai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8200,1,NULL,'tibt','tibetan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8201,1,NULL,'ugar','ugaritic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8202,1,NULL,'vaii','vai','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8203,1,NULL,'visp','visible speech','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8204,1,NULL,'wara','varang kshiti','1260316800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8204,1,NULL,'wara','warang citi','1260316800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8205,1,NULL,'xpeo','old persian','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8206,1,NULL,'xsux','sumero-akkadian cuneiform','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8207,1,NULL,'yiii','yi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8208,1,NULL,'zinh','code for inherited script','1238716800',NULL,NULL,NULL,NULL,NULL,NULL,'not intended for use as a language subtag'); +INSERT INTO "iana_records" VALUES(8209,1,NULL,'zmth','mathematical notation','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8210,1,NULL,'zsym','symbols','1196812800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8211,1,NULL,'zxxx','code for unwritten documents','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8212,1,NULL,'zyyy','code for undetermined script','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8213,2,NULL,'zzzz','code for uncoded script','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8214,2,NULL,'aa','private use','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8215,2,NULL,'ac','ascension island','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8216,2,NULL,'ad','andorra','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8217,2,NULL,'ae','united arab emirates','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8218,2,NULL,'af','afghanistan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8219,2,NULL,'ag','antigua and barbuda','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8220,2,NULL,'ai','anguilla','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8221,2,NULL,'al','albania','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8222,2,NULL,'am','armenia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8223,2,NULL,'an','netherlands antilles','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8224,2,NULL,'ao','angola','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8225,2,NULL,'aq','antarctica','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8226,2,NULL,'ar','argentina','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8227,2,NULL,'as','american samoa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8228,2,NULL,'at','austria','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8229,2,NULL,'au','australia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8230,2,NULL,'aw','aruba','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8231,2,NULL,'ax','Åland islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8232,2,NULL,'az','azerbaijan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8233,2,NULL,'ba','bosnia and herzegovina','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8234,2,NULL,'bb','barbados','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8235,2,NULL,'bd','bangladesh','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8236,2,NULL,'be','belgium','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8237,2,NULL,'bf','burkina faso','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8238,2,NULL,'bg','bulgaria','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8239,2,NULL,'bh','bahrain','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8240,2,NULL,'bi','burundi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8241,2,NULL,'bj','benin','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8242,2,NULL,'bl','saint barthélemy','1193961600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8243,2,NULL,'bm','bermuda','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8244,2,NULL,'bn','brunei darussalam','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8245,2,NULL,'bo','bolivia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8246,2,NULL,'br','brazil','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8247,2,NULL,'bs','bahamas','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8248,2,NULL,'bt','bhutan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8249,2,NULL,'bu','burma','1129420800',628819200,'mm',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8250,2,NULL,'bv','bouvet island','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8251,2,NULL,'bw','botswana','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8252,2,NULL,'by','belarus','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8253,2,NULL,'bz','belize','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8254,2,NULL,'ca','canada','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8255,2,NULL,'cc','cocos (keeling) islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8256,2,NULL,'cd','the democratic republic of the congo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8257,2,NULL,'cf','central african republic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8258,2,NULL,'cg','congo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8259,2,NULL,'ch','switzerland','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8260,2,NULL,'ci','côte d''ivoire','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8261,2,NULL,'ck','cook islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8262,2,NULL,'cl','chile','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8263,2,NULL,'cm','cameroon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8264,2,NULL,'cn','china','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8265,2,NULL,'co','colombia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8266,2,NULL,'cp','clipperton island','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8267,2,NULL,'cr','costa rica','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8268,2,NULL,'cs','serbia and montenegro','1129420800',1160006400,NULL,NULL,NULL,NULL,NULL,'see rs for serbia or me for montenegro'); +INSERT INTO "iana_records" VALUES(8269,2,NULL,'cu','cuba','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8270,2,NULL,'cv','cape verde','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8271,2,NULL,'cx','christmas island','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8272,2,NULL,'cy','cyprus','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8273,2,NULL,'cz','czech republic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8274,2,NULL,'dd','german democratic republic','1129420800',657244800,'de',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8275,2,NULL,'de','germany','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8276,2,NULL,'dg','diego garcia','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8277,2,NULL,'dj','djibouti','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8278,2,NULL,'dk','denmark','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8279,2,NULL,'dm','dominica','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8280,2,NULL,'do','dominican republic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8281,2,NULL,'dz','algeria','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8282,2,NULL,'ea','ceuta, melilla','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8283,2,NULL,'ec','ecuador','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8284,2,NULL,'ee','estonia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8285,2,NULL,'eg','egypt','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8286,2,NULL,'eh','western sahara','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8287,2,NULL,'er','eritrea','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8288,2,NULL,'es','spain','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8289,2,NULL,'et','ethiopia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8290,2,NULL,'eu','european union','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8291,2,NULL,'fi','finland','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8292,2,NULL,'fj','fiji','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8293,2,NULL,'fk','falkland islands (malvinas)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8294,2,NULL,'fm','federated states of micronesia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8295,2,NULL,'fo','faroe islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8296,2,NULL,'fr','france','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8297,2,NULL,'fx','metropolitan france','1129420800',868838400,'fr',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8298,2,NULL,'ga','gabon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8299,2,NULL,'gb','united kingdom','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,'as of 2006-03-29 gb no longer includes the channel islands and isle of man; see gg, je, im'); +INSERT INTO "iana_records" VALUES(8300,2,NULL,'gd','grenada','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8301,2,NULL,'ge','georgia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8302,2,NULL,'gf','french guiana','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8303,2,NULL,'gg','guernsey','1143590400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8304,2,NULL,'gh','ghana','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8305,2,NULL,'gi','gibraltar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8306,2,NULL,'gl','greenland','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8307,2,NULL,'gm','gambia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8308,2,NULL,'gn','guinea','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8309,2,NULL,'gp','guadeloupe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8310,2,NULL,'gq','equatorial guinea','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8311,2,NULL,'gr','greece','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8312,2,NULL,'gs','south georgia and the south sandwich islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8313,2,NULL,'gt','guatemala','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8314,2,NULL,'gu','guam','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8315,2,NULL,'gw','guinea-bissau','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8316,2,NULL,'gy','guyana','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8317,2,NULL,'hk','hong kong','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8318,2,NULL,'hm','heard island and mcdonald islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8319,2,NULL,'hn','honduras','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8320,2,NULL,'hr','croatia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8321,2,NULL,'ht','haiti','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8322,2,NULL,'hu','hungary','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8323,2,NULL,'ic','canary islands','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8324,2,NULL,'id','indonesia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8325,2,NULL,'ie','ireland','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8326,2,NULL,'il','israel','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8327,2,NULL,'im','isle of man','1143590400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8328,2,NULL,'in','india','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8329,2,NULL,'io','british indian ocean territory','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8330,2,NULL,'iq','iraq','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8331,2,NULL,'ir','islamic republic of iran','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8332,2,NULL,'is','iceland','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8333,2,NULL,'it','italy','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8334,2,NULL,'je','jersey','1143590400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8335,2,NULL,'jm','jamaica','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8336,2,NULL,'jo','jordan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8337,2,NULL,'jp','japan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8338,2,NULL,'ke','kenya','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8339,2,NULL,'kg','kyrgyzstan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8340,2,NULL,'kh','cambodia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8341,2,NULL,'ki','kiribati','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8342,2,NULL,'km','comoros','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8343,2,NULL,'kn','saint kitts and nevis','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8344,2,NULL,'kp','democratic people''s republic of korea','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8345,2,NULL,'kr','republic of korea','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8346,2,NULL,'kw','kuwait','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8347,2,NULL,'ky','cayman islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8348,2,NULL,'kz','kazakhstan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8349,2,NULL,'la','lao people''s democratic republic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8350,2,NULL,'lb','lebanon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8351,2,NULL,'lc','saint lucia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8352,2,NULL,'li','liechtenstein','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8353,2,NULL,'lk','sri lanka','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8354,2,NULL,'lr','liberia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8355,2,NULL,'ls','lesotho','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8356,2,NULL,'lt','lithuania','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8357,2,NULL,'lu','luxembourg','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8358,2,NULL,'lv','latvia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8359,2,NULL,'ly','libyan arab jamahiriya','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8360,2,NULL,'ma','morocco','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8361,2,NULL,'mc','monaco','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8362,2,NULL,'md','moldova','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8363,2,NULL,'me','montenegro','1160006400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8364,2,NULL,'mf','saint martin','1193961600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8365,2,NULL,'mg','madagascar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8366,2,NULL,'mh','marshall islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8367,2,NULL,'mk','the former yugoslav republic of macedonia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8368,2,NULL,'ml','mali','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8369,2,NULL,'mm','myanmar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8370,2,NULL,'mn','mongolia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8371,2,NULL,'mo','macao','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8372,2,NULL,'mp','northern mariana islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8373,2,NULL,'mq','martinique','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8374,2,NULL,'mr','mauritania','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8375,2,NULL,'ms','montserrat','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8376,2,NULL,'mt','malta','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8377,2,NULL,'mu','mauritius','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8378,2,NULL,'mv','maldives','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8379,2,NULL,'mw','malawi','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8380,2,NULL,'mx','mexico','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8381,2,NULL,'my','malaysia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8382,2,NULL,'mz','mozambique','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8383,2,NULL,'na','namibia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8384,2,NULL,'nc','new caledonia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8385,2,NULL,'ne','niger','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8386,2,NULL,'nf','norfolk island','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8387,2,NULL,'ng','nigeria','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8388,2,NULL,'ni','nicaragua','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8389,2,NULL,'nl','netherlands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8390,2,NULL,'no','norway','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8391,2,NULL,'np','nepal','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8392,2,NULL,'nr','nauru','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8393,2,NULL,'nt','neutral zone','1129420800',742435200,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8394,2,NULL,'nu','niue','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8395,2,NULL,'nz','new zealand','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8396,2,NULL,'om','oman','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8397,2,NULL,'pa','panama','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8398,2,NULL,'pe','peru','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8399,2,NULL,'pf','french polynesia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8400,2,NULL,'pg','papua new guinea','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8401,2,NULL,'ph','philippines','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8402,2,NULL,'pk','pakistan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8403,2,NULL,'pl','poland','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8404,2,NULL,'pm','saint pierre and miquelon','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8405,2,NULL,'pn','pitcairn','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8406,2,NULL,'pr','puerto rico','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8407,2,NULL,'ps','occupied palestinian territory','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8408,2,NULL,'pt','portugal','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8409,2,NULL,'pw','palau','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8410,2,NULL,'py','paraguay','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8411,2,NULL,'qa','qatar','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8412,2,NULL,'qm..qz','private use','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8413,2,NULL,'re','réunion','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8414,2,NULL,'ro','romania','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8415,2,NULL,'rs','serbia','1160006400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8416,2,NULL,'ru','russian federation','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8417,2,NULL,'rw','rwanda','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8418,2,NULL,'sa','saudi arabia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8419,2,NULL,'sb','solomon islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8420,2,NULL,'sc','seychelles','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8421,2,NULL,'sd','sudan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8422,2,NULL,'se','sweden','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8423,2,NULL,'sg','singapore','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8424,2,NULL,'sh','saint helena, ascension and tristan da cunha','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8425,2,NULL,'si','slovenia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8426,2,NULL,'sj','svalbard and jan mayen','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8427,2,NULL,'sk','slovakia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8428,2,NULL,'sl','sierra leone','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8429,2,NULL,'sm','san marino','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8430,2,NULL,'sn','senegal','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8431,2,NULL,'so','somalia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8432,2,NULL,'sr','suriname','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8433,2,NULL,'st','sao tome and principe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8434,2,NULL,'su','union of soviet socialist republics','1129420800',715132800,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8435,2,NULL,'sv','el salvador','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8436,2,NULL,'sy','syrian arab republic','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8437,2,NULL,'sz','swaziland','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8438,2,NULL,'ta','tristan da cunha','1248825600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8439,2,NULL,'tc','turks and caicos islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8440,2,NULL,'td','chad','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8441,2,NULL,'tf','french southern territories','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8442,2,NULL,'tg','togo','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8443,2,NULL,'th','thailand','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8444,2,NULL,'tj','tajikistan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8445,2,NULL,'tk','tokelau','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8446,2,NULL,'tl','timor-leste','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8447,2,NULL,'tm','turkmenistan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8448,2,NULL,'tn','tunisia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8449,2,NULL,'to','tonga','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8450,2,NULL,'tp','east timor','1129420800',1021852800,'tl',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8451,2,NULL,'tr','turkey','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8452,2,NULL,'tt','trinidad and tobago','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8453,2,NULL,'tv','tuvalu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8454,2,NULL,'tw','taiwan, province of china','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8455,2,NULL,'tz','united republic of tanzania','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8456,2,NULL,'ua','ukraine','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8457,2,NULL,'ug','uganda','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8458,2,NULL,'um','united states minor outlying islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8459,2,NULL,'us','united states','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8460,2,NULL,'uy','uruguay','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8461,2,NULL,'uz','uzbekistan','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8462,2,NULL,'va','holy see (vatican city state)','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8463,2,NULL,'vc','saint vincent and the grenadines','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8464,2,NULL,'ve','venezuela','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8465,2,NULL,'vg','british virgin islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8466,2,NULL,'vi','u.s. virgin islands','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8467,2,NULL,'vn','viet nam','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8468,2,NULL,'vu','vanuatu','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8469,2,NULL,'wf','wallis and futuna','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8470,2,NULL,'ws','samoa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8471,2,NULL,'xa..xz','private use','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8472,2,NULL,'yd','democratic yemen','1129420800',650592000,'ye',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8473,2,NULL,'ye','yemen','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8474,2,NULL,'yt','mayotte','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8475,2,NULL,'yu','yugoslavia','1129420800',1058918400,NULL,NULL,NULL,NULL,NULL,'see ba, hr, me, mk, rs, or si'); +INSERT INTO "iana_records" VALUES(8476,2,NULL,'za','south africa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8477,2,NULL,'zm','zambia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8478,2,NULL,'zr','zaire','1129420800',868838400,'cd',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8479,2,NULL,'zw','zimbabwe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8480,2,NULL,'zz','private use','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8481,2,NULL,'001','world','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8482,2,NULL,'002','africa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8483,2,NULL,'005','south america','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8484,2,NULL,'009','oceania','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8485,2,NULL,'011','western africa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8486,2,NULL,'013','central america','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8487,2,NULL,'014','eastern africa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8488,2,NULL,'015','northern africa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8489,2,NULL,'017','middle africa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8490,2,NULL,'018','southern africa','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8491,2,NULL,'019','americas','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8492,2,NULL,'021','northern america','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8493,2,NULL,'029','caribbean','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8494,2,NULL,'030','eastern asia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8495,2,NULL,'034','southern asia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8496,2,NULL,'035','south-eastern asia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8497,2,NULL,'039','southern europe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8498,2,NULL,'053','australia and new zealand','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8499,2,NULL,'054','melanesia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8500,2,NULL,'057','micronesia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8501,2,NULL,'061','polynesia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8502,2,NULL,'142','asia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8503,2,NULL,'143','central asia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8504,2,NULL,'145','western asia','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8505,2,NULL,'150','europe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8506,2,NULL,'151','eastern europe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8507,2,NULL,'154','northern europe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8508,2,NULL,'155','western europe','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8509,3,NULL,'419','latin america and the caribbean','1129420800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8510,3,NULL,'1606nict','late middle french (to 1606)','1174348800',NULL,NULL,'frm',NULL,NULL,NULL,'16th century french as in jean nicot, "thresor de la langue francoyse", 1606, but also including some french similar to that of rabelais'); +INSERT INTO "iana_records" VALUES(8511,3,NULL,'1694acad','early modern french','1174348800',NULL,NULL,'fr',NULL,NULL,NULL,'17th century french, as catalogued in the "dictionnaire de l''académie françoise", 4eme ed. 1694; frequently includes elements of middle french, as this is a transitional period'); +INSERT INTO "iana_records" VALUES(8512,3,NULL,'1901','traditional german orthography','1129420800',NULL,NULL,'de',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8513,3,NULL,'1959acad','"academic" ("governmental") variant of belarusian as codified in 1959','1222732800',NULL,NULL,'be',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8514,3,NULL,'1994','standardized resian orthography','1185580800',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'for standardized resian an orthography was published in 1994.'); +INSERT INTO "iana_records" VALUES(8514,3,NULL,'1994','standardized resian orthography','1185580800',NULL,NULL,'sl-rozaj-biske',NULL,NULL,NULL,'for standardized resian an orthography was published in 1994.'); +INSERT INTO "iana_records" VALUES(8514,3,NULL,'1994','standardized resian orthography','1185580800',NULL,NULL,'sl-rozaj-njiva',NULL,NULL,NULL,'for standardized resian an orthography was published in 1994.'); +INSERT INTO "iana_records" VALUES(8514,3,NULL,'1994','standardized resian orthography','1185580800',NULL,NULL,'sl-rozaj-osojs',NULL,NULL,NULL,'for standardized resian an orthography was published in 1994.'); +INSERT INTO "iana_records" VALUES(8514,3,NULL,'1994','standardized resian orthography','1185580800',NULL,NULL,'sl-rozaj-solba',NULL,NULL,NULL,'for standardized resian an orthography was published in 1994.'); +INSERT INTO "iana_records" VALUES(8515,3,NULL,'1996','german orthography of 1996','1129420800',NULL,NULL,'de',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8516,3,NULL,'alalc97','ala-lc romanization, 1997 edition','1260316800',NULL,NULL,NULL,NULL,NULL,NULL,'romanizations recommended by the american library association and the library of congress, in "ala-lc romanization tables: transliteration schemes for non-roman scripts" (1997), isbn 978-0-8444-0940-5.'); +INSERT INTO "iana_records" VALUES(8517,3,NULL,'aluku','aluku dialect','1252108800',NULL,NULL,'djk',NULL,NULL,NULL,'aluku dialect of the "busi nenge tongo" english-based creole continuum in eastern suriname and western french guiana'); +INSERT INTO "iana_records" VALUES(8517,3,NULL,'aluku','boni dialect','1252108800',NULL,NULL,'djk',NULL,NULL,NULL,'aluku dialect of the "busi nenge tongo" english-based creole continuum in eastern suriname and western french guiana'); +INSERT INTO "iana_records" VALUES(8518,3,NULL,'arevela','eastern armenian','1158537600',NULL,NULL,'hy',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8519,3,NULL,'arevmda','western armenian','1158537600',NULL,NULL,'hy',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'az',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'ba',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'crh',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'kk',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'krc',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'ky',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'sah',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'tk',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'tt',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8520,3,NULL,'baku1926','unified turkic latin alphabet (historical)','1176854400',NULL,NULL,'uz',NULL,NULL,NULL,'denotes alphabet used in turkic republics/regions of the former ussr in late 1920s, and throughout 1930s, which aspired to represent equivalent phonemes in a unified fashion. also known as: new turkic alphabet; birlәşdirilmiş jeni tyrk Әlifbasь (birlesdirilmis jeni tyrk elifbasi); jaŋalif (janalif).'); +INSERT INTO "iana_records" VALUES(8521,3,NULL,'biscayan','biscayan dialect of basque','1271116800',NULL,NULL,'eu',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8522,3,NULL,'biske','the bila dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of san giorgio/bila is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8522,3,NULL,'biske','the san giorgio dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of san giorgio/bila is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8523,3,NULL,'boont','boontling','1158537600',NULL,NULL,'en',NULL,NULL,NULL,'jargon embedded in american english'); +INSERT INTO "iana_records" VALUES(8524,3,NULL,'fonipa','international phonetic alphabet','1165795200',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8525,3,NULL,'fonupa','uralic phonetic alphabet','1165795200',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8526,3,NULL,'hepburn','hepburn romanization','1254355200',NULL,NULL,'ja-latn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8527,3,NULL,'heploc','hepburn romanization, library of congress method','1254355200',1265500800,'alalc97','ja-latn-hepburn',NULL,NULL,NULL,'preferred tag is ja-latn-alalc97'); +INSERT INTO "iana_records" VALUES(8528,3,NULL,'hognorsk','norwegian in høgnorsk (high norwegian) orthography','1262390400',NULL,NULL,'nn',NULL,NULL,NULL,'norwegian following ivar aasen''s orthographical principles, including modern usage.'); +INSERT INTO "iana_records" VALUES(8529,3,NULL,'jauer','jauer dialect of romansh','1277769600',NULL,NULL,'rm',NULL,NULL,NULL,'the spoken dialect of the val müstair, which has no written standard.'); +INSERT INTO "iana_records" VALUES(8530,3,NULL,'kkcor','common cornish orthography of revived cornish','1223942400',NULL,NULL,'kw',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8531,3,NULL,'lipaw','the lipovaz dialect of resian','1186790400',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of lipovaz/lipovec is one of the minor local dialects of resian'); +INSERT INTO "iana_records" VALUES(8531,3,NULL,'lipaw','the lipovec dialect of resian','1186790400',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of lipovaz/lipovec is one of the minor local dialects of resian'); +INSERT INTO "iana_records" VALUES(8532,3,NULL,'monoton','monotonic greek','1165795200',NULL,NULL,'el',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8533,3,NULL,'ndyuka','aukan dialect','1252108800',NULL,NULL,'djk',NULL,NULL,NULL,'ndyuka dialect of the "busi nenge tongo" english-based creole continuum in eastern suriname and western french guiana'); +INSERT INTO "iana_records" VALUES(8533,3,NULL,'ndyuka','ndyuka dialect','1252108800',NULL,NULL,'djk',NULL,NULL,NULL,'ndyuka dialect of the "busi nenge tongo" english-based creole continuum in eastern suriname and western french guiana'); +INSERT INTO "iana_records" VALUES(8534,3,NULL,'nedis','nadiza dialect','1129420800',NULL,NULL,'sl',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8534,3,NULL,'nedis','natisone dialect','1129420800',NULL,NULL,'sl',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8535,3,NULL,'njiva','the gniva dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of gniva/njiva is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8535,3,NULL,'njiva','the njiva dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of gniva/njiva is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8536,3,NULL,'osojs','the oseacco dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of oseacco/osojane is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8536,3,NULL,'osojs','the osojane dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of oseacco/osojane is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8537,3,NULL,'pamaka','pamaka dialect','1252108800',NULL,NULL,'djk',NULL,NULL,NULL,'pamaka dialect of the "busi nenge tongo" english-based creole continuum in eastern suriname and western french guiana'); +INSERT INTO "iana_records" VALUES(8538,3,NULL,'pinyin','pinyin romanization','1223942400',NULL,NULL,'bo-latn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8538,3,NULL,'pinyin','pinyin romanization','1223942400',NULL,NULL,'zh-latn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8539,3,NULL,'polyton','polytonic greek','1165795200',NULL,NULL,'el',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8540,3,NULL,'puter','puter idiom of romansh','1277769600',NULL,NULL,'rm',NULL,NULL,NULL,'puter is one of the five traditional written standards or "idioms" of the romansh language.'); +INSERT INTO "iana_records" VALUES(8541,3,NULL,'rozaj','resian','1129420800',NULL,NULL,'sl',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8541,3,NULL,'rozaj','resianic','1129420800',NULL,NULL,'sl',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8541,3,NULL,'rozaj','rezijan','1129420800',NULL,NULL,'sl',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8542,3,NULL,'rumgr','rumantsch grischun','1277769600',NULL,NULL,'rm',NULL,NULL,NULL,'supraregional romansh written standard'); +INSERT INTO "iana_records" VALUES(8543,3,NULL,'scotland','scottish standard english','1188518400',NULL,NULL,'en',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8544,3,NULL,'scouse','scouse','1158537600',NULL,NULL,'en',NULL,NULL,NULL,'english liverpudlian dialect known as ''scouse'''); +INSERT INTO "iana_records" VALUES(8545,3,NULL,'solba','the solbica dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of stolvizza/solbica is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8545,3,NULL,'solba','the stolvizza dialect of resian','1183593600',NULL,NULL,'sl-rozaj',NULL,NULL,NULL,'the dialect of stolvizza/solbica is one of the four major local dialects of resian'); +INSERT INTO "iana_records" VALUES(8546,3,NULL,'surmiran','surmiran idiom of romansh','1277769600',NULL,NULL,'rm',NULL,NULL,NULL,'surmiran is one of the five traditional written standards or "idioms" of the romansh language.'); +INSERT INTO "iana_records" VALUES(8547,3,NULL,'sursilv','sursilvan idiom of romansh','1277769600',NULL,NULL,'rm',NULL,NULL,NULL,'sursilvan is one of the five traditional written standards or "idioms" of the romansh language.'); +INSERT INTO "iana_records" VALUES(8548,3,NULL,'sutsilv','sutsilvan idiom of romansh','1277769600',NULL,NULL,'rm',NULL,NULL,NULL,'sutsilvan is one of the five traditional written standards or "idioms" of the romansh language.'); +INSERT INTO "iana_records" VALUES(8549,3,NULL,'tarask','belarusian in taraskievica orthography','1177632000',NULL,NULL,'be',NULL,NULL,NULL,'the subtag represents branislau taraskievic''s belarusian orthography as published in "bielaruski klasycny pravapis" by juras buslakou, vincuk viacorka, zmicier sanko, and zmicier sauka (vilnia- miensk 2005).'); +INSERT INTO "iana_records" VALUES(8550,3,NULL,'uccor','unified cornish orthography of revived cornish','1223942400',NULL,NULL,'kw',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8551,3,NULL,'ucrcor','unified cornish revised orthography of revived cornish','1223942400',NULL,NULL,'kw',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8552,3,NULL,'ulster','ulster dialect of scots','1270857600',NULL,NULL,'sco',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8553,3,NULL,'valencia','valencian','1173139200',NULL,NULL,'ca',NULL,NULL,NULL,'variety spoken in the "comunidad valenciana" region of spain, where it is co-official with spanish.'); +INSERT INTO "iana_records" VALUES(8554,3,NULL,'vallader','vallader idiom of romansh','1277769600',NULL,NULL,'rm',NULL,NULL,NULL,'vallader is one of the five traditional written standards or "idioms" of the romansh language.'); +INSERT INTO "iana_records" VALUES(8555,4,NULL,'wadegile','wade-giles romanization','1222992000',NULL,NULL,'zh-latn',NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8556,4,'art-lojban',NULL,'lojban','1005436800',1062460800,'jbo',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8557,4,'cel-gaulish',NULL,'gaulish','990748800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8558,4,'en-gb-oed',NULL,'english, oxford english dictionary spelling','1057708800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8559,4,'i-ami',NULL,'amis','927590400',1248825600,'ami',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8560,4,'i-bnn',NULL,'bunun','927590400',1248825600,'bnn',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8561,4,'i-default',NULL,'default language','889488000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8562,4,'i-enochian',NULL,'enochian','1025654400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8563,4,'i-hak',NULL,'hakka','917740800',947462400,'hak',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8564,4,'i-klingon',NULL,'klingon','927676800',1077580800,'tlh',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8565,4,'i-lux',NULL,'luxembourgish','874627200',905299200,'lb',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8566,4,'i-mingo',NULL,'mingo','874627200',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8567,4,'i-navajo',NULL,'navajo','874627200',950832000,'nv',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8568,4,'i-pwn',NULL,'paiwan','927590400',1248825600,'pwn',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8569,4,'i-tao',NULL,'tao','927590400',1248825600,'tao',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8570,4,'i-tay',NULL,'tayal','927590400',1248825600,'tay',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8571,4,'i-tsu',NULL,'tsou','927590400',1248825600,'tsu',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8572,4,'no-bok',NULL,'norwegian bokmal','809136000',950832000,'nb',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8573,4,'no-nyn',NULL,'norwegian nynorsk','809136000',950832000,'nn',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8574,4,'sgn-be-fr',NULL,'belgian-french sign language','1005436800',1248825600,'sfb',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8575,4,'sgn-be-nl',NULL,'belgian-flemish sign language','1005436800',1248825600,'vgt',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8576,4,'sgn-ch-de',NULL,'swiss german sign language','1005436800',1248825600,'sgg',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8577,4,'zh-guoyu',NULL,'mandarin or standard chinese','945475200',1121385600,'cmn',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8578,4,'zh-hakka',NULL,'hakka','945475200',1248825600,'hak',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8579,4,'zh-min',NULL,'min, fuzhou, hokkien, amoy, or taiwanese','945475200',1248825600,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8580,4,'zh-min-nan',NULL,'minnan, hokkien, amoy, taiwanese, southern min, southern fujian, hoklo, southern fukien, ho-lo','985564800',1248825600,'nan',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8581,5,'zh-xiang',NULL,'xiang or hunanese','945475200',1248825600,'hsn',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8582,5,'az-arab',NULL,'azerbaijani in arabic script','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8583,5,'az-cyrl',NULL,'azerbaijani in cyrillic script','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8584,5,'az-latn',NULL,'azerbaijani in latin script','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8585,5,'be-latn',NULL,'belarusian in latin script','1104969600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8586,5,'bs-cyrl',NULL,'bosnian in cyrillic script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8587,5,'bs-latn',NULL,'bosnian in latin script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8588,5,'de-1901',NULL,'german, traditional orthography','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8589,5,'de-1996',NULL,'german, orthography of 1996','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8590,5,'de-at-1901',NULL,'german, austrian variant, traditional orthography','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8591,5,'de-at-1996',NULL,'german, austrian variant, orthography of 1996','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8592,5,'de-ch-1901',NULL,'german, swiss variant, traditional orthography','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8593,5,'de-ch-1996',NULL,'german, swiss variant, orthography of 1996','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8594,5,'de-de-1901',NULL,'german, german variant, traditional orthography','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8595,5,'de-de-1996',NULL,'german, german variant, orthography of 1996','995328000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8596,5,'en-boont',NULL,'boontling','1045180800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8597,5,'en-scouse',NULL,'scouse','959212800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8598,5,'es-419',NULL,'latin american spanish','1121385600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8599,5,'iu-cans',NULL,'inuktitut in canadian aboriginal syllabic script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8600,5,'iu-latn',NULL,'inuktitut in latin script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8601,5,'mn-cyrl',NULL,'mongolian in cyrillic script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8602,5,'mn-mong',NULL,'mongolian in mongolian script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8603,5,'sgn-br',NULL,'brazilian sign language','1005436800',1248825600,'bzs',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8604,5,'sgn-co',NULL,'colombian sign language','1005436800',1248825600,'csn',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8605,5,'sgn-de',NULL,'german sign language','1005436800',1248825600,'gsg',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8606,5,'sgn-dk',NULL,'danish sign language','1005436800',1248825600,'dsl',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8607,5,'sgn-es',NULL,'spanish sign language','1005436800',1248825600,'ssp',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8608,5,'sgn-fr',NULL,'french sign language','1005436800',1248825600,'fsl',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8609,5,'sgn-gb',NULL,'british sign language','983491200',1248825600,'bfi',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8610,5,'sgn-gr',NULL,'greek sign language','1005436800',1248825600,'gss',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8611,5,'sgn-ie',NULL,'irish sign language','983491200',1248825600,'isg',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8612,5,'sgn-it',NULL,'italian sign language','1005436800',1248825600,'ise',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8613,5,'sgn-jp',NULL,'japanese sign language','1005436800',1248825600,'jsl',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8614,5,'sgn-mx',NULL,'mexican sign language','1005436800',1248825600,'mfs',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8615,5,'sgn-ni',NULL,'nicaraguan sign language','983491200',1248825600,'ncs',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8616,5,'sgn-nl',NULL,'dutch sign language','1005436800',1248825600,'dse',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8617,5,'sgn-no',NULL,'norwegian sign language','1005436800',1248825600,'nsl',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8618,5,'sgn-pt',NULL,'portuguese sign language','1005436800',1248825600,'psr',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8619,5,'sgn-se',NULL,'swedish sign language','1005436800',1248825600,'swl',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8620,5,'sgn-us',NULL,'american sign language','983491200',1248825600,'ase',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8621,5,'sgn-za',NULL,'south african sign language','1005436800',1248825600,'sfs',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8622,5,'sl-nedis',NULL,'natisone dialect, nadiza dialect','1086048000',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8623,5,'sl-rozaj',NULL,'resian, resianic, rezijan','1065657600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8624,5,'sr-cyrl',NULL,'serbian in cyrillic script','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8625,5,'sr-latn',NULL,'serbian in latin script','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8626,5,'tg-arab',NULL,'tajik in arabic script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8627,5,'tg-cyrl',NULL,'tajik in cyrillic script','1108598400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8628,5,'uz-cyrl',NULL,'uzbek in cyrillic script','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8629,5,'uz-latn',NULL,'uzbek in latin script','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8630,5,'yi-latn',NULL,'yiddish, in latin script','1041897600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8631,5,'zh-cmn',NULL,'mandarin chinese','1121385600',1248825600,'cmn',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8632,5,'zh-cmn-hans',NULL,'mandarin chinese (simplified)','1121385600',1248825600,'cmn-hans',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8633,5,'zh-cmn-hant',NULL,'mandarin chinese (traditional)','1121385600',1248825600,'cmn-hant',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8634,5,'zh-gan',NULL,'kan or gan','945475200',1248825600,'gan',NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8635,5,'zh-hans',NULL,'simplified chinese','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8636,5,'zh-hans-cn',NULL,'prc mainland chinese in simplified script','1113350400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8637,5,'zh-hans-hk',NULL,'hong kong chinese in simplified script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8638,5,'zh-hans-mo',NULL,'macao chinese in simplified script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8639,5,'zh-hans-sg',NULL,'singapore chinese in simplified script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8640,5,'zh-hans-tw',NULL,'taiwan chinese in simplified script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8641,5,'zh-hant',NULL,'traditional chinese','1054252800',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8642,5,'zh-hant-cn',NULL,'prc mainland chinese in traditional script','1113350400',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8643,5,'zh-hant-hk',NULL,'hong kong chinese in traditional script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8644,5,'zh-hant-mo',NULL,'macao chinese in traditional script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8645,5,'zh-hant-sg',NULL,'singapore chinese in traditional script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8646,5,'zh-hant-tw',NULL,'taiwan chinese in traditional script','1113177600',NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO "iana_records" VALUES(8647,5,'zh-wuu',NULL,'shanghaiese or wu','945475200',1248825600,'wuu',NULL,NULL,NULL,NULL,NULL); +COMMIT; ) diff --git a/modules/i18n/dao/orm/orm_generator_i18n.h b/modules/i18n/dao/orm/orm_generator_i18n.h new file mode 100644 index 0000000..53cfea3 --- /dev/null +++ b/modules/i18n/dao/orm/orm_generator_i18n.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ORM_GENERATOR_I18N_H_ +#define _ORM_GENERATOR_I18N_H_ + +#define ORM_GENERATOR_DATABASE_NAME i18n_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif // _ORM_GENERATOR_I18N_H_ diff --git a/modules/i18n/dao/orm/version_db b/modules/i18n/dao/orm/version_db new file mode 100644 index 0000000..7e20d8d --- /dev/null +++ b/modules/i18n/dao/orm/version_db @@ -0,0 +1,5 @@ +SQL( + BEGIN TRANSACTION; + CREATE TABLE DB_CHECKSUM (version INT); + COMMIT; +) diff --git a/modules/i18n/dao/src/i18n_dao_read_only.cpp b/modules/i18n/dao/src/i18n_dao_read_only.cpp new file mode 100644 index 0000000..19822ff --- /dev/null +++ b/modules/i18n/dao/src/i18n_dao_read_only.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the definition of i18n dao namespace. + * + * @file i18n_dao_read_only.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file contains the definition of i18n dao + */ + +#include +#include + +#include + +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::i18n; + +namespace I18n { +namespace DB { +namespace I18nDAOReadOnly { +bool IsValidSubTag(const DPL::String& tag, int type) +{ + I18N_DB_SELECT(select, iana_records) + select->Where(And(Equals(tag), + Equals(type))); + return !select->GetRowList().empty(); +} +} +} +} diff --git a/modules/i18n/dao/src/i18n_database.cpp b/modules/i18n/dao/src/i18n_database.cpp new file mode 100644 index 0000000..e1a1fc5 --- /dev/null +++ b/modules/i18n/dao/src/i18n_database.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +namespace I18n { +namespace DB { +namespace Interface { +namespace { +const char* const I18N_DB_FILE_PATH = "/opt/usr/dbspace/.wrt_i18n.db"; + +DPL::DB::SqlConnection::Flag::Type I18N_DB_FLAGS = + DPL::DB::SqlConnection::Flag::UseLucene; +} + +DPL::Mutex g_dbQueriesMutex; +DPL::DB::ThreadDatabaseSupport g_dbInterface(I18N_DB_FILE_PATH, + I18N_DB_FLAGS); + +void attachDatabaseRO() +{ + g_dbInterface.AttachToThread(DPL::DB::SqlConnection::Flag::RO); +} + +void detachDatabase() +{ + g_dbInterface.DetachFromThread(); +} +} //namespace Interface +} //namespace DB +} //namespace I18n diff --git a/modules/localization/config.cmake b/modules/localization/config.cmake new file mode 100644 index 0000000..80f77c4 --- /dev/null +++ b/modules/localization/config.cmake @@ -0,0 +1,39 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Soyoung Kim(sy037.kim@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_LOCALIZATION_SOURCES + ${PROJECT_SOURCE_DIR}/modules/localization/src/w3c_file_localization.cpp + ${PROJECT_SOURCE_DIR}/modules/localization/src/LanguageTagsProvider.cpp + PARENT_SCOPE +) + + +SET(DPL_LOCALIZATION_HEADERS + ${PROJECT_SOURCE_DIR}/modules/localization/include/dpl/localization/localization_utils.h + ${PROJECT_SOURCE_DIR}/modules/localization/include/dpl/localization/w3c_file_localization.h + ${PROJECT_SOURCE_DIR}/modules/localization/include/LanguageTagsProvider.h + PARENT_SCOPE +) + +SET(DPL_LOCALIZATION_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/localization/include + PARENT_SCOPE +) diff --git a/modules/localization/include/LanguageTagsProvider.h b/modules/localization/include/LanguageTagsProvider.h new file mode 100644 index 0000000..529101f --- /dev/null +++ b/modules/localization/include/LanguageTagsProvider.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file LanguageTagsProvider.h + * @author Marcin Kaminski (marcin.ka@samsung.com) + * @version 1.0 + */ + +#ifndef LANGUAGETAGSPROVIDER_H +#define LANGUAGETAGSPROVIDER_H + +#include +#include +#include +#include + +typedef std::list LanguageTags; + +class LanguageTagsProvider +{ + public: + /* + * Get list of currently set language tags + */ + const LanguageTags getLanguageTags() const; + + /* + * Set new language tags (other than based on system locales) + */ + void setLanguageTags(const LanguageTags& taglist); + + /* + * Set language tags from given locales. + * Supported format is: xx[-yy[-zz]][.encoding] + */ + void setLanguageTagsFromLocales(const char* locales); + + /* + * Set language tags based on system language settings + */ + void resetLanguageTags(); + + /* + * Adds default widget locales to language tags if + * it doesn't exist within actual tags. + * Default locales i added: + * - at the beginning if less then 2 tags exists on list + * - just before empty ("") locales - pre-last position + * - at the end if last position is not empty locale + */ + void addWidgetDefaultLocales(const DPL::String&); + + /* + * Function converts language tag string (i.e. en-US) + * into locales string (en_US). + */ + static DPL::String BCP47LanguageTagToLocale(const DPL::String&); + + /* + * Function converts locales string (i.e. en_US.UTF-8) into language tag + * (i.e. en-US) + */ + static DPL::String LocaleToBCP47LanguageTag(const DPL::String&); + + private: + friend class DPL::Singleton; + + LanguageTags m_languageTagsList; + + LanguageTagsProvider(); + virtual ~LanguageTagsProvider(); + + void loadSystemTags(); + void createTagsFromLocales(const char* language); +}; + +typedef DPL::Singleton LanguageTagsProviderSingleton; + +#endif /* LANGUAGETAGSPROVIDER_H */ diff --git a/modules/localization/include/dpl/localization/localization_utils.h b/modules/localization/include/dpl/localization/localization_utils.h new file mode 100644 index 0000000..66a232d --- /dev/null +++ b/modules/localization/include/dpl/localization/localization_utils.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file localization_utils.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + */ + +#ifndef LOCALIZATION_UTILS_H +#define LOCALIZATION_UTILS_H + +#include + +#include +#include +#include +#include + +/** + * WidgetIcon + * Structure to hold information about widget icon. + */ + +struct WidgetIcon +{ + WidgetIcon() : + width(DPL::Optional::Null), + height(DPL::Optional::Null) + {} + + /* + * a valid URI to an image file inside the widget package that represents an + * iconic representation of the widget + */ + DPL::String src; + DPL::Optional width; /// the width of the icon in pixels + DPL::Optional height; /// the height of the icon in pixels + + bool operator==(const WidgetIcon &other) const + { + return src == other.src; + } +}; + +struct WidgetStartFileInfo +{ + DPL::String file; + DPL::String localizedPath; + DPL::String encoding; + DPL::String type; + + bool operator==(const WidgetStartFileInfo& other) const + { + return file == other.file && + localizedPath == other.localizedPath && + encoding == other.encoding && + type == other.type; + } +}; + +typedef DPL::Optional OptionalWidgetIcon; +typedef DPL::Optional OptionalWidgetStartFileInfo; + +#endif //LOCALIZATION_UTILS_H diff --git a/modules/localization/include/dpl/localization/w3c_file_localization.h b/modules/localization/include/dpl/localization/w3c_file_localization.h new file mode 100755 index 0000000..7a437d8 --- /dev/null +++ b/modules/localization/include/dpl/localization/w3c_file_localization.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file w3c_file_localization.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + */ + +#ifndef W3C_FILE_LOCALIZATION_H +#define W3C_FILE_LOCALIZATION_H + +#include +#include +#include +#include + +#include + +// WrtDB::DbWidgetHandle +#include + +namespace W3CFileLocalization { +typedef std::list WidgetIconList; + +DPL::Optional getFilePathInWidgetPackageFromUrl( + const WrtDB::TizenAppId &tzAppId, + const DPL::String &url); +DPL::Optional getFilePathInWidgetPackageFromUrl( + WrtDB::WidgetDAOReadOnlyPtr dao, + const DPL::String &url); +std::string getFilePathInWidgetPackageFromUrl(const std::string &tzAppId, const std::string &url); + +DPL::Optional getFilePathInWidgetPackage( + const WrtDB::TizenAppId &tzAppId, + const DPL::String& file); +DPL::Optional getFilePathInWidgetPackage( + WrtDB::WidgetDAOReadOnlyPtr dao, + const DPL::String& file); + +DPL::OptionalString getStartFile(const WrtDB::TizenAppId & tzAppId); +DPL::OptionalString getStartFile(WrtDB::WidgetDAOReadOnlyPtr dao); + +OptionalWidgetIcon getIcon(const WrtDB::TizenAppId & tzAppId); +OptionalWidgetIcon getIcon(WrtDB::WidgetDAOReadOnlyPtr dao); + +WidgetIconList getValidIconsList( + const WrtDB::TizenAppId &tzAppId); +WidgetIconList getValidIconsList( + WrtDB::WidgetDAOReadOnlyPtr dao); + +OptionalWidgetStartFileInfo getStartFileInfo( + const WrtDB::TizenAppId &tzAppId); +OptionalWidgetStartFileInfo getStartFileInfo( + WrtDB::WidgetDAOReadOnlyPtr dao); + +WrtDB::WidgetLocalizedInfo getLocalizedInfo( + const WrtDB::TizenAppId & tzAppId); +WrtDB::WidgetLocalizedInfo getLocalizedInfo(WrtDB::WidgetDAOReadOnlyPtr dao); +} + +#endif //W3C_FILE_LOCALIZATION_H diff --git a/modules/localization/src/LanguageTagsProvider.cpp b/modules/localization/src/LanguageTagsProvider.cpp new file mode 100644 index 0000000..848cc34 --- /dev/null +++ b/modules/localization/src/LanguageTagsProvider.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file LanguageTagsProvider.cpp + * @author Marcin Kaminski (marcin.ka@samsung.com) + * @version 1.0 + */ + +#include "LanguageTagsProvider.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +IMPLEMENT_SINGLETON(LanguageTagsProvider) + +/* ========== public ========== */ +const LanguageTags LanguageTagsProvider::getLanguageTags() const +{ + return m_languageTagsList; +} + +void LanguageTagsProvider::setLanguageTags(const LanguageTags& taglist) +{ + m_languageTagsList = taglist; + /* If given list does not contain default value (empty string) + * than append it to the list. + * In case of empty list given as parameter only default value + * will exist on m_languageTagsList. */ + DPL::String tofind = L""; + if (std::find(m_languageTagsList.begin(), m_languageTagsList.end(), + tofind) == m_languageTagsList.end()) + { + m_languageTagsList.push_back(L""); + } +} + +void LanguageTagsProvider::setLanguageTagsFromLocales(const char* locales) +{ + LogDebug("Setting new language tags for locales " << locales); + this->createTagsFromLocales(locales); +} + +void LanguageTagsProvider::resetLanguageTags() +{ + this->loadSystemTags(); +} + +void LanguageTagsProvider::addWidgetDefaultLocales( + const DPL::String& defaultLocale) +{ + if (defaultLocale.size() > 0 && + std::find(m_languageTagsList.begin(), m_languageTagsList.end(), + defaultLocale) == m_languageTagsList.end()) + { + if (m_languageTagsList.size() < 2) { + m_languageTagsList.push_front(defaultLocale); + } else { + LanguageTags::iterator placeToInsert = m_languageTagsList.end(); + --placeToInsert; + if (*placeToInsert != L"") { + ++placeToInsert; + } + m_languageTagsList.insert(placeToInsert, defaultLocale); + } + } +} + +DPL::String LanguageTagsProvider::BCP47LanguageTagToLocale( + const DPL::String& inLanguageTag) +{ + DPL::String languageTag(inLanguageTag); + /* Replace all */ + std::replace(languageTag.begin(), languageTag.end(), '-', '_'); + return languageTag; +} + +DPL::String LanguageTagsProvider::LocaleToBCP47LanguageTag( + const DPL::String& inLocaleString) +{ + /* Cut off codepage information from given string (if any exists) + * i.e. change en_US.UTF-8 into en_US */ + DPL::String localeString = inLocaleString.substr( + 0, inLocaleString.find_first_of(L".")); + /* Replace all '_' with '-' */ + std::replace(localeString.begin(), localeString.end(), '_', '-'); + return localeString; +} + +/* ========== private ========== */ +LanguageTagsProvider::LanguageTagsProvider() +{ + LogDebug("Creating LanguageTagsProvider instance"); + this->loadSystemTags(); +} + +LanguageTagsProvider::~LanguageTagsProvider() +{} + +void LanguageTagsProvider::loadSystemTags() +{ + char* language = vconf_get_str(VCONFKEY_LANGSET); + if (!language) { + LogError("Failed to get language from vconf"); + } else { + LogDebug("Language fetched from vconf: " << language); + } + createTagsFromLocales(language); + free(language); +} + +void LanguageTagsProvider::createTagsFromLocales(const char* language) +{ + m_languageTagsList.clear(); + if (!language) { + LogDebug("Setting default language tags"); + /* If NULL language given than set default language tags + * and return. */ + m_languageTagsList.push_back(L""); + return; + } + + LogDebug("Setting tags for language: " << language); + DPL::String langdescr = + LocaleToBCP47LanguageTag(DPL::FromUTF8String(language)); + + if (langdescr.empty()) { + LogError("Empty language description while correct value needed"); + } else { + /* Language tags list should not be cleared before this place to + * avoid losing current data when new data are invalid */ + size_t position; + while (true) { + LogDebug("Processing language description: " << langdescr); + m_languageTagsList.push_back(langdescr); + + // compatibility with lower language Tag by SDK + std::string langtag = DPL::ToUTF8String(langdescr); + std::transform(langtag.begin(), langtag.end(), langtag.begin(), ::tolower); + if (langtag != DPL::ToUTF8String(langdescr)) { + m_languageTagsList.push_back(DPL::FromUTF8String(langtag)); + } + + position = langdescr.find_last_of(L"-"); + if (position == DPL::String::npos) { + break; + } + langdescr = langdescr.substr(0, position); + } + } + /* Add empty tag for non-localized content */ + m_languageTagsList.push_back(L""); +} diff --git a/modules/localization/src/w3c_file_localization.cpp b/modules/localization/src/w3c_file_localization.cpp new file mode 100644 index 0000000..438c62b --- /dev/null +++ b/modules/localization/src/w3c_file_localization.cpp @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file w3c_file_localization.cpp + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + */ +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +using namespace WrtDB; + +namespace { +const DPL::String FILE_URI_BEGIN = L"file://"; +const DPL::String WIDGET_URI_BEGIN = L"widget://"; +const DPL::String APP_URI_BEGIN = L"app://"; +const DPL::String LOCALE_PREFIX = L"locales/"; + +DPL::Optional GetFilePathInWidgetPackageInternal( + const std::string& basePath, + std::string filePath) +{ + LogDebug("Looking for file: " << filePath << " in: " << basePath); + + const LanguageTags& ltags = + LanguageTagsProviderSingleton::Instance().getLanguageTags(); + + //Check if string isn't empty + if (filePath.size() == 0) { + return DPL::Optional::Null; + } + //Removing preceding '/' + if (filePath[0] == '/') { + filePath.erase(0, 1); + } + // In some cases (start file localization) url has unnecessary "/" at the + // end + if (filePath[filePath.size() - 1] == '/') { + filePath.erase(filePath.size() - 1, 1); + } + //Check if string isn't empty + if (filePath.size() == 0) { + return DPL::Optional::Null; + } + + LogDebug("locales size = " << ltags.size()); + for (LanguageTags::const_iterator it = ltags.begin(); + it != ltags.end(); + ++it) + { + LogDebug("Trying locale: " << *it); + std::string path = basePath; + if (path[path.size() - 1] == '/') { + path.erase(path.size() - 1); + } + + if (it->empty()) { + path += "/" + filePath; + } else { + path += "/locales/" + DPL::ToUTF8String(*it) + "/" + filePath; + } + + LogDebug("Trying locale: " << *it << " | " << path); + struct stat buf; + if (0 == stat(path.c_str(), &buf)) { + if ((buf.st_mode & S_IFMT) == S_IFREG) { + path.erase(0, basePath.length()); + return DPL::Optional(path); + } + } + } + + return DPL::Optional::Null; +} + +DPL::Optional GetFilePathInWidgetPackageInternal( + const DPL::String& basePath, + const DPL::String& filePath) +{ + DPL::Optional path = + GetFilePathInWidgetPackageInternal(DPL::ToUTF8String(basePath), + DPL::ToUTF8String(filePath)); + DPL::Optional dplPath; + if (!!path) { + dplPath = DPL::FromUTF8String(*path); + } + return dplPath; +} +} + +namespace W3CFileLocalization { +static bool isExistFileCached(const std::string& path) +{ + static std::map pathCache; + + // is cached? + if (pathCache.find(path) == pathCache.end()) + { + struct stat buf; + + if (0 == stat(path.c_str(), &buf)) + { + pathCache[path] = true; + + return true; + } + else + { + pathCache[path] = false; + + return false; + } + } + + return pathCache[path]; +} + +std::string getFilePathInWidgetPackageFromUrl(const std::string &tzAppId, const std::string &url) +{ + const std::string SCHEME_FILE = "file://"; + const std::string SCHEME_WIDGET = "widget://"; + const std::string SCHEM_APP = "app://"; + const std::string LOCALE_PATH = "locales/"; + const std::string DOUBLE_ROOT = "//"; + + static std::string lastTzAppId; + static WidgetDAOReadOnlyPtr dao; + static std::string srcPath; + + std::string workingUrl = url; + bool found = false; + + // Dao caching + if (lastTzAppId != tzAppId) + { + lastTzAppId = tzAppId; + dao.reset(new WidgetDAOReadOnly(DPL::FromUTF8String(tzAppId))); + srcPath = DPL::ToUTF8String(dao->getPath()); + } + + // backup suffix string + std::string backupSuffix; + size_t pos = workingUrl.find_first_of("#?"); + + if (pos != std::string::npos) + { + backupSuffix = workingUrl.substr(pos); + workingUrl.resize(pos); + } + + // make basis path + if (workingUrl.compare(0, SCHEME_WIDGET.length(), SCHEME_WIDGET) == 0) + { + // remove "widget://" + workingUrl.erase(0, SCHEME_WIDGET.length()); + } + else if (workingUrl.compare(0, SCHEME_FILE.length(), SCHEME_FILE) == 0) + { + // remove "file://" + workingUrl.erase(0, SCHEME_FILE.length()); + + // exception handling for "//" + if (workingUrl.compare(0, DOUBLE_ROOT.length(), DOUBLE_ROOT) == 0) + { + workingUrl.erase(0, 1); + LogDebug("workingUrl: " << workingUrl); + } + + // remove src path + if (workingUrl.compare(0, srcPath.length(), srcPath) == 0) + { + workingUrl.erase(0, srcPath.length()); + } + + // remove locale path + if (workingUrl.compare(0, LOCALE_PATH.length(), LOCALE_PATH) == 0) + { + workingUrl.erase(0, LOCALE_PATH.length()); + + pos = workingUrl.find_first_of('/'); + + if (pos != std::string::npos && pos > 0) + { + workingUrl.erase(0, pos+1); + } + } + } + else if (workingUrl.compare(0, SCHEM_APP.length(), SCHEM_APP) == 0) + { + // remove "app://" + workingUrl.erase(0, SCHEM_APP.length()); + + // remove tizen app id + if (workingUrl.compare(0, tzAppId.length(), tzAppId) == 0) + { + workingUrl.erase(0, tzAppId.length()); + } + else + { + LogError("Tizen id does not match, ignoring"); + return ""; + } + } + + // remove '/' token + if (!workingUrl.empty() && workingUrl[0] == '/') + { + workingUrl.erase(0, 1); + } + + if (!workingUrl.empty() && workingUrl[workingUrl.length()-1] == '/') { + workingUrl.erase(workingUrl.length()-1, 1); + } + + if (workingUrl.empty()) + { + LogError("URL Localization Error!"); + return ""; + } + + const LanguageTags& ltags = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + + FOREACH(it, ltags) + { + std::string path = srcPath; + + if (!it->empty()) + { + path += LOCALE_PATH; + + if (isExistFileCached(path) == false) + { + continue; + } + + path += DPL::ToUTF8String(*it) + "/"; + + if (isExistFileCached(path) == false) + { + continue; + } + } + + path += workingUrl; + + if (isExistFileCached(path) == true) + { + found = true; + workingUrl = path; + break; + } + } + + // restore suffix string + if (!found) + { + // return empty string + workingUrl = ""; + } + else + { + if (!backupSuffix.empty()) + { + workingUrl += backupSuffix; + } + } + + return workingUrl; +} + +DPL::Optional getFilePathInWidgetPackageFromUrl( + const WrtDB::TizenAppId &tzAppId, + const DPL::String &url) +{ + return getFilePathInWidgetPackageFromUrl( + WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(tzAppId)), + url); +} + +DPL::Optional getFilePathInWidgetPackageFromUrl( + WrtDB::WidgetDAOReadOnlyPtr dao, + const DPL::String &url) +{ + DPL::String req = url; + + DPL::String suffix; + DPL::String::size_type pos = req.find_first_of('#'); + if(pos != DPL::String::npos) + { + suffix = req.substr(pos) + suffix; + req.resize(pos); //truncate fragment identifier + } + + pos = req.find_first_of('?'); + if(pos != DPL::String::npos) + { + suffix = req.substr(pos) + suffix; + req.resize(pos); //truncate query string + } + + if (req.find(WIDGET_URI_BEGIN) == 0) { + req.erase(0, WIDGET_URI_BEGIN.length()); + } else if (req.find(FILE_URI_BEGIN) == 0) { + req.erase(0, FILE_URI_BEGIN.length()); + if (req.find(dao->getPath()) == 0) { + req.erase(0, dao->getPath().length()); + } + if (req.find(LOCALE_PREFIX) == 0) { + req.erase(0, LOCALE_PREFIX.length()); + size_t position = req.find('/'); + // should always be >0 as correct locales path is + // always locales/xx/ or locales/xx-XX/ + if (position != std::string::npos && position > 0) { + req.erase(0, position + 1); + } + } + } else if(req.find(APP_URI_BEGIN) == 0) { + req.erase(0, APP_URI_BEGIN.length()); + DPL::String id = dao->getTizenAppId(); + if(req.substr(0, id.size()) != id) + { + LogError("Tizen id does not match, ignoring"); + return DPL::Optional::Null; + } + req.erase(0, id.length()); + } else { + LogDebug("Unknown path format, ignoring"); + return DPL::Optional::Null; + } + + auto widgetPath = dao->getPath(); + + LogDebug("Required path: " << req); + DPL::Optional found = + GetFilePathInWidgetPackageInternal(widgetPath, req); + + if (!found) { + LogError("Path not found within current locale in current widget"); + return DPL::Optional::Null; + } + + found = widgetPath + *found + suffix; + + return found; +} + +DPL::Optional getFilePathInWidgetPackage( + const WrtDB::TizenAppId &tzAppId, + const DPL::String& file) +{ + return getFilePathInWidgetPackage( + WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(tzAppId)), + file); +} + +DPL::Optional getFilePathInWidgetPackage( + WrtDB::WidgetDAOReadOnlyPtr dao, + const DPL::String& file) +{ + return GetFilePathInWidgetPackageInternal(dao->getPath(), file); +} + +DPL::OptionalString getStartFile(const WrtDB::TizenAppId & tzAppId) +{ + return getStartFile(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(tzAppId))); +} + +DPL::OptionalString getStartFile(WrtDB::WidgetDAOReadOnlyPtr dao) +{ + WidgetDAOReadOnly::LocalizedStartFileList locList = + dao->getLocalizedStartFileList(); + WidgetDAOReadOnly::WidgetStartFileList list = dao->getStartFileList(); + LanguageTags tagsList = + LanguageTagsProviderSingleton::Instance().getLanguageTags(); + + DPL::OptionalString defaultLoc = dao->getDefaultlocale(); + if (!!defaultLoc) { + tagsList.push_back(*defaultLoc); + } + + FOREACH(tag, tagsList) + { + FOREACH(sFile, locList) + { + if (*tag == sFile->widgetLocale) { + FOREACH(it, list) + { + if (it->startFileId == sFile->startFileId) { + return it->src; + } + } + } + } + } + + return DPL::OptionalString::Null; +} + +OptionalWidgetIcon getIcon(const WrtDB::TizenAppId & tzAppId) +{ + return getIcon(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(tzAppId))); +} + +OptionalWidgetIcon getIcon(WrtDB::WidgetDAOReadOnlyPtr dao) +{ + WidgetDAOReadOnly::WidgetLocalizedIconList locList = + dao->getLocalizedIconList(); + WidgetDAOReadOnly::WidgetIconList list = dao->getIconList(); + LanguageTags tagsList = + LanguageTagsProviderSingleton::Instance().getLanguageTags(); + + DPL::OptionalString defaultLoc = dao->getDefaultlocale(); + if (!!defaultLoc) { + tagsList.push_back(*defaultLoc); + } + + FOREACH(tag, tagsList) + { + FOREACH(icon, locList) + { + if (*tag == icon->widgetLocale) { + FOREACH(it, list) + { + if (it->iconId == icon->iconId) { + WidgetIcon ret; + ret.src = it->iconSrc; + ret.width = it->iconWidth; + ret.height = it->iconHeight; + return ret; + } + } + } + } + } + + return OptionalWidgetIcon::Null; +} + +WidgetIconList getValidIconsList(const WrtDB::TizenAppId &tzAppId) +{ + return getValidIconsList( + WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(tzAppId))); +} + +WidgetIconList getValidIconsList(WrtDB::WidgetDAOReadOnlyPtr dao) +{ + WidgetDAOReadOnly::WidgetIconList list = dao->getIconList(); + + WidgetIconList outlist; + + FOREACH(it, list) + { + LogDebug(":" << it->iconSrc); + if (!!getFilePathInWidgetPackage(dao->getTizenAppId(), + it->iconSrc)) + { + WidgetIcon ret; + ret.src = it->iconSrc; + ret.width = it->iconWidth; + ret.height = it->iconHeight; + outlist.push_back(ret); + } + } + return outlist; +} + +OptionalWidgetStartFileInfo getStartFileInfo( + const WrtDB::TizenAppId &tzAppId) +{ + return getStartFileInfo( + WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(tzAppId))); +} + +OptionalWidgetStartFileInfo getStartFileInfo(WrtDB::WidgetDAOReadOnlyPtr dao) +{ + WidgetStartFileInfo info; + + WidgetDAOReadOnly::LocalizedStartFileList locList = + dao->getLocalizedStartFileList(); + WidgetDAOReadOnly::WidgetStartFileList list = dao->getStartFileList(); + const LanguageTags tagsList = + LanguageTagsProviderSingleton::Instance().getLanguageTags(); + + FOREACH(tag, tagsList) + { + FOREACH(sFile, locList) + { + if (*tag == sFile->widgetLocale) { + FOREACH(it, list) + { + if (it->startFileId == + sFile->startFileId) + { + info.file = it->src; + info.encoding = sFile->encoding; + info.type = sFile->type; + if (tag->empty()) { + info.localizedPath = it->src; + } else { + info.localizedPath = L"locales/" + *tag + L"/"; + info.localizedPath += it->src; + } + return info; + } + } + } + } + } + + return OptionalWidgetStartFileInfo::Null; +} + +WidgetLocalizedInfo getLocalizedInfo(const WrtDB::TizenAppId & tzAppId) +{ + return getLocalizedInfo(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(tzAppId))); +} + +WidgetLocalizedInfo getLocalizedInfo(WidgetDAOReadOnlyPtr dao) +{ + LanguageTags languages = + LanguageTagsProviderSingleton::Instance().getLanguageTags(); + DPL::OptionalString dl = dao->getDefaultlocale(); + if (!!dl) { + languages.push_back(*dl); + } + + WidgetLocalizedInfo result; + FOREACH(i, languages) + { + WidgetLocalizedInfo languageResult = dao->getLocalizedInfo(*i); + +#define OVERWRITE_IF_NULL(FIELD) if (!result.FIELD) { \ + result.FIELD = languageResult.FIELD; \ +} + + OVERWRITE_IF_NULL(name); + OVERWRITE_IF_NULL(shortName); + OVERWRITE_IF_NULL(description); + OVERWRITE_IF_NULL(license); + OVERWRITE_IF_NULL(licenseHref); + +#undef OVERWRITE_IF_NULL + } + + return result; +} +} diff --git a/modules/log/config.cmake b/modules/log/config.cmake new file mode 100644 index 0000000..30ad033 --- /dev/null +++ b/modules/log/config.cmake @@ -0,0 +1,42 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_LOG_SOURCES + ${PROJECT_SOURCE_DIR}/modules/log/src/abstract_log_provider.cpp + ${PROJECT_SOURCE_DIR}/modules/log/src/dlog_log_provider.cpp + ${PROJECT_SOURCE_DIR}/modules/log/src/log.cpp + ${PROJECT_SOURCE_DIR}/modules/log/src/old_style_log_provider.cpp + PARENT_SCOPE +) + +SET(DPL_LOG_HEADERS + ${PROJECT_SOURCE_DIR}/modules/log/include/dpl/log/abstract_log_provider.h + ${PROJECT_SOURCE_DIR}/modules/log/include/dpl/log/dlog_log_provider.h + ${PROJECT_SOURCE_DIR}/modules/log/include/dpl/log/log.h + ${PROJECT_SOURCE_DIR}/modules/log/include/dpl/log/old_style_log_provider.h + ${PROJECT_SOURCE_DIR}/modules/log/include/dpl/log/secure_log.h + PARENT_SCOPE +) + +SET(DPL_LOG_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/log/include/ + PARENT_SCOPE +) diff --git a/modules/log/include/dpl/log/abstract_log_provider.h b/modules/log/include/dpl/log/abstract_log_provider.h new file mode 100644 index 0000000..62fa050 --- /dev/null +++ b/modules/log/include/dpl/log/abstract_log_provider.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract log provider + */ +#ifndef DPL_ABSTRACT_LOG_PROVIDER_H +#define DPL_ABSTRACT_LOG_PROVIDER_H + +namespace DPL { +namespace Log { +class AbstractLogProvider +{ + public: + virtual ~AbstractLogProvider() {} + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function) = 0; + + protected: + static const char *LocateSourceFileName(const char *filename); +}; +} +} // namespace DPL + +#endif // DPL_ABSTRACT_LOG_PROVIDER_H diff --git a/modules/log/include/dpl/log/dlog_log_provider.h b/modules/log/include/dpl/log/dlog_log_provider.h new file mode 100644 index 0000000..1dd4c2d --- /dev/null +++ b/modules/log/include/dpl/log/dlog_log_provider.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dlog_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of DLOG log provider + */ +#ifndef DPL_DLOG_LOG_PROVIDER_H +#define DPL_DLOG_LOG_PROVIDER_H + +#include +#include +#include + +namespace DPL { +namespace Log { +class DLOGLogProvider : + public AbstractLogProvider +{ + private: + DPL::ScopedFree m_tag; + + static std::string FormatMessage(const char *message, + const char *filename, + int line, + const char *function); + + public: + DLOGLogProvider(); + virtual ~DLOGLogProvider(); + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function); + + // Set global Tag according to DLOG + void SetTag(const char *tag); +}; +} +} // namespace DPL + +#endif // DPL_DLOG_LOG_PROVIDER_H diff --git a/modules/log/include/dpl/log/log.h b/modules/log/include/dpl/log/log.h new file mode 100644 index 0000000..d4d95ed --- /dev/null +++ b/modules/log/include/dpl/log/log.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file log.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of log system + */ +#ifndef DPL_LOG_H +#define DPL_LOG_H + +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Log { +/** + * DPL log system + * + * To switch logs into old style, export + * DPL_USE_OLD_STYLE_LOGS before application start + */ +class LogSystem : + private Noncopyable +{ + private: + typedef std::list AbstractLogProviderPtrList; + AbstractLogProviderPtrList m_providers; + + DLOGLogProvider *m_dlogProvider; + OldStyleLogProvider *m_oldStyleProvider; + + bool m_isLoggingEnabled; + + public: + bool IsLoggingEnabled() const; + LogSystem(); + virtual ~LogSystem(); + + /** + * Log debug message + */ + void Debug(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log info message + */ + void Info(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log warning message + */ + void Warning(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log error message + */ + void Error(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log pedantic message + */ + void Pedantic(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Set default's DLOG provider Tag + */ + void SetTag(const char *tag); + + /** + * Add abstract provider to providers list + * + * @notice Ownership is transfered to LogSystem and deleted upon exit + */ + void AddProvider(AbstractLogProvider *provider); + + /** + * Remove abstract provider from providers list + */ + void RemoveProvider(AbstractLogProvider *provider); +}; + +/* + * Replacement low overhead null logging class + */ +class NullStream +{ + public: + NullStream() {} + + template + NullStream& operator<<(const T&) + { + return *this; + } +}; + +/** + * Log system singleton + */ +typedef Singleton LogSystemSingleton; +} +} // namespace DPL + +// +// Log support +// +// + +#ifdef DPL_LOGS_ENABLED + #define DPL_MACRO_FOR_LOGGING(message, function) \ + do \ + { \ + if (DPL::Log::LogSystemSingleton::Instance().IsLoggingEnabled()) \ + { \ + std::ostringstream platformLog; \ + platformLog << message; \ + DPL::Log::LogSystemSingleton::Instance().function( \ + platformLog.str().c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) +#else +/* avoid warnings about unused variables */ + #define DPL_MACRO_FOR_LOGGING(message, function) \ + do { \ + DPL::Log::NullStream ns; \ + ns << message; \ + } while (0) +#endif + +#define LogDebug(message) DPL_MACRO_FOR_LOGGING(message, Debug) +#define LogInfo(message) DPL_MACRO_FOR_LOGGING(message, Info) +#define LogWarning(message) DPL_MACRO_FOR_LOGGING(message, Warning) +#define LogError(message) DPL_MACRO_FOR_LOGGING(message, Error) +#define LogPedantic(message) DPL_MACRO_FOR_LOGGING(message, Pedantic) + +#endif // DPL_LOG_H diff --git a/modules/log/include/dpl/log/old_style_log_provider.h b/modules/log/include/dpl/log/old_style_log_provider.h new file mode 100644 index 0000000..70e308a --- /dev/null +++ b/modules/log/include/dpl/log/old_style_log_provider.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file old_style_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of old style log provider + */ +#ifndef DPL_OLD_STYLE_LOG_PROVIDER_H +#define DPL_OLD_STYLE_LOG_PROVIDER_H + +#include +#include + +namespace DPL { +namespace Log { +class OldStyleLogProvider : + public AbstractLogProvider +{ + private: + bool m_showDebug; + bool m_showInfo; + bool m_showWarning; + bool m_showError; + bool m_showPedantic; + bool m_printStdErr; + + static std::string FormatMessage(const char *message, + const char *filename, + int line, + const char *function); + + public: + OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic); + OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic, + bool printStdErr); + virtual ~OldStyleLogProvider() {} + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function); +}; +} +} // namespace DPL + +#endif // DPL_OLD_STYLE_LOG_PROVIDER_H diff --git a/modules/log/include/dpl/log/secure_log.h b/modules/log/include/dpl/log/secure_log.h new file mode 100644 index 0000000..6402c4f --- /dev/null +++ b/modules/log/include/dpl/log/secure_log.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file secure_log.h + * @author Jihoon Chung(jihoon.chung@samsung.com) + * @version 0.1 + * @brief + */ + +#ifndef DPL_SECURE_LOG_H +#define DPL_SECURE_LOG_H + +#include + +#define COLOR_ERROR "\e[1;31m" +#define COLOR_WARNING "\e[2;31m" +#define COLOR_END "\e[0m" +#define COLOR_TAG "\e[0m" + +// default TAG +#undef LOG_TAG +#define LOG_TAG "WRT_UNDEFINED" + +#ifdef WRT_LOG +#undef LOG_TAG +#define LOG_TAG "WRT" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;32m" +#endif + +#ifdef WRT_BUNDLE_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_BUNDLE" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;34m" +#endif + +#ifdef WRT_PLUGINS_COMMON_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_PLUGINS/COMMON" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;36m" +#endif + +#ifdef WRT_PLUGINS_WIDGET_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_PLUGINS/WIDGET" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;35m" +#endif + +#ifdef WRT_INSTALLER_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_INSTALLER" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;32m" +#endif + +#ifndef SECURE_SLOGD +#define SECURE_SLOGD(fmt, arg...) SLOGD(fmt,##arg) +#endif + +#ifndef SECURE_SLOGW +#define SECURE_SLOGW(fmt, arg...) SLOGW(fmt,##arg) +#endif + +#ifndef SECURE_SLOGE +#define SECURE_SLOGE(fmt, arg...) SLOGE(fmt,##arg) +#endif + +#undef _D +#define _D(fmt, arg ...) SECURE_SLOGD(COLOR_TAG fmt COLOR_END,##arg) +#undef _W +#define _W(fmt, arg ...) SECURE_SLOGW(COLOR_WARNING fmt COLOR_END,##arg) +#undef _E +#define _E(fmt, arg ...) SECURE_SLOGE(COLOR_ERROR fmt COLOR_END,##arg) + +#endif // DPL_SECURE_LOG_H + diff --git a/modules/log/src/abstract_log_provider.cpp b/modules/log/src/abstract_log_provider.cpp new file mode 100644 index 0000000..a03f8a0 --- /dev/null +++ b/modules/log/src/abstract_log_provider.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_log_provider.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract log provider + */ +#include +#include +#include + +namespace DPL { +namespace Log { +const char *AbstractLogProvider::LocateSourceFileName(const char *filename) +{ + const char *ptr = strrchr(filename, '/'); + return ptr != NULL ? ptr + 1 : filename; +} +} +} diff --git a/modules/log/src/dlog_log_provider.cpp b/modules/log/src/dlog_log_provider.cpp new file mode 100644 index 0000000..1a203db --- /dev/null +++ b/modules/log/src/dlog_log_provider.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dlog_log_provider.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of DLOG log provider + */ +#include +#include +#include +#include +#include + +#ifdef SECURE_LOG + #define INTERNAL_DLP_LOG_ SECURE_LOG +#else + #define INTERNAL_DLP_LOG_ LOG +#endif + +/* + * The __extension__ keyword in the following define is required because + * macros used here from dlog.h use non-standard extension that cause + * gcc to show unwanted warnings when compiling with -pedantic switch. + */ +#define INTERNAL_DLP_LOG __extension__ INTERNAL_DLP_LOG_ + +namespace DPL { +namespace Log { +std::string DLOGLogProvider::FormatMessage(const char *message, + const char *filename, + int line, + const char *function) +{ + std::ostringstream val; + + val << std::string("[") << + LocateSourceFileName(filename) << std::string(":") << line << + std::string("] ") << function << std::string("(): ") << message; + + return val.str(); +} + +DLOGLogProvider::DLOGLogProvider() +{} + +DLOGLogProvider::~DLOGLogProvider() +{} + +void DLOGLogProvider::SetTag(const char *tag) +{ + m_tag.Reset(strdup(tag)); +} + +void DLOGLogProvider::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_DEBUG, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_INFO, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_WARN, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_ERROR, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +} + +void DLOGLogProvider::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + INTERNAL_DLP_LOG(LOG_DEBUG, "DPL", "%s", + FormatMessage(message, filename, line, function).c_str()); +} +} +} // namespace DPL + +#undef INTERNAL_DLP_LOG +#undef INTERNAL_DLP_LOG_ + diff --git a/modules/log/src/log.cpp b/modules/log/src/log.cpp new file mode 100644 index 0000000..7c0ebc2 --- /dev/null +++ b/modules/log/src/log.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file log.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of log system + */ +#include +#include +#include + +IMPLEMENT_SINGLETON(DPL::Log::LogSystem) + +namespace DPL { +namespace Log { +namespace // anonymous +{ +const char *OLD_STYLE_LOGS_ENV_NAME = "DPL_USE_OLD_STYLE_LOGS"; +const char *OLD_STYLE_PEDANTIC_LOGS_ENV_NAME = + "DPL_USE_OLD_STYLE_PEDANTIC_LOGS"; +const char *OLD_STYLE_LOGS_MASK_ENV_NAME = "DPL_USE_OLD_STYLE_LOGS_MASK"; +const char *DPL_LOG_OFF = "DPL_LOG_OFF"; +} // namespace anonymous + +bool LogSystem::IsLoggingEnabled() const +{ + return m_isLoggingEnabled; +} + +LogSystem::LogSystem() : + m_dlogProvider(NULL), + m_oldStyleProvider(NULL), + m_isLoggingEnabled(!getenv(DPL_LOG_OFF)) +{ + bool oldStyleLogs = false; + bool oldStyleDebugLogs = true; + bool oldStyleInfoLogs = true; + bool oldStyleWarningLogs = true; + bool oldStyleErrorLogs = true; + bool oldStylePedanticLogs = false; + + // Check environment settings about pedantic logs + const char *value = getenv(OLD_STYLE_LOGS_ENV_NAME); + + if (value != NULL && !strcmp(value, "1")) { + oldStyleLogs = true; + } + + value = getenv(OLD_STYLE_PEDANTIC_LOGS_ENV_NAME); + + if (value != NULL && !strcmp(value, "1")) { + oldStylePedanticLogs = true; + } + + value = getenv(OLD_STYLE_LOGS_MASK_ENV_NAME); + + if (value != NULL) { + size_t len = strlen(value); + + if (len >= 1) { + if (value[0] == '0') { + oldStyleDebugLogs = false; + } else if (value[0] == '1') { + oldStyleDebugLogs = true; + } + } + + if (len >= 2) { + if (value[1] == '0') { + oldStyleInfoLogs = false; + } else if (value[1] == '1') { + oldStyleInfoLogs = true; + } + } + + if (len >= 3) { + if (value[2] == '0') { + oldStyleWarningLogs = false; + } else if (value[2] == '1') { + oldStyleWarningLogs = true; + } + } + + if (len >= 4) { + if (value[3] == '0') { + oldStyleErrorLogs = false; + } else if (value[3] == '1') { + oldStyleErrorLogs = true; + } + } + } + + // Setup default DLOG and old style logging + if (oldStyleLogs) { + // Old style + m_oldStyleProvider = new OldStyleLogProvider(oldStyleDebugLogs, + oldStyleInfoLogs, + oldStyleWarningLogs, + oldStyleErrorLogs, + oldStylePedanticLogs); + AddProvider(m_oldStyleProvider); + } else { + // DLOG + m_dlogProvider = new DLOGLogProvider(); + AddProvider(m_dlogProvider); + } +} + +LogSystem::~LogSystem() +{ + // Delete all providers + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + delete *iterator; + } + + m_providers.clear(); + + // And even default providers + m_dlogProvider = NULL; + m_oldStyleProvider = NULL; +} + +void LogSystem::SetTag(const char* tag) +{ + if (m_dlogProvider != NULL) { + m_dlogProvider->SetTag(tag); + } +} + +void LogSystem::AddProvider(AbstractLogProvider *provider) +{ + m_providers.push_back(provider); +} + +void LogSystem::RemoveProvider(AbstractLogProvider *provider) +{ + m_providers.remove(provider); +} + +void LogSystem::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Debug(message, filename, line, function); + } +} + +void LogSystem::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Info(message, filename, line, function); + } +} + +void LogSystem::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Warning(message, filename, line, function); + } +} + +void LogSystem::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Error(message, filename, line, function); + } +} + +void LogSystem::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Pedantic(message, filename, line, function); + } +} +} +} // namespace DPL diff --git a/modules/log/src/old_style_log_provider.cpp b/modules/log/src/old_style_log_provider.cpp new file mode 100644 index 0000000..b8060dd --- /dev/null +++ b/modules/log/src/old_style_log_provider.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file old_style_log_provider.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of old style log provider + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Log { +namespace // anonymous +{ +using namespace DPL::Colors::Text; +const char *DEBUG_BEGIN = GREEN_BEGIN; +const char *DEBUG_END = GREEN_END; +const char *INFO_BEGIN = CYAN_BEGIN; +const char *INFO_END = CYAN_END; +const char *ERROR_BEGIN = RED_BEGIN; +const char *ERROR_END = RED_END; +const char *WARNING_BEGIN = BOLD_GOLD_BEGIN; +const char *WARNING_END = BOLD_GOLD_END; +const char *PEDANTIC_BEGIN = PURPLE_BEGIN; +const char *PEDANTIC_END = PURPLE_END; + +std::string GetFormattedTime() +{ + timeval tv; + tm localNowTime; + + gettimeofday(&tv, NULL); + localtime_r(&tv.tv_sec, &localNowTime); + + char format[64]; + snprintf(format, + sizeof(format), + "%02i:%02i:%02i.%03i", + localNowTime.tm_hour, + localNowTime.tm_min, + localNowTime.tm_sec, + static_cast(tv.tv_usec / 1000)); + return format; +} +} // namespace anonymous + +std::string OldStyleLogProvider::FormatMessage(const char *message, + const char *filename, + int line, + const char *function) +{ + std::ostringstream val; + + val << std::string("[") << GetFormattedTime() << std::string("] [") << + static_cast(pthread_self()) << "/" << + static_cast(getpid()) << std::string("] [") << + LocateSourceFileName(filename) << std::string(":") << line << + std::string("] ") << function << std::string("(): ") << message; + + return val.str(); +} + +OldStyleLogProvider::OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic) : + m_showDebug(showDebug), + m_showInfo(showInfo), + m_showWarning(showWarning), + m_showError(showError), + m_showPedantic(showPedantic), + m_printStdErr(false) +{} + +OldStyleLogProvider::OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic, + bool printStdErr) : + m_showDebug(showDebug), + m_showInfo(showInfo), + m_showWarning(showWarning), + m_showError(showError), + m_showPedantic(showPedantic), + m_printStdErr(printStdErr) +{} + +void OldStyleLogProvider::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showDebug) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", DEBUG_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), DEBUG_END); + } else { + fprintf(stdout, "%s%s%s\n", DEBUG_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), DEBUG_END); + } + } +} + +void OldStyleLogProvider::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showInfo) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", INFO_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), INFO_END); + } else { + fprintf(stdout, "%s%s%s\n", INFO_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), INFO_END); + } + } +} + +void OldStyleLogProvider::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showWarning) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", WARNING_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), WARNING_END); + } else { + fprintf(stdout, "%s%s%s\n", WARNING_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), WARNING_END); + } + } +} + +void OldStyleLogProvider::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showError) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", ERROR_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), ERROR_END); + } else { + fprintf(stdout, "%s%s%s\n", ERROR_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), ERROR_END); + } + } +} + +void OldStyleLogProvider::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showPedantic) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", PEDANTIC_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), PEDANTIC_END); + } else { + fprintf(stdout, "%s%s%s\n", PEDANTIC_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), PEDANTIC_END); + } + } +} +} +} // namespace DPL diff --git a/modules/rpc/config.cmake b/modules/rpc/config.cmake new file mode 100644 index 0000000..9f3d810 --- /dev/null +++ b/modules/rpc/config.cmake @@ -0,0 +1,52 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_RPC_SOURCES + ${PROJECT_SOURCE_DIR}/modules/rpc/src/abstract_rpc_connection.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/abstract_rpc_connector.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/generic_rpc_connection.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/generic_socket_rpc_client.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/generic_socket_rpc_connection.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/generic_socket_rpc_server.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/unix_socket_rpc_client.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/unix_socket_rpc_connection.cpp + ${PROJECT_SOURCE_DIR}/modules/rpc/src/unix_socket_rpc_server.cpp + PARENT_SCOPE +) + +SET(DPL_RPC_HEADERS + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/abstract_rpc_connection.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/abstract_rpc_connector.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/generic_rpc_connection.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/generic_socket_rpc_client.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/generic_socket_rpc_connection.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/generic_socket_rpc_server.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/rpc_function.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/unix_socket_rpc_client.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/unix_socket_rpc_connection.h + ${PROJECT_SOURCE_DIR}/modules/rpc/include/dpl/rpc/unix_socket_rpc_server.h + PARENT_SCOPE +) + +SET(DPL_RPC_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/rpc/include + PARENT_SCOPE +) diff --git a/modules/rpc/include/dpl/rpc/abstract_rpc_connection.h b/modules/rpc/include/dpl/rpc/abstract_rpc_connection.h new file mode 100644 index 0000000..7857c60 --- /dev/null +++ b/modules/rpc/include/dpl/rpc/abstract_rpc_connection.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_rpc_connection.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for abstract RPC connection + */ +#ifndef DPL_ABSTRACT_RPC_CONNECTION_H +#define DPL_ABSTRACT_RPC_CONNECTION_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace RPC { +namespace AbstractRPCConnectionEvents { +/** + * Asynchronous call event + */ +DECLARE_GENERIC_EVENT_1(AsyncCallEvent, RPCFunction) + +/** + * Connection closed event + */ +DECLARE_GENERIC_EVENT_0(ConnectionClosedEvent) + +/** + * Connection broken event + */ +DECLARE_GENERIC_EVENT_0(ConnectionBrokenEvent) +} // namespace AbstractRPCConnectionEvents + +class AbstractRPCConnection : + public DPL::Event::EventSupport, + public DPL::Event::EventSupport, + public DPL::Event::EventSupport +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, AsyncCallFailed) + DECLARE_EXCEPTION_TYPE(Base, PingFailed) + }; + + public: + virtual ~AbstractRPCConnection() {} + + /** + * Call asynchronously RPC function + * + * @param function COnstant reference to RPC function to call + * @return none + */ + virtual void AsyncCall(const RPCFunction &function) = 0; + + /** + * Ping RPC connection + * This will send a ping/pong packet over connection to ensure it is alive + * If any errors are to occur proper events will be emitted + * + * @return none + */ + virtual void Ping() = 0; +}; + +/** + * Abstract connection ID used to represent connection being established + * or RPC server accepting connection + */ +typedef void *AbstractRPCConnectionID; +} +} // namespace DPL + +#endif // DPL_ABSTRACT_RPC_CONNECTION_H diff --git a/modules/rpc/include/dpl/rpc/abstract_rpc_connector.h b/modules/rpc/include/dpl/rpc/abstract_rpc_connector.h new file mode 100644 index 0000000..c9e3b1f --- /dev/null +++ b/modules/rpc/include/dpl/rpc/abstract_rpc_connector.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_rpc_connector.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for abstract RPC connector + */ +#ifndef DPL_ABSTRACT_RPC_CONNECTOR_H +#define DPL_ABSTRACT_RPC_CONNECTOR_H + +#include +#include +#include + +namespace DPL { +namespace RPC { +namespace AbstractRPCConnectorEvents { +/** + * RPC connection established + */ +DECLARE_GENERIC_EVENT_2(ConnectionEstablishedEvent, + AbstractRPCConnectionID, + AbstractRPCConnection *) +} // namespace AbstractRPCClientEvents + +class AbstractRPCConnector : + public DPL::Event::EventSupport +{ + public: + /** + * Destructor + */ + virtual ~AbstractRPCConnector() {} +}; +} +} // namespace DPL + +#endif // DPL_ABSTRACT_RPC_CONNECTOR_H diff --git a/modules/rpc/include/dpl/rpc/generic_rpc_connection.h b/modules/rpc/include/dpl/rpc/generic_rpc_connection.h new file mode 100644 index 0000000..d9614c6 --- /dev/null +++ b/modules/rpc/include/dpl/rpc/generic_rpc_connection.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_rpc_connection.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for generic RPC connection + */ +#ifndef DPL_GENERIC_RPC_CONNECTION_H +#define DPL_GENERIC_RPC_CONNECTION_H + +#include +#include +#include +#include + +namespace DPL { +namespace RPC { +class GenericRPCConnection : + public AbstractRPCConnection, + private DPL::Socket::WaitableInputOutputExecutionContextSupport +{ + private: + // WaitableInputOutputExecutionContextSupport + virtual void OnInputStreamRead(); + virtual void OnInputStreamClosed(); + virtual void OnInputStreamBroken(); + + std::unique_ptr m_inputOutput; + + public: + /** + * Costructor + * + * Abstract waitable input/outobject is acquired by class and destroyed upon + * destructor + */ + explicit GenericRPCConnection(AbstractWaitableInputOutput *inputOutput); + virtual ~GenericRPCConnection(); + + virtual void AsyncCall(const RPCFunction &function); + virtual void Ping(); +}; +} +} // namespace DPL + +#endif // DPL_GENERIC_RPC_CONNECTION_H diff --git a/modules/rpc/include/dpl/rpc/generic_socket_rpc_client.h b/modules/rpc/include/dpl/rpc/generic_socket_rpc_client.h new file mode 100644 index 0000000..9629e61 --- /dev/null +++ b/modules/rpc/include/dpl/rpc/generic_socket_rpc_client.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket_rpc_client.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for generic socket RPC client + */ +#ifndef DPL_GENERIC_SOCKET_RPC_CLIENT_H +#define DPL_GENERIC_SOCKET_RPC_CLIENT_H + +#include +#include +#include + +namespace DPL { +namespace RPC { +template +class GenericSocketRPCClient : + public AbstractRPCConnector, + private DPL::Event::EventListener +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) + }; + + protected: + // Derived class implementations for connection managment + virtual AbstractRPCConnection *OpenSpecificConnection(SocketType *socket) = + 0; + + private: + typedef std::set InternalConnectionSet; + InternalConnectionSet m_internalConnectionSet; + + virtual void OnEventReceived( + const DPL::Socket::AbstractSocketEvents::ConnectedEvent &event) + { + // Retrieve socket sender + SocketType *socket = static_cast(event.GetSender()); + + LogPedantic("Connection with RPC server established"); + + // Is this connection still tracked ? + // It might have disappeared on close + typename InternalConnectionSet::iterator iterator = + m_internalConnectionSet.find(socket); + + if (iterator == m_internalConnectionSet.end()) { + LogPedantic("RPC client connection socket disappeared"); + return; + } + + // Open specific connection implementation + AbstractRPCConnection *connection = OpenSpecificConnection(socket); + + // Remove internal connection + socket->EventSupport + ::RemoveListener(this); + m_internalConnectionSet.erase(iterator); + + // Retrieve ID once again + AbstractRPCConnectionID connectionID = + static_cast(socket); + + // Inform listeners + DPL::Event::EventSupport:: + EmitEvent(AbstractRPCConnectorEvents::ConnectionEstablishedEvent( + connectionID, connection, EventSender( + this)), DPL::Event::EmitMode::Queued); + } + + public: + explicit GenericSocketRPCClient() + {} + + virtual ~GenericSocketRPCClient() + { + // Always close all connections + CloseAll(); + } + + AbstractRPCConnectionID Open(const Address &socketAddress) + { + LogPedantic("Starting client: " << socketAddress.ToString()); + + // Alloc new socket + SocketType *socket = new SocketType(); + + // Add socket listeners + socket->EventSupport + ::AddListener(this); + + Try + { + // Open socket + socket->Open(); + + // Start connecting to server + socket->Connect(Address(socketAddress)); + } + Catch(DPL::Socket::AbstractSocket::Exception::Base) + { + // Remove back socket listener + socket->EventSupport::RemoveListener(this); + + // Log debug message + LogPedantic("Cannot connect to: " << socketAddress.ToString()); + + // Problem with client startup + ReThrowMsg(typename Exception::OpenFailed, socketAddress.ToString()); + } + + // Register new internal connection + m_internalConnectionSet.insert(socket); + + // Debug info + LogPedantic( + "Client started on interface: " << + socket->GetLocalAddress().ToString()); + + // Return unique identifier + return static_cast(socket); + } + + void Close(AbstractRPCConnectionID connectionID) + { + LogPedantic("Closing client interface..."); + + // Get socket from ID + SocketType *socket = static_cast(connectionID); + + // Find corresponding internal connection + typename InternalConnectionSet::iterator iterator = + m_internalConnectionSet.find(socket); + + if (iterator == m_internalConnectionSet.end()) { + return; + } + + // Close socket + socket->Close(); + + // Remove internal socket + socket->EventSupport + ::RemoveListener(this); + delete socket; + + m_internalConnectionSet.erase(iterator); + + // Done + LogPedantic("Closed"); + } + + void CloseAll() + { + while (!m_internalConnectionSet.empty()) { + Close(static_cast(*m_internalConnectionSet + .begin())); + } + } +}; +} +} // namespace DPL + +#endif // DPL_GENERIC_SOCKET_RPC_CLIENT_H diff --git a/modules/rpc/include/dpl/rpc/generic_socket_rpc_connection.h b/modules/rpc/include/dpl/rpc/generic_socket_rpc_connection.h new file mode 100644 index 0000000..6c2d0ce --- /dev/null +++ b/modules/rpc/include/dpl/rpc/generic_socket_rpc_connection.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket_rpc_connection.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for generic socket RPC connection + */ +#ifndef DPL_GENERIC_SOCKET_RPC_CONNECTION_H +#define DPL_GENERIC_SOCKET_RPC_CONNECTION_H + +#include + +namespace DPL { +namespace RPC { +template +class GenericSocketRPCConnection : + public GenericRPCConnection +{ + protected: + // Private construction with socket acquisition + GenericSocketRPCConnection(SocketType *socket) : + GenericRPCConnection(socket) + {} +}; +} +} // namespace DPL + +#endif // DPL_GENERIC_SOCKET_RPC_CONNECTION_H diff --git a/modules/rpc/include/dpl/rpc/generic_socket_rpc_server.h b/modules/rpc/include/dpl/rpc/generic_socket_rpc_server.h new file mode 100644 index 0000000..a4cae00 --- /dev/null +++ b/modules/rpc/include/dpl/rpc/generic_socket_rpc_server.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket_rpc_server.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for generic socket RPC server + */ +#ifndef DPL_GENERIC_SOCKET_RPC_SERVER_H +#define DPL_GENERIC_SOCKET_RPC_SERVER_H + +#include +#include +#include + +namespace DPL { +namespace RPC { +template +class GenericSocketRPCServer : + public AbstractRPCConnector, + private DPL::Event::EventListener +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) + }; + + protected: + // Derived class implementations for connection managment + virtual AbstractRPCConnection *OpenSpecificConnection(SocketType *socket) = + 0; + + private: + typedef std::set InternalInterfaceSet; + InternalInterfaceSet m_internalInterfacesSet; + + virtual void OnEventReceived( + const DPL::Socket::AbstractSocketEvents::AcceptEvent &event) + { + // Retrieve socket sender + SocketType *server = static_cast(event.GetSender()); + + // Is this interface still tracked ? + // It might have disappeared on close + typename InternalInterfaceSet::iterator iterator = + m_internalInterfacesSet.find(server); + + if (iterator == m_internalInterfacesSet.end()) { + LogPedantic("RPC server interface socket disappeared"); + return; + } + + // Accept incoming client + SocketType *client = static_cast(server->Accept()); + if (client == NULL) { + LogPedantic("Spontaneous accept on socket occurred"); + return; + } + + LogPedantic( + "Client connected to server: " << + client->GetRemoteAddress().ToString()); + + // Open specific connection implementation + AbstractRPCConnection *connection = OpenSpecificConnection(client); + + // Retrieve ID once again + AbstractRPCConnectionID connectionID = + static_cast(server); + + // Inform listeners + DPL::Event::EventSupport:: + EmitEvent(AbstractRPCConnectorEvents::ConnectionEstablishedEvent( + connectionID, connection, EventSender( + this)), DPL::Event::EmitMode::Queued); + } + + public: + explicit GenericSocketRPCServer() + {} + + virtual ~GenericSocketRPCServer() + { + // Always close connection + CloseAll(); + } + + AbstractRPCConnectionID Open(const Address &socketAddress) + { + LogPedantic("Starting server: " << socketAddress.ToString()); + + // Alloc new socket + SocketType *socket = new SocketType(); + + // Add socket listener + socket->EventSupport:: + AddListener(this); + + Try + { + // Open socket + socket->Open(); + + // Bind socket address + socket->Bind(socketAddress); + + // Start listening + socket->Listen(8); + } + Catch(DPL::Socket::AbstractSocket::Exception::Base) + { + // Remove back socket listener + socket->EventSupport + ::RemoveListener(this); + + // Log debug + LogPedantic("Cannot start server: " << socketAddress.ToString()); + + // Problem with server startup + ReThrowMsg(typename Exception::OpenFailed, socketAddress.ToString()); + } + + // Register new internal connection + m_internalInterfacesSet.insert(socket); + + // Debug info + LogPedantic( + "Server started on interface: " << + socket->GetLocalAddress().ToString()); + + // Return unique identifier + return static_cast(socket); + } + + void Close(AbstractRPCConnectionID connectionID) + { + LogPedantic("Closing server interface..."); + + // Get socket from ID + SocketType *socket = static_cast(connectionID); + + // Find corresponding internal connection + typename InternalInterfaceSet::iterator iterator = + m_internalInterfacesSet.find(socket); + + if (iterator == m_internalInterfacesSet.end()) { + return; + } + + // Close socket + socket->Close(); + + // Remove socket listeners + socket->EventSupport:: + RemoveListener(this); + delete socket; + + m_internalInterfacesSet.erase(iterator); + + // Done + LogPedantic("Closed"); + } + + void CloseAll() + { + while (!m_internalInterfacesSet.empty()) { + Close(static_cast(*m_internalInterfacesSet + .begin())); + } + } +}; +} +} // namespace DPL + +#endif // DPL_GENERIC_SOCKET_RPC_SERVER_H diff --git a/modules/rpc/include/dpl/rpc/rpc_function.h b/modules/rpc/include/dpl/rpc/rpc_function.h new file mode 100644 index 0000000..a01235f --- /dev/null +++ b/modules/rpc/include/dpl/rpc/rpc_function.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file rpc_function.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for RPC function + */ +#ifndef DPL_RPC_FUNCTION_H +#define DPL_RPC_FUNCTION_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace RPC { +class RPCFunction : public IStream +{ + protected: + BinaryQueue m_buffer; ///< Serialized RPC function call as a binary queue + + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, ParseFailed) + }; + + /** + * Constructor + */ + RPCFunction() + {} + + /** + * Constructor + * + * @param buffer Binary queue to copy initialization data from + */ + RPCFunction(const BinaryQueue &buffer) + { + m_buffer.AppendCopyFrom(buffer); + } + + /** + * Destructor + */ + virtual ~RPCFunction() + {} + + /** + * Append argument to call + * + * @param[in] arg Template based argument to append + * @return none + * @warning Carefully add any pointers to buffer because of template nature + * of this method + */ + template + void AppendArg(const Type &arg) + { + size_t argSize = sizeof(arg); + m_buffer.AppendCopy(&argSize, sizeof(argSize)); + m_buffer.AppendCopy(&arg, sizeof(arg)); + } + + /** + * Append @a std::string argument to call + * + * @param[in] arg String to append to function call + * @return none + */ + void AppendArg(const std::string &arg) + { + size_t argSize = arg.size(); + m_buffer.AppendCopy(&argSize, sizeof(argSize)); + m_buffer.AppendCopy(arg.c_str(), argSize); + } + + /** + * Append @a DPL::String argument to call + * + * @param[in] arg String to append to function call + * @return none + */ + void AppendArg(const String &arg) + { + std::string localStdString = ToUTF8String(arg); + AppendArg(localStdString); + } + + /** + * Consume argument from call. Arguments are retrieved in non-reversed order + * (same as they were pushed onto RPC function argument stack) + * + * @param[out] arg Reference to output template based argument + * @warning Carefully add any pointers to buffer because of template nature + * of this method + * @return none + */ + template + void ConsumeArg(Type &arg) + { + Try + { + size_t argSize = sizeof(arg); + m_buffer.FlattenConsume(&argSize, sizeof(argSize)); + + if (argSize != sizeof(arg)) { + ThrowMsg(Exception::ParseFailed, "Stream parse CRC failed"); + } + + m_buffer.FlattenConsume(&arg, sizeof(arg)); + } + Catch(BinaryQueue::Exception::OutOfData) + { + ReThrowMsg(Exception::ParseFailed, "Unexpected end of stream"); + } + } + + /** + * Consume @a std::string argument from call. Arguments are retrieved in + * non-reversed order + * (same as they were pushed onto RPC function argument stack) + * + * @param[out] arg Reference to output @a std::string argument + * @return none + */ + void ConsumeArg(std::string &arg) + { + Try + { + std::string::size_type size; + m_buffer.FlattenConsume(&size, sizeof(size)); + ScopedArray str(new char[size]); + m_buffer.FlattenConsume(str.Get(), size); + arg = std::string(str.Get(), str.Get() + size); + } + Catch(BinaryQueue::Exception::OutOfData) + { + ReThrowMsg(Exception::ParseFailed, "Unexpected end of stream"); + } + } + + /** + * Consume @a DPL::String argument from call. Arguments are converted to + * UTF-8 string + * + * @param[out] arg Reference to output @a DPL::String argument + * @return none + */ + void ConsumeArg(String &arg) + { + std::string consumedStdString; + ConsumeArg(consumedStdString); + arg = FromUTF8String(consumedStdString); + } + + /** + * Serialize all function parameters into single binary queue + * + * @return Serialized binary queue representation of RPC function + */ + BinaryQueue Serialize() const + { + return m_buffer; + } + + /** + * Reads binary data from serialized stream + * + * @param num number of bytes to read + * @param bytes buffer for read data + */ + virtual void Read(size_t num, void * bytes) + { + m_buffer.FlattenConsume(bytes, num); + } + + /** + * Writes binary data to serialized stream + * + * @param num number of bytes to write to serialization buffer + * @param bytes buffer for data to write + */ + virtual void Write(size_t num, const void * bytes) + { + m_buffer.AppendCopy(bytes, num); + } +}; +} +} // namespace DPL + +#endif // DPL_RPC_FUNCTION_H diff --git a/modules/rpc/include/dpl/rpc/unix_socket_rpc_client.h b/modules/rpc/include/dpl/rpc/unix_socket_rpc_client.h new file mode 100644 index 0000000..aba62ec --- /dev/null +++ b/modules/rpc/include/dpl/rpc/unix_socket_rpc_client.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket_rpc_client.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for unix socket RPC client + */ +#ifndef DPL_UNIX_SOCKET_RPC_CLIENT_H +#define DPL_UNIX_SOCKET_RPC_CLIENT_H + +#include +#include +#include + +namespace DPL { +namespace RPC { +class UnixSocketRPCClient : + public GenericSocketRPCClient +{ + protected: + virtual AbstractRPCConnection *OpenSpecificConnection( + DPL::Socket::UnixSocket *socket); + + public: + AbstractRPCConnectionID Open(const std::string &fileName); +}; +} +} // namespace DPL + +#endif // DPL_UNIX_SOCKET_RPC_CLIENT_H diff --git a/modules/rpc/include/dpl/rpc/unix_socket_rpc_connection.h b/modules/rpc/include/dpl/rpc/unix_socket_rpc_connection.h new file mode 100644 index 0000000..9b00141 --- /dev/null +++ b/modules/rpc/include/dpl/rpc/unix_socket_rpc_connection.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket_rpc_connection.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for unix socket RPC connection + */ +#ifndef DPL_UNIX_SOCKET_RPC_CONNECTION_H +#define DPL_UNIX_SOCKET_RPC_CONNECTION_H + +#include +#include + +namespace DPL { +namespace RPC { +class UnixSocketRPCConnection : + public GenericSocketRPCConnection +{ + public: + // Socket acquisition + UnixSocketRPCConnection(DPL::Socket::UnixSocket *socket); +}; +} +} // namespace DPL + +#endif // DPL_UNIX_SOCKET_RPC_CONNECTION_H diff --git a/modules/rpc/include/dpl/rpc/unix_socket_rpc_server.h b/modules/rpc/include/dpl/rpc/unix_socket_rpc_server.h new file mode 100644 index 0000000..de2b605 --- /dev/null +++ b/modules/rpc/include/dpl/rpc/unix_socket_rpc_server.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket_rpc_server.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for unix socket RPC server + */ +#ifndef DPL_UNIX_SOCKET_RPC_SERVER_H +#define DPL_UNIX_SOCKET_RPC_SERVER_H + +#include +#include +#include + +namespace DPL { +namespace RPC { +class UnixSocketRPCServer : + public GenericSocketRPCServer +{ + protected: + virtual AbstractRPCConnection *OpenSpecificConnection( + DPL::Socket::UnixSocket *socket); + + public: + AbstractRPCConnectionID Open(const std::string &fileName); +}; +} +} // namespace DPL + +#endif // DPL_UNIX_SOCKET_RPC_SERVER_H diff --git a/modules/rpc/src/abstract_rpc_connection.cpp b/modules/rpc/src/abstract_rpc_connection.cpp new file mode 100644 index 0000000..e5455e2 --- /dev/null +++ b/modules/rpc/src/abstract_rpc_connection.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_rpc_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract RPC connection + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/rpc/src/abstract_rpc_connector.cpp b/modules/rpc/src/abstract_rpc_connector.cpp new file mode 100644 index 0000000..2bd879e --- /dev/null +++ b/modules/rpc/src/abstract_rpc_connector.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_rpc_connector.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract RPC connector + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/rpc/src/generic_rpc_connection.cpp b/modules/rpc/src/generic_rpc_connection.cpp new file mode 100644 index 0000000..6b16f28 --- /dev/null +++ b/modules/rpc/src/generic_rpc_connection.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_rpc_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of generic RPC connection + */ +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace RPC { +namespace // anonymous +{ +namespace Protocol { +// Packet definitions +enum PacketType +{ + PacketType_AsyncCall, + PacketType_PingPong +}; + +struct Header +{ + unsigned short size; + unsigned short type; +} DPL_ALIGNED(1); + +struct AsyncCall : + public Header +{ + unsigned char data[1]; +} DPL_ALIGNED(1); +} // namespace Protocol +} // namespace anonymous + +GenericRPCConnection::GenericRPCConnection( + AbstractWaitableInputOutput *inputOutput) : + m_inputOutput(inputOutput) +{ + LogPedantic("Opening generic RPC..."); + WaitableInputOutputExecutionContextSupport::Open(inputOutput); + LogPedantic("Generic RPC opened"); +} + +GenericRPCConnection::~GenericRPCConnection() +{ + // Ensure RPC is closed + LogPedantic("Closing generic RPC..."); + WaitableInputOutputExecutionContextSupport::Close(); + LogPedantic("Generic RPC closed"); +} + +void GenericRPCConnection::AsyncCall(const RPCFunction &function) +{ + LogPedantic("Executing async call"); + + // Create binary call + BinaryQueue serializedCall = function.Serialize(); + + // Append buffers + Protocol::AsyncCall call; + call.size = static_cast(serializedCall.Size()); + call.type = Protocol::PacketType_AsyncCall; + + m_outputStream.AppendCopy(&call, sizeof(Protocol::Header)); + m_outputStream.AppendMoveFrom(serializedCall); + + // Try to feed output with data + Try + { + FeedOutput(); + } + Catch(WaitableInputOutputExecutionContextSupport::Exception::NotOpened) + { + // Error occurred while feeding + ReThrow(AbstractRPCConnection::Exception::AsyncCallFailed); + } +} + +void GenericRPCConnection::Ping() +{ + LogPedantic("Executing ping call"); + + // Append buffers + Protocol::AsyncCall call; + call.size = 0; + call.type = Protocol::PacketType_PingPong; + + m_outputStream.AppendCopy(&call, sizeof(Protocol::Header)); + + // Try to feed output with data + Try + { + FeedOutput(); + } + Catch(WaitableInputOutputExecutionContextSupport::Exception::NotOpened) + { + // Error occurred while feeding + ReThrow(AbstractRPCConnection::Exception::PingFailed); + } +} + +void GenericRPCConnection::OnInputStreamRead() +{ + LogPedantic("Interpreting " << m_inputStream.Size() << " bytes buffer"); + + // Enough bytes to read at least one header ? + if (m_inputStream.Size() >= sizeof(Protocol::Header)) { + // Begin consuming as much packets as it is possible + while (m_inputStream.Size() >= sizeof(Protocol::Header)) { + Protocol::Header header; + m_inputStream.Flatten(&header, sizeof(header)); + + if (m_inputStream.Size() >= sizeof(Protocol::Header) + + header.size) + { + LogPedantic("Will parse packet of type: " << header.type); + + // Allocate new packet (header + real packet data) + void *binaryPacket = malloc( + sizeof(Protocol::Header) + header.size); + + if (binaryPacket == NULL) { + throw std::bad_alloc(); + } + + // Get it from stream + m_inputStream.FlattenConsume( + binaryPacket, + sizeof(Protocol::Header) + + header.size); + + // Parse specific packet + switch (header.type) { + case Protocol::PacketType_AsyncCall: + { + BinaryQueue call; + + // No need to delete packet data, we can use it + call.AppendUnmanaged(binaryPacket, + sizeof(Protocol::Header) + header.size, + &BinaryQueue::BufferDeleterFree, + NULL); + + // ...but just remove protocol header + call.Consume(sizeof(Protocol::Header)); + + LogPedantic( + "Async call of size: " << header.size << + " parsed"); + + // Call async call event listeners + DPL::Event::EventSupport:: + EmitEvent(AbstractRPCConnectionEvents::AsyncCallEvent( + RPCFunction(call), EventSender( + this)), DPL::Event::EmitMode::Queued); + } + break; + + case Protocol::PacketType_PingPong: + { + // Reply with ping/pong + Ping(); + + // Do not need packet data + free(binaryPacket); + + LogPedantic("Ping pong replied"); + } + break; + + default: + LogPedantic("Warning: Unknown packet type"); + free(binaryPacket); + break; + } + } else { + LogPedantic("Too few bytes to read packet"); + break; + } + } + } else { + LogPedantic("Too few bytes to read header"); + } +} + +void GenericRPCConnection::OnInputStreamClosed() +{ + // Emit closed event + DPL::Event::EventSupport + :: + EmitEvent(AbstractRPCConnectionEvents::ConnectionClosedEvent( + EventSender(this)), DPL::Event::EmitMode::Queued); +} + +void GenericRPCConnection::OnInputStreamBroken() +{ + // Emit broken event + DPL::Event::EventSupport + :: + EmitEvent(AbstractRPCConnectionEvents::ConnectionBrokenEvent( + EventSender(this)), DPL::Event::EmitMode::Queued); +} +} +} // namespace DPL diff --git a/modules/rpc/src/generic_socket_rpc_client.cpp b/modules/rpc/src/generic_socket_rpc_client.cpp new file mode 100644 index 0000000..51c1b97 --- /dev/null +++ b/modules/rpc/src/generic_socket_rpc_client.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket_rpc_client.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of generic socket RPC + * client + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/rpc/src/generic_socket_rpc_connection.cpp b/modules/rpc/src/generic_socket_rpc_connection.cpp new file mode 100644 index 0000000..2d84a4a --- /dev/null +++ b/modules/rpc/src/generic_socket_rpc_connection.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket_rpc_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of generic socket RPC + * connection + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/rpc/src/generic_socket_rpc_server.cpp b/modules/rpc/src/generic_socket_rpc_server.cpp new file mode 100644 index 0000000..a0590f4 --- /dev/null +++ b/modules/rpc/src/generic_socket_rpc_server.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket_rpc.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of generic socket RPC + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/rpc/src/unix_socket_rpc_client.cpp b/modules/rpc/src/unix_socket_rpc_client.cpp new file mode 100644 index 0000000..8b105f2 --- /dev/null +++ b/modules/rpc/src/unix_socket_rpc_client.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket_rpc_client.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of unix socket RPC client + */ +#include +#include +#include + +namespace DPL { +namespace RPC { +AbstractRPCConnection *UnixSocketRPCClient::OpenSpecificConnection( + DPL::Socket::UnixSocket *socket) +{ + // Allocate new UNIX/RPC connection object + UnixSocketRPCConnection *connection = new UnixSocketRPCConnection(socket); + + // Return new connection + return connection; +} + +AbstractRPCConnectionID UnixSocketRPCClient::Open(const std::string &fileName) +{ + return GenericSocketRPCClient::Open(Address( + fileName)); +} +} +} // namespace DPL diff --git a/modules/rpc/src/unix_socket_rpc_connection.cpp b/modules/rpc/src/unix_socket_rpc_connection.cpp new file mode 100644 index 0000000..b21098d --- /dev/null +++ b/modules/rpc/src/unix_socket_rpc_connection.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket_rpc_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of unix socket RPC + * connection + */ +#include +#include + +namespace DPL { +namespace RPC { +UnixSocketRPCConnection::UnixSocketRPCConnection( + DPL::Socket::UnixSocket *socket) : + GenericSocketRPCConnection(socket) +{} +} +} // namespace DPL diff --git a/modules/rpc/src/unix_socket_rpc_server.cpp b/modules/rpc/src/unix_socket_rpc_server.cpp new file mode 100644 index 0000000..e9dd9ab --- /dev/null +++ b/modules/rpc/src/unix_socket_rpc_server.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket_rpc_server.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of unix socket RPC server + */ +#include +#include +#include + +namespace DPL { +namespace RPC { +AbstractRPCConnection *UnixSocketRPCServer::OpenSpecificConnection( + DPL::Socket::UnixSocket *socket) +{ + // Allocate new UNIX/RPC connection object + UnixSocketRPCConnection *connection = new UnixSocketRPCConnection(socket); + + // Return new connection + return connection; +} + +AbstractRPCConnectionID UnixSocketRPCServer::Open(const std::string &fileName) +{ + return GenericSocketRPCServer::Open(Address( + fileName)); +} +} +} // namespace DPL diff --git a/modules/security_origin_dao/CMakeLists.txt b/modules/security_origin_dao/CMakeLists.txt new file mode 100644 index 0000000..3375925 --- /dev/null +++ b/modules/security_origin_dao/CMakeLists.txt @@ -0,0 +1,56 @@ +SET(TARGET_SECURITY_ORIGIN_DAO_DB "Sqlite3DbSecurityOrigin") + +ADD_CUSTOM_COMMAND( OUTPUT .security_origin.db + COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/.security_origin.db + COMMAND gcc -Wall -I${PROJECT_SOURCE_DIR}/modules/db/include -I${PROJECT_SOURCE_DIR}/modules/security_origin_dao/orm -E ${PROJECT_SOURCE_DIR}/modules/security_origin_dao/orm/security_origin_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_BINARY_DIR}/security_origin_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_BINARY_DIR}/.security_origin.db ".read ${CMAKE_CURRENT_BINARY_DIR}/security_origin_db.sql" || rm -f ${CMAKE_CURRENT_BINARY_DIR}/.security_origin.db + DEPENDS ${PROJECT_SOURCE_DIR}/modules/security_origin_dao/orm/security_origin_db_sql_generator.h ${PROJECT_SOURCE_DIR}/modules/security_origin_dao/orm/security_origin_db + ) + +ADD_CUSTOM_COMMAND( OUTPUT .security_origin.db-journal + COMMAND touch + ARGS ${CMAKE_CURRENT_BINARY_DIR}/.security_origin.db-journal + ) + +ADD_CUSTOM_TARGET(${TARGET_SECURITY_ORIGIN_DAO_DB} ALL DEPENDS .security_origin.db .security_origin.db-journal) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/security_origin_db.sql DESTINATION share/wrt-engine/) + +############################################################################### + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(SECURITY_ORIGIN_DAO_DEPS + glib-2.0 + dlog + REQUIRED) + +SET(SECURITY_ORIGIN_DAO_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/modules/security_origin_dao/include + ${PROJECT_SOURCE_DIR}/modules/security_origin_dao/orm + ${PROJECT_SOURCE_DIR}/modules/core/include + ${PROJECT_SOURCE_DIR}/modules/db/include + ${PROJECT_SOURCE_DIR}/modules/log/include + ${PROJECT_SOURCE_DIR}/modules/widget_dao/include +) + +SET(SECURITY_ORIGIN_DAO_SOURCES + dao/security_origin_dao_types.cpp + dao/security_origin_dao.cpp +) + +INCLUDE_DIRECTORIES(SYSTEM ${SECURITY_ORIGIN_DAO_DEPS_INCLUDE_DIRS} ) +INCLUDE_DIRECTORIES(${SECURITY_ORIGIN_DAO_INCLUDE_DIRS}) + +ADD_LIBRARY(${TARGET_SECURITY_ORIGIN_DAO_LIB} SHARED ${SECURITY_ORIGIN_DAO_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_SECURITY_ORIGIN_DAO_LIB} PROPERTIES SOVERSION ${API_VERSION} VERSION ${VERSION}) +TARGET_LINK_LIBRARIES(${TARGET_SECURITY_ORIGIN_DAO_LIB} ${TARGET_DPL_EFL} ${TARGET_DPL_DB_EFL} ${TARGET_WRT_DAO_RO_LIB} ${SECURITY_ORIGIN_DAO_DEPS_LIBRARIES}) +ADD_DEPENDENCIES(${TARGET_SECURITY_ORIGIN_DAO_LIB} ${TARGET_SECURITY_ORIGIN_DAO_DB}) + +INSTALL(TARGETS ${TARGET_SECURITY_ORIGIN_DAO_LIB} DESTINATION lib) + +INSTALL(FILES + include/wrt-commons/security-origin-dao/security_origin_dao_types.h + include/wrt-commons/security-origin-dao/security_origin_dao.h + DESTINATION include/dpl-efl/wrt-commons/security-origin-dao +) + diff --git a/modules/security_origin_dao/dao/security_origin_dao.cpp b/modules/security_origin_dao/dao/security_origin_dao.cpp new file mode 100644 index 0000000..7551189 --- /dev/null +++ b/modules/security_origin_dao/dao/security_origin_dao.cpp @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file security_origin_dao.cpp + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + * @brief This file contains the definition of security origin dao class. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::security_origin; + +namespace SecurityOriginDB { +using namespace WrtDB; +#define SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN Try + +#define SQL_CONNECTION_EXCEPTION_HANDLER_END(message) \ + Catch(DPL::DB::SqlConnection::Exception::Base) { \ + LogError(message); \ + ReThrowMsg(SecurityOriginDAO::Exception::DatabaseError, \ + message); \ + } + +// database connection +#define SECURITY_ORIGIN_DB_INTERNAL(tlsCommand, InternalType, interface) \ + InternalType tlsCommand(interface); +#define SECURITY_ORIGIN_DB_SELECT(name, type, interface) \ + SECURITY_ORIGIN_DB_INTERNAL(name, type::Select, interface) +#define SECURITY_ORIGIN_DB_INSERT(name, type, interface) \ + SECURITY_ORIGIN_DB_INTERNAL(name, type::Insert, interface) +#define SECURITY_ORIGIN_DB_UPDATE(name, type, interface) \ + SECURITY_ORIGIN_DB_INTERNAL(name, type::Update, interface) +#define SECURITY_ORIGIN_DB_DELETE(name, type, interface) \ + SECURITY_ORIGIN_DB_INTERNAL(name, type::Delete, interface) + +typedef DPL::DB::ORM::security_origin::SecurityOriginInfo::Row + SecurityOriginInfoRow; +typedef DPL::DB::ORM::security_origin::SecurityOriginInfo::Select::RowList + SecurityOriginInfoRowList; + +namespace { +DPL::DB::SqlConnection::Flag::Option SECURITY_ORIGIN_DB_OPTION = + DPL::DB::SqlConnection::Flag::RW; +DPL::DB::SqlConnection::Flag::Type SECURITY_ORIGIN_DB_TYPE = + DPL::DB::SqlConnection::Flag::UseLucene; +const char* const SECURITY_ORIGIN_DB_NAME = ".security_origin.db"; +const char* const SECURITY_ORIGIN_DB_SQL_PATH = + "/usr/share/wrt-engine/security_origin_db.sql"; +const char* const SECURITY_DATABASE_JOURNAL_FILENAME = "-journal"; + +const int WEB_APPLICATION_UID = 5000; +const int WEB_APPLICATION_GUID = 5000; + +std::string createDatabasePath(const WrtDB::TizenPkgId &pkgName) +{ + std::stringstream filename; + + filename << WrtDB::WidgetConfig::GetWidgetPersistentStoragePath(pkgName) + << "/" + << SECURITY_ORIGIN_DB_NAME; + return filename.str(); +} + +void checkDatabase(std::string databasePath) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + if (databasePath.empty()) { + ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, + "Wrong database Path is passed"); + } + + struct stat buffer; + if (stat(databasePath.c_str(), &buffer) != 0) { + //Create fresh database + LogDebug("Creating database " << databasePath); + + std::fstream file; + file.open(SECURITY_ORIGIN_DB_SQL_PATH, std::ios_base::in); + if (!file) { + ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, + "Fail to get database Path"); + } + + std::stringstream ssBuffer; + ssBuffer << file.rdbuf(); + + file.close(); + + DPL::DB::SqlConnection con(databasePath, + SECURITY_ORIGIN_DB_TYPE, + SECURITY_ORIGIN_DB_OPTION); + con.ExecCommand(ssBuffer.str().c_str()); + + if(chown(databasePath.c_str(), + WEB_APPLICATION_UID, + WEB_APPLICATION_GUID) != 0) + { + ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, + "Fail to change uid/guid"); + } + std::string databaseJournal = + databasePath + SECURITY_DATABASE_JOURNAL_FILENAME; + if(chown(databaseJournal.c_str(), + WEB_APPLICATION_UID, + WEB_APPLICATION_GUID) != 0) + { + ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, + "Fail to change uid/guid"); + } + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to get database Path") +} +} // namespace SecurityOriginDB + +SecurityOriginDAO::SecurityOriginDAO(const WrtDB::TizenPkgId &pkgName) : + m_dbPath(createDatabasePath(pkgName)), + m_dbInterface(m_dbPath, SECURITY_ORIGIN_DB_TYPE) +{ + checkDatabase(m_dbPath); + m_dbInterface.AttachToThread(SECURITY_ORIGIN_DB_OPTION); +} + +SecurityOriginDAO::~SecurityOriginDAO() +{ + m_dbInterface.DetachFromThread(); +} + +SecurityOriginDataList SecurityOriginDAO::getSecurityOriginDataList(void) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + SecurityOriginDataList list; + SECURITY_ORIGIN_DB_SELECT(select, SecurityOriginInfo, &m_dbInterface); + typedef std::list RowList; + RowList rowList = select.GetRowList(); + + FOREACH(it, rowList) { + Origin origin(it->Get_scheme(), it->Get_host(), it->Get_port()); + list.push_back( + SecurityOriginDataPtr( + new SecurityOriginData( + static_cast(it->Get_feature()), origin))); + } + return list; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get data list") +} + +Result SecurityOriginDAO::getResult(const SecurityOriginData &data) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + SECURITY_ORIGIN_DB_SELECT(select, SecurityOriginInfo, &m_dbInterface); + Equals eFeature(data.feature); + Equals eScheme(data.origin.scheme); + Equals eHost(data.origin.host); + Equals ePort(data.origin.port); + select.Where(And(And(And(eFeature, eScheme), eHost), ePort)); + SecurityOriginInfoRowList rows = select.GetRowList(); + if (rows.empty()) { + return RESULT_UNKNOWN; + } + SecurityOriginInfoRow row = rows.front(); + return static_cast(row.Get_result()); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("getResult error") +} + +bool SecurityOriginDAO::isReadOnly(const SecurityOriginData &data) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + SECURITY_ORIGIN_DB_SELECT(select, SecurityOriginInfo, &m_dbInterface); + Equals eFeature(data.feature); + Equals eScheme(data.origin.scheme); + Equals eHost(data.origin.host); + Equals ePort(data.origin.port); + select.Where(And(And(And(eFeature, eScheme), eHost), ePort)); + SecurityOriginInfoRowList rows = select.GetRowList(); + if (rows.empty()) { + return RESULT_UNKNOWN; + } + SecurityOriginInfoRow row = rows.front(); + return row.Get_readonly() ? true : false; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("isReadOnly error") +} + +void SecurityOriginDAO::setSecurityOriginData(const SecurityOriginData &data, + const Result result, + const bool readOnly) +{ + if (true == hasResult(data)) { + updateData(data, result, readOnly); + } else { + insertData(data, result, readOnly); + } +} + +void SecurityOriginDAO::setPrivilegeSecurityOriginData( + const Feature feature, + bool isOnlyAllowedLocalOrigin) +{ + //TODO: this breaks app:// scheme code -> no case for app scheme + Origin origin(DPL::FromUTF8String("file"), + DPL::FromUTF8String(""), + 0); + if (!isOnlyAllowedLocalOrigin) { + origin.scheme = DPL::FromUTF8String(""); + } + SecurityOriginData data(feature, origin); + setSecurityOriginData(data, RESULT_ALLOW_ALWAYS, true); +} + +void SecurityOriginDAO::removeSecurityOriginData( + const SecurityOriginData &data) +{ + if (false == hasResult(data)) { + // There is no data + return; + } + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&m_dbInterface); + SECURITY_ORIGIN_DB_DELETE(del, SecurityOriginInfo, &m_dbInterface) + Equals eFeature(data.feature); + Equals eScheme(data.origin.scheme); + Equals eHost(data.origin.host); + Equals ePort(data.origin.port); + del.Where(And(And(And(eFeature, eScheme), eHost), ePort)); + del.Execute(); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to remove security origin data") +} + +void SecurityOriginDAO::removeSecurityOriginData(const Result result) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&m_dbInterface); + SECURITY_ORIGIN_DB_DELETE(del, SecurityOriginInfo, &m_dbInterface) + del.Where(Equals(result)); + del.Execute(); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to remove data by result") +} + +bool SecurityOriginDAO::hasResult(const SecurityOriginData &data) +{ + Result ret = getResult(data); + return (ret != RESULT_UNKNOWN); +} + +void SecurityOriginDAO::insertData(const SecurityOriginData &data, + const Result result, + const bool readOnly) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + SecurityOriginInfoRow row; + row.Set_feature(data.feature); + row.Set_scheme(data.origin.scheme); + row.Set_host(data.origin.host); + row.Set_port(data.origin.port); + row.Set_result(result); + row.Set_readonly(readOnly ? 1 : 0); + + ScopedTransaction transaction(&m_dbInterface); + SECURITY_ORIGIN_DB_INSERT(insert, SecurityOriginInfo, &m_dbInterface); + insert.Values(row); + insert.Execute(); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to insert") +} + +void SecurityOriginDAO::updateData(const SecurityOriginData &data, + const Result result, + const bool readOnly) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + SecurityOriginInfoRow row; + row.Set_feature(data.feature); + row.Set_scheme(data.origin.scheme); + row.Set_host(data.origin.host); + row.Set_port(data.origin.port); + row.Set_result(result); + row.Set_readonly(readOnly ? 1 : 0); + + ScopedTransaction transaction(&m_dbInterface); + SECURITY_ORIGIN_DB_UPDATE(update, SecurityOriginInfo, &m_dbInterface); + Equals eFeature(data.feature); + Equals eScheme(data.origin.scheme); + Equals eHost(data.origin.host); + Equals ePort(data.origin.port); + update.Where(And(And(And(eFeature, eScheme), eHost), ePort)); + update.Values(row); + update.Execute(); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to update") +} +#undef SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN +#undef SQL_CONNECTION_EXCEPTION_HANDLER_END +} // namespace SecurityOriginDB diff --git a/modules/security_origin_dao/dao/security_origin_dao_types.cpp b/modules/security_origin_dao/dao/security_origin_dao_types.cpp new file mode 100755 index 0000000..8d2a9f8 --- /dev/null +++ b/modules/security_origin_dao/dao/security_origin_dao_types.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file security_origin_dao_types.cpp + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + * @brief This file contains the implementation of + * common data types for wrt_security_origin.db + */ + +#include +#include + +namespace SecurityOriginDB { +} // namespace SecurityOriginDB diff --git a/modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao.h b/modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao.h new file mode 100644 index 0000000..d922764 --- /dev/null +++ b/modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file securoty_origin_dao.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of security origin dao + */ +#ifndef _SECURITY_ORIGIN_DAO_H_ +#define _SECURITY_ORIGIN_DAO_H_ + +#include +#include +#include +#include + +namespace SecurityOriginDB { +class SecurityOriginDAO +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + DECLARE_EXCEPTION_TYPE(Base, DataNotExist) + }; + + explicit SecurityOriginDAO(const WrtDB::TizenPkgId &pkgName); + virtual ~SecurityOriginDAO(); + SecurityOriginDataList getSecurityOriginDataList(); + Result getResult(const SecurityOriginData &data); + bool isReadOnly(const SecurityOriginData &data); + void setSecurityOriginData(const SecurityOriginData &data, + const Result result, + const bool readOnly = false); + void setPrivilegeSecurityOriginData(const WrtDB::Feature feature, + bool isOnlyAllowedLocalOrigin = true); + void removeSecurityOriginData(const SecurityOriginData &data); + void removeSecurityOriginData(const Result result); + + private: + std::string m_dbPath; + DPL::DB::ThreadDatabaseSupport m_dbInterface; + + bool hasResult(const SecurityOriginData &data); + void insertData(const SecurityOriginData &data, + const Result result, + const bool readOnly); + void updateData(const SecurityOriginData &data, + const Result result, + const bool readOnly); +}; + +typedef std::shared_ptr SecurityOriginDAOPtr; +} // namespace SecurityOriginDB + +#endif // _SECURITY_ORIGIN_DAO_H_ diff --git a/modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao_types.h b/modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao_types.h new file mode 100755 index 0000000..4753925 --- /dev/null +++ b/modules/security_origin_dao/include/wrt-commons/security-origin-dao/security_origin_dao_types.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file security_origin_dao_types.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of + * common data types for security origin database. + */ +#ifndef _SECURITY_ORIGIN_DAO_TYPES_H_ +#define _SECURITY_ORIGIN_DAO_TYPES_H_ + +#include +#include +#include +#include +#include + +namespace SecurityOriginDB { +enum Result +{ + RESULT_UNKNOWN = 0, + RESULT_ALLOW_ONCE, + RESULT_DENY_ONCE, + RESULT_ALLOW_ALWAYS, + RESULT_DENY_ALWAYS +}; + +struct Origin +{ + DPL::String scheme; + DPL::String host; + unsigned int port; + + Origin(const DPL::String& Scheme, + const DPL::String& Host, + const unsigned int Port) : + scheme(Scheme), + host(Host), + port(Port) + {} + + bool operator== (const Origin& other) const + { + return (!DPL::StringCompare(scheme, other.scheme) && + !DPL::StringCompare(host, other.host) && + port == other.port); + } + + bool operator!= (const Origin& other) const + { + return !(*this == other); + } +}; + +struct SecurityOriginData +{ + WrtDB::Feature feature; + Origin origin; + + SecurityOriginData(const WrtDB::Feature features, const Origin& ori) : + feature(features), + origin(ori) + {} + + bool operator== (const SecurityOriginData& other) const + { + return (origin == other.origin) && + (feature == other.feature); + } + + bool operator!= (const SecurityOriginData& other) const + { + return !(*this == other); + } +}; + +typedef std::shared_ptr SecurityOriginDataPtr; +typedef std::list SecurityOriginDataList; +} // namespace SecurityOriginDB + +#endif // _SECURITY_ORIGIN_DAO_TYPES_H_ diff --git a/modules/security_origin_dao/orm/orm_generator_security_origin.h b/modules/security_origin_dao/orm/orm_generator_security_origin.h new file mode 100644 index 0000000..84888de --- /dev/null +++ b/modules/security_origin_dao/orm/orm_generator_security_origin.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ORM_GENERATOR_SECURITY_ORIGIN_H_ +#define _ORM_GENERATOR_SECURITY_ORIGIN_H_ + +#define ORM_GENERATOR_DATABASE_NAME security_origin_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif // _ORM_GENERATOR_SECURITY_ORIGIN_H_ diff --git a/modules/security_origin_dao/orm/security_origin_db b/modules/security_origin_dao/orm/security_origin_db new file mode 100644 index 0000000..2d9c4f9 --- /dev/null +++ b/modules/security_origin_dao/orm/security_origin_db @@ -0,0 +1,13 @@ +SQL(BEGIN TRANSACTION;) + +CREATE_TABLE(SecurityOriginInfo) + COLUMN_NOT_NULL(feature, INT, ) + COLUMN_NOT_NULL(scheme, TEXT,DEFAULT '') + COLUMN_NOT_NULL(host, TEXT,DEFAULT '') + COLUMN_NOT_NULL(port, INT, DEFAULT 0) + COLUMN_NOT_NULL(result, INT, DEFAULT 0) + COLUMN_NOT_NULL(readonly, INT, DEFAULT 0) + TABLE_CONSTRAINTS(PRIMARY KEY(feature,scheme,host,port)) +CREATE_TABLE_END() + +SQL(COMMIT;) diff --git a/modules/security_origin_dao/orm/security_origin_db_definitions b/modules/security_origin_dao/orm/security_origin_db_definitions new file mode 100644 index 0000000..dc74f98 --- /dev/null +++ b/modules/security_origin_dao/orm/security_origin_db_definitions @@ -0,0 +1,5 @@ +DATABASE_START(security_origin) + +#include "security_origin_db" + +DATABASE_END() diff --git a/modules/security_origin_dao/orm/security_origin_db_sql_generator.h b/modules/security_origin_dao/orm/security_origin_db_sql_generator.h new file mode 100644 index 0000000..3bdbe6d --- /dev/null +++ b/modules/security_origin_dao/orm/security_origin_db_sql_generator.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file security_origin_db_sql_generator.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL + * input file from database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. +#include + +#include "security_origin_db_definitions" diff --git a/modules/socket/config.cmake b/modules/socket/config.cmake new file mode 100644 index 0000000..6e097a4 --- /dev/null +++ b/modules/socket/config.cmake @@ -0,0 +1,40 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_SOCKET_SOURCES + ${PROJECT_SOURCE_DIR}/modules/socket/src/generic_socket.cpp + ${PROJECT_SOURCE_DIR}/modules/socket/src/unix_socket.cpp + ${PROJECT_SOURCE_DIR}/modules/socket/src/waitable_input_output_execution_context_support.cpp + PARENT_SCOPE +) + +SET(DPL_SOCKET_HEADERS + ${PROJECT_SOURCE_DIR}/modules/socket/include/dpl/socket/abstract_socket.h + ${PROJECT_SOURCE_DIR}/modules/socket/include/dpl/socket/generic_socket.h + ${PROJECT_SOURCE_DIR}/modules/socket/include/dpl/socket/unix_socket.h + ${PROJECT_SOURCE_DIR}/modules/socket/include/dpl/socket/waitable_input_output_execution_context_support.h + PARENT_SCOPE +) + +SET(DPL_SOCKET_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/socket/include/ + PARENT_SCOPE +) diff --git a/modules/socket/include/dpl/socket/abstract_socket.h b/modules/socket/include/dpl/socket/abstract_socket.h new file mode 100644 index 0000000..0c06f99 --- /dev/null +++ b/modules/socket/include/dpl/socket/abstract_socket.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_socket.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract socket + */ +#ifndef DPL_ABSTRACT_SOCKET_H +#define DPL_ABSTRACT_SOCKET_H + +#include +#include +#include +#include +#include + +namespace DPL { +namespace Socket { +namespace AbstractSocketEvents { +// Successfuly connected to server socket +DECLARE_GENERIC_EVENT_0(ConnectedEvent) + +// New connection occurred and need to be accepted +DECLARE_GENERIC_EVENT_0(AcceptEvent) + +// Connection has read data waiting +DECLARE_GENERIC_EVENT_0(ReadEvent) + +// Connection write buffer is now empty again and ready to write more +DECLARE_GENERIC_EVENT_0(WriteEvent) +} // namespace AbstractSocketEvents + +class AbstractSocket : + public AbstractWaitableInputOutput, + public DPL::Event::EventSupport, + public DPL::Event::EventSupport, + public DPL::Event::EventSupport, + public DPL::Event::EventSupport +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) ///< Base abstract + // socket exception + + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) ///< Fatal error + // occurred during + // open socket + // descriptor. Socket + // state is + // inconsistent and + // it should be not + // used anymore. + + DECLARE_EXCEPTION_TYPE(Base, ConnectFailed) ///< Fatal error + // occurred during + // connect. Socket + // state is + // inconsistent and + // it should be not + // used anymore. + ///< Warning: This + // exception does not + // mean that socket + // did not succeed to + // connect, see + // CannotConnect + ///< for this + // specific scenario + + DECLARE_EXCEPTION_TYPE(Base, SetNonBlockingFailed) ///< Fatal error + // occurred during + // setting socket to + // non-blocking mode. + // Socket state is + // inconsistent and + // it should be not + // used anymore. + + DECLARE_EXCEPTION_TYPE(Base, BindFailed) ///< Fatal error + // occurred during + // bind. Socket state + // is inconsistent + // and it should be + // not used anymore. + + DECLARE_EXCEPTION_TYPE(Base, AcceptFailed) ///< Fatal error + // occurred during + // accept. Socket + // state is + // inconsistent and + // it should be not + // used anymore. + + DECLARE_EXCEPTION_TYPE(Base, ListenFailed) ///< Fatal error + // occurred during + // listen. Socket + // state is + // inconsistent and + // it should be not + // used anymore. + + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) ///< Fatal error + // occurred during + // close. Socket + // state is + // inconsistent and + // it should be not + // used anymore. + + DECLARE_EXCEPTION_TYPE(Base, ReadFailed) ///< Fatal error + // occurred during + // read. Socket state + // is inconsistent + // and it should be + // not used anymore. + ///< Warning: This + // exception does not + // mean that + // connection was + // broken, see + // ConnectionBroken + ///< for this + // specific scenario + + DECLARE_EXCEPTION_TYPE(Base, WriteFailed) ///< Fatal error + // occurred during + // write. Socket + // state is + // inconsistent and + // it should be not + // used anymore. + ///< Warning: This + // exception does not + // mean that + // connection was + // broken, see + // ConnectionBroken + ///< for this + // specific scenario + + DECLARE_EXCEPTION_TYPE(Base, GetPeerNameFailed) ///< Fatal error + // occurred during + // getpeername or + // getsockname. + // Socket state is + // inconsistent and + // it should be not + // used anymore. + + DECLARE_EXCEPTION_TYPE(Base, CannotConnect) ///< Cannot connect + // to remote socket. + // This is not fatal + // error, socket + // state is still + // consistent and it + // can be + // reconnected. + + DECLARE_EXCEPTION_TYPE(Base, ConnectionBroken) ///< Connection was + // broken. This is + // not fatal error, + // socket state is + // still consistent + // and it can be + // reconnected. + }; + + public: + virtual ~AbstractSocket() {} + + // Connect to remote host + virtual void Connect(const Address &address) = 0; + + // Open empty, unconnected socket + virtual void Open() = 0; + + // Close connection + virtual void Close() = 0; + + // Bind server socket address + virtual void Bind(const Address &address) = 0; + + // Begin listening for incoming connections + virtual void Listen(int backlog) = 0; + + // Accept waiting connection and create derived class connection + // One should cast resulting pointer to derived class + virtual AbstractSocket *Accept() = 0; + + // Local socket address + virtual Address GetLocalAddress() const = 0; + + // Remote socket address + virtual Address GetRemoteAddress() const = 0; +}; +} +} // namespace DPL + +#endif // DPL_ABSTRACT_SOCKET_H diff --git a/modules/socket/include/dpl/socket/generic_socket.h b/modules/socket/include/dpl/socket/generic_socket.h new file mode 100644 index 0000000..3ed9b86 --- /dev/null +++ b/modules/socket/include/dpl/socket/generic_socket.h @@ -0,0 +1,934 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of generic socket + */ +#ifndef DPL_GENERIC_SOCKET_H +#define DPL_GENERIC_SOCKET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Socket { +// +// Generic abstract socket implementation +// Execution context is inherited +// +template +class GenericSocket : + public AbstractSocket, + private WaitableHandleWatchSupport::WaitableHandleListener +{ + protected: + /** + * Translate generic Address to specific socket kernel structure + * + * @warning Must be implemented in derived class + */ + virtual std::pair TranslateAddressGenericToSpecific( + const Address &address) const = 0; + + /** + * Translate specific socket kernel structure to generic Address + * + * @warning Must be implemented in derived class + */ + virtual Address TranslateAddressSpecificToGeneric(sockaddr *, + socklen_t) const = 0; + + /** + * Get specific socket kernel structure size + * + * @warning Must be implemented in derived class + */ + virtual socklen_t GetSpecificAddressSize() const = 0; + + /** + * Alloc specific implementation of socket from descriptor + * + * @warning Must be implemented in derived class + */ + virtual SocketType *AllocAcceptedSpecificSocket() const = 0; + + /** + * Alloc specific implementation of socket descriptor + * + * @warning Must be implemented in derived class + */ + virtual int AllocSpecificDescriptor() const = 0; + + private: + // Constants + static const size_t DEFAULT_READ_BUFFER_SIZE = 4096; + + // Socket handle + int m_socket; // FIXME: Consider generalization to WaitableHandle upon + // leaving nix platform + + // Internal state + enum InternalState + { + InternalState_None, ///< Not connected and not listening state + InternalState_Prepare, ///< Descriptor allocated, but not connected + InternalState_Listening, ///< Listening state + InternalState_Connecting, ///< Connecting state + InternalState_Connected ///< Connected state + }; + + InternalState m_internalState; + + void SetNonBlocking() + { + // Set non-blocking mode + if (fcntl(m_socket, F_SETFL, O_NONBLOCK | + fcntl(m_socket, F_GETFL)) == -1) + { + Throw(AbstractSocket::Exception::SetNonBlockingFailed); + } + } + + // WaitableHandleWatchSupport::WaitableHandleListener + virtual void OnWaitableHandleEvent(WaitableHandle waitableHandle, + WaitMode::Type mode) + { + (void)waitableHandle; + Assert(waitableHandle == m_socket); + + switch (m_internalState) { + case InternalState_None: + break; + + case InternalState_Prepare: + Assert(0 && "Invalid internal generic socket state!"); + break; + + case InternalState_Listening: + Assert(mode == WaitMode::Read); + + // New client waiting for accept + DPL::Event::EventSupport:: + EmitEvent(AbstractSocketEvents::AcceptEvent( + EventSender(this)), DPL::Event::EmitMode::Queued); + + // Done + break; + + case InternalState_Connecting: + Assert(mode == WaitMode::Write); + + // Connected to server + RemoveConnectWatch(); + m_internalState = InternalState_Connected; + + // Add read watch + AddReadWatch(); + + // Emit event + DPL::Event::EventSupport:: + EmitEvent(AbstractSocketEvents::ConnectedEvent( + EventSender(this)), DPL::Event::EmitMode::Queued); + + // Done + break; + + case InternalState_Connected: + if (mode == WaitMode::Read) { + // Emit ReadEvent + DPL::Event::EventSupport:: + EmitEvent(AbstractSocketEvents::ReadEvent( + EventSender( + this)), DPL::Event::EmitMode::Queued); + } else if (mode == WaitMode::Write) { + // Emit WriteEvent + DPL::Event::EventSupport:: + EmitEvent(AbstractSocketEvents::WriteEvent( + EventSender( + this)), DPL::Event::EmitMode::Queued); + } else { + Assert(0); + } + + break; + + default: + Assert(0); + break; + } + } + + void AddAcceptWatch() + { + WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch( + this, + m_socket, + WaitMode::Read); + } + + void RemoveAcceptWatch() + { + WaitableHandleWatchSupport::InheritedContext()-> + RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read); + } + + void AddConnectWatch() + { + WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch( + this, + m_socket, + WaitMode::Write); + } + + void RemoveConnectWatch() + { + WaitableHandleWatchSupport::InheritedContext()-> + RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write); + } + + void AddReadWatch() + { + WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch( + this, + m_socket, + WaitMode::Read); + } + + void RemoveReadWatch() + { + WaitableHandleWatchSupport::InheritedContext()-> + RemoveWaitableHandleWatch(this, m_socket, WaitMode::Read); + } + + void AddWriteWatch() + { + WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch( + this, + m_socket, + WaitMode::Write); + } + + void RemoveWriteWatch() + { + WaitableHandleWatchSupport::InheritedContext()-> + RemoveWaitableHandleWatch(this, m_socket, WaitMode::Write); + } + + public: + GenericSocket() : + m_socket(-1), + m_internalState(InternalState_None) + {} + + virtual ~GenericSocket() + { + // Always ensure to close socket + Try + { + Close(); + } + Catch(Exception::CloseFailed) + { + LogPedantic("Close failed and ignored"); + } + + // Check consistency + Assert(m_socket == -1); + } + + virtual void Open() + { + if (m_internalState != InternalState_None) { + ThrowMsg(AbstractSocket::Exception::OpenFailed, + "Invalid socket state, should be 'None'"); + } + + LogPedantic("Opening socket..."); + + // Check consistency + Assert(m_socket == -1); + + // Allocate specific socket descriptor + m_socket = AllocSpecificDescriptor(); + + // Set socket non-blocking + SetNonBlocking(); + + // State is prepared + m_internalState = InternalState_Prepare; + + LogPedantic("Socket opened"); + } + + virtual void Connect(const Address &address) + { + if (m_internalState != InternalState_Prepare) { + ThrowMsg(AbstractSocket::Exception::ConnectFailed, + "Invalid socket state, should be 'Prepare'"); + } + + LogPedantic("Connecting to: " << address.ToString()); + + // Try to convert address + std::pair socketAddress; + + Try + { + // Translate address to specific socket address struct + socketAddress = TranslateAddressGenericToSpecific(address); + } + Catch(Address::Exception::InvalidAddress) + { + // This address is invalid. Cannot connect. + ReThrowMsg(AbstractSocket::Exception::ConnectFailed, + address.ToString()); + } + + // Do connect + int result = + TEMP_FAILURE_RETRY(connect(m_socket, socketAddress.first, + socketAddress.second)); + + if (result == 0) { + // Immediate connect + LogPedantic("Immediate connected to: " << address.ToString()); + + // Add read watch + AddReadWatch(); + m_internalState = InternalState_Connected; + + // Emit connected event + DPL::Event::EventSupport:: + EmitEvent(AbstractSocketEvents::ConnectedEvent( + EventSender(this)), DPL::Event::EmitMode::Queued); + } else { + if (errno == EINTR || errno == EINPROGRESS) { + LogPedantic( + "Asynchronous connect in progress: " << address.ToString()); + + // Connecting in progress + AddConnectWatch(); + m_internalState = InternalState_Connecting; + } else { + // Free translation structure + free(socketAddress.first); + + // Error occurred + ThrowMsg(AbstractSocket::Exception::ConnectFailed, + address.ToString()); + } + } + + // Free translation structure + free(socketAddress.first); + } + + virtual void Close() + { + if (m_internalState == InternalState_None) { + return; + } + + Assert(m_socket != -1); + + if (m_internalState == InternalState_Listening) { + // Remove watch in listening state + LogPedantic("Removing accept watch"); + RemoveAcceptWatch(); + m_internalState = InternalState_None; + } else if (m_internalState == InternalState_Connecting) { + // Remove watch in connecting state + LogPedantic("Removing connect watch"); + RemoveConnectWatch(); + m_internalState = InternalState_None; + } else if (m_internalState == InternalState_Connected) { + // Remove watch in connected state + LogPedantic("Removing read watch"); + RemoveReadWatch(); + m_internalState = InternalState_None; + } else { + // State must be just prepared only + Assert(m_internalState == InternalState_Prepare); + } + + if (TEMP_FAILURE_RETRY(close(m_socket)) == -1) { + Throw(Exception::CloseFailed); + } + + // Reset socket + m_socket = -1; + + // Reset socket state + m_internalState = InternalState_None; + + LogPedantic("Socket closed"); + } + + virtual void Bind(const Address &address) + { + if (m_internalState != InternalState_Prepare) { + ThrowMsg(AbstractSocket::Exception::BindFailed, + "Invalid socket state, should be 'Prepare'"); + } + + LogPedantic( + "Binding to: " << address.GetAddress() << ":" << address.GetPort()); + + // Translate address to specific socket address struct + std::pair socketAddress = TranslateAddressGenericToSpecific( + address); + + // Do bind + if (::bind(m_socket, socketAddress.first, + socketAddress.second) == -1) + { + ThrowMsg(AbstractSocket::Exception::BindFailed, address.ToString()); + } + + // Free translation structure + free(socketAddress.first); + + // Show info + LogPedantic( + "Bound to address: " << address.GetAddress() << ":" << + address.GetPort()); + } + + virtual void Listen(int backlog) + { + if (m_internalState != InternalState_Prepare) { + ThrowMsg(AbstractSocket::Exception::ListenFailed, + "Invalid socket state, should be 'None'"); + } + + LogPedantic("Starting to listen..."); + + // Do listen + if (listen(m_socket, backlog) != 0) { + Throw(AbstractSocket::Exception::ListenFailed); + } + + // Begin read watch + AddAcceptWatch(); + m_internalState = InternalState_Listening; + + LogPedantic("Listen started"); + } + + virtual AbstractSocket *Accept() + { + if (m_internalState != InternalState_Listening) { + ThrowMsg(AbstractSocket::Exception::AcceptFailed, + "Invalid socket state, should be 'Listening'"); + } + + LogPedantic("Accepting..."); + + // Do listen + socklen_t length = 0; + int client = TEMP_FAILURE_RETRY(accept(m_socket, NULL, &length)); + + LogPedantic("Socket accept returned " << client); + if (client == -1) { + // Check if there is any client waiting + if (errno == EWOULDBLOCK || errno == EAGAIN) { + return NULL; + } + int err = errno; + if (errno == ENOENT) { + return NULL; + } + LogPedantic("throwing error. errrno " << err); + // Error occurred + Throw(AbstractSocket::Exception::AcceptFailed); + } + + LogPedantic("Accepted client. Seting up..."); + + // Create derived class type + GenericSocket *acceptedSocket = AllocAcceptedSpecificSocket(); + + // Save client socket specific descriptor + acceptedSocket->m_socket = client; + + // Enter proper states and add read watch + acceptedSocket->AddReadWatch(); + acceptedSocket->m_internalState = InternalState_Connected; + + // Set non-blocking mode for new socket + acceptedSocket->SetNonBlocking(); + + // Show info + LogPedantic("Accepted client set up"); + + // return new conneced client socket + return acceptedSocket; + } + + virtual Address GetLocalAddress() const + { + // FIXME: Additional internal state check + + socklen_t length = GetSpecificAddressSize(); + ScopedFree address(static_cast(calloc( + static_cast< + size_t>( + length), + 1))); + + if (getsockname(m_socket, address.Get(), &length) == -1) { + ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed, + "Failed to get local address"); + } + + return TranslateAddressSpecificToGeneric(address.Get(), length); + } + + virtual Address GetRemoteAddress() const + { + // FIXME: Additional internal state check + + socklen_t length = GetSpecificAddressSize(); + ScopedFree address(static_cast(calloc( + static_cast< + size_t>( + length), + 1))); + + if (getpeername(m_socket, address.Get(), &length) == -1) { + ThrowMsg(AbstractSocket::Exception::GetPeerNameFailed, + "Failed to get remote address"); + } + + return TranslateAddressSpecificToGeneric(address.Get(), length); + } + + virtual BinaryQueueAutoPtr Read(size_t size) + { + if (m_internalState != InternalState_Connected) { + ThrowMsg(AbstractSocket::Exception::AcceptFailed, + "Invalid socket state, should be 'Connected'"); + } + + Try + { + // Adjust bytes to be read + size_t bytesToRead = size > + DEFAULT_READ_BUFFER_SIZE ? DEFAULT_READ_BUFFER_SIZE : size; + + // Malloc default read buffer size + // It is unmanaged, so it can be then attached directly to binary + // queue + void *buffer = malloc(bytesToRead); + + if (buffer == NULL) { + throw std::bad_alloc(); + } + + // Receive bytes from socket + ssize_t result = + TEMP_FAILURE_RETRY(recv(m_socket, buffer, bytesToRead, 0)); + + if (result > 0) { + // Succedded to read socket data + BinaryQueueAutoPtr binaryQueue(new BinaryQueue()); + + // Append unmanaged memory + binaryQueue->AppendUnmanaged(buffer, + result, + &BinaryQueue::BufferDeleterFree, + NULL); + + // Return buffer + return binaryQueue; + } else if (result == 0) { + // Socket was gracefuly closed + free(buffer); + + // Return empty buffer + return BinaryQueueAutoPtr(new BinaryQueue()); + } else { + // Must first save errno value, because it may be altered + int lastErrno = errno; + + // Free buffer + free(buffer); + + // Interpret error result + switch (lastErrno) { + case EAGAIN: // = EWOULDBLOCK + // + // * The socket's file descriptor is marked O_NONBLOCK and + // no data is waiting + // to be received; or MSG_OOB is set and no out-of-band + // data is available + // and either the socket's file descriptor is marked + // O_NONBLOCK or the socket + // does not support blocking to await out-of-band data. + // + // return null data buffer to indicate no data waiting + // + return BinaryQueueAutoPtr(); + + case EBADF: + // + // * The socket argument is not a valid file descriptor. + // + // This is internal error + // + ThrowMsg(CommonException::InternalError, + "Invalid socket descriptor"); + + case ECONNRESET: + // + // * A connection was forcibly closed by a peer. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case EINTR: + // + // * The recv() function was interrupted by a signal that + // was caught, before any + // data was available. + // + // No interrupt here is expected, due to fact that we used + // TEMP_FAILURE_RETRY + // + ThrowMsg(CommonException::InternalError, + "Unexpected interrupt occurred"); + + case EINVAL: + // + // * The MSG_OOB flag is set and no out-of-band data is + // available. + // + // We did not specified OOB data. This is an error. + // + ThrowMsg(CommonException::InternalError, + "Unexpected OOB error occurred"); + + case ENOTCONN: + // + // * A receive is attempted on a connection-mode socket that + // is not connected. + // + // FIXME: Is this proper exception here ? + // + ThrowMsg(CommonException::InternalError, + "Socket is not connected"); + + case ENOTSOCK: + // + // * The socket argument does not refer to a socket. + // + ThrowMsg(CommonException::InternalError, + "Handle is not a socket"); + + case EOPNOTSUPP: + // + // * The specified flags are not supported for this socket + // type or protocol. + // + ThrowMsg(CommonException::InternalError, + "Socket flags not supported"); + + case ETIMEDOUT: + // + // * The connection timed out during connection + // establishment, or due to a transmission timeout on active + // connection. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case EIO: + // + // * An I/O error occurred while reading from or writing to + // the file system. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case ENOBUFS: + // + // * Insufficient resources were available in the system to + // perform the operation. + // + ThrowMsg(CommonException::InternalError, + "Insufficient system resources"); + + case ENOMEM: + // + // * Insufficient memory was available to fulfill the + // request. + // + ThrowMsg(CommonException::InternalError, + "Insufficient system memory"); + + default: + // Some kernel error occurred, should never happen + ThrowMsg(CommonException::InternalError, + "Unknown kernel read error returned"); + break; + } + } + } + Catch(CommonException::InternalError) + { + // If any internal error occurred, this is fatal for Write method + // interpret this as WriteError exception and rethrow + ReThrow(AbstractSocket::Exception::ReadFailed); + } + } + + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize) + { + if (m_internalState != InternalState_Connected) { + ThrowMsg(AbstractSocket::Exception::AcceptFailed, + "Invalid socket state, should be 'Connected'"); + } + + Try + { + // Adjust write size + if (bufferSize > buffer.Size()) { + bufferSize = buffer.Size(); + } + + // FIXME: User write visitor to write ! + // WriteVisitor visitor + + ScopedFree flattened(malloc(bufferSize)); + buffer.Flatten(flattened.Get(), bufferSize); + + // Linux: MSG_NOSIGNAL is supported, but it is not an ideal solution + // FIXME: Should we setup signal PIPE ignoring for whole process ? + // In BSD, there is: setsockopt(c, SOL_SOCKET, SO_NOSIGPIPE, (void + // *)&on, sizeof(on)) + ssize_t result = + TEMP_FAILURE_RETRY(send(m_socket, flattened.Get(), bufferSize, + MSG_NOSIGNAL)); + + if (result > 0) { + // Successfuly written some bytes + return static_cast(result); + } else if (result == 0) { + // This is abnormal result + ThrowMsg(CommonException::InternalError, + "Invalid socket write result, 0 bytes written"); + } else if (result == -1) { + // Interpret error result + switch (errno) { + case EAGAIN: // = EWOULDBLOCK + // + // * The socket's file descriptor is marked O_NONBLOCK and + // the requested operation would block. + // + // We should wait for writability + // + return 0; + + case EBADF: + // + // * The socket argument is not a valid file descriptor. + // + // This is internal error + // + ThrowMsg(CommonException::InternalError, + "Invalid socket descriptor"); + + case ECONNRESET: + // + // * A connection was forcibly closed by a peer. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case EDESTADDRREQ: + // + // * The socket is not connection-mode and no peer address + // is set. + // + // FIXME: Is this proper exception here ? + // + ThrowMsg(CommonException::InternalError, + "Socket is not connected"); + + case EINTR: + // + // * A signal interrupted send() before any data was + // transmitted. + // + // No interrupt here is expected, due to fact that we used + // TEMP_FAILURE_RETRY + // + ThrowMsg(CommonException::InternalError, + "Unexpected interrupt occurred"); + + case EMSGSIZE: + // + // * The message is too large to be sent all at once, as the + // socket requires. + // + // FIXME: Is this proper exception here ? + // + ThrowMsg(CommonException::InternalError, + "Socket message is too big"); + + case ENOTCONN: + // + // * The socket is not connected or otherwise has not had + // the peer pre-specified. + // + // FIXME: Is this proper exception here ? + // + ThrowMsg(CommonException::InternalError, + "Socket is not connected"); + + case ENOTSOCK: + // + // * The socket argument does not refer to a socket. + // + ThrowMsg(CommonException::InternalError, + "Handle is not a socket"); + + case EOPNOTSUPP: + // + // * The socket argument is associated with a socket that + // does not support one or more of the values set in flags. + // + ThrowMsg(CommonException::InternalError, + "Socket flags not supported"); + + case EPIPE: + // + // * The socket is shut down for writing, or the socket is + // connection-mode and + // is no longer connected. In the latter case, and if the + // socket is of type + // SOCK_STREAM, the SIGPIPE signal is generated to the + // calling thread. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case EACCES: + // + // * The calling process does not have the appropriate + // privileges. + // + // Priviledges might have changed. + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case EIO: + // + // * An I/O error occurred while reading from or writing to + // the file system. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case ENETDOWN: + // + // * The local network interface used to reach the + // destination is down. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case ENETUNREACH: + // + // * No route to the network is present. + // + // In result, we can interpret this error as a broken + // connection + // + Throw(AbstractSocket::Exception::ConnectionBroken); + + case ENOBUFS: + // + // * Insufficient resources were available in the system to + // perform the operation. + // + ThrowMsg(CommonException::InternalError, + "Insufficient system resources"); + + default: + // Some kernel error occurred, should never happen + ThrowMsg(CommonException::InternalError, + "Unknown kernel write error returned"); + break; + } + } + } + Catch(CommonException::InternalError) + { + // If any internal error occurred, this is fatal for Write method + // interpret this as WriteError exception and rethrow + ReThrow(AbstractSocket::Exception::WriteFailed); + } + + // Does not apply + return 0; + } + + // AbstractWaitableInput + virtual WaitableHandle WaitableReadHandle() const + { + return m_socket; + } + + // AbstractWaitableOutput + virtual WaitableHandle WaitableWriteHandle() const + { + return m_socket; + } +}; +} +} // namespace DPL + +#endif // DPL_GENERIC_SOCKET_H diff --git a/modules/socket/include/dpl/socket/unix_socket.h b/modules/socket/include/dpl/socket/unix_socket.h new file mode 100644 index 0000000..37614ce --- /dev/null +++ b/modules/socket/include/dpl/socket/unix_socket.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of unix socket + */ +#ifndef DPL_UNIX_SOCKET_H +#define DPL_UNIX_SOCKET_H + +#include +#include + +namespace DPL { +namespace Socket { +class UnixSocket : + public GenericSocket +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, CreateFailed) + }; + + protected: + /** + * Translate generic Address to specific socket kernel structure + */ + virtual std::pair TranslateAddressGenericToSpecific( + const Address &address) const; + + /** + * Translate specific socket kernel structure to generic Address + */ + virtual Address TranslateAddressSpecificToGeneric(sockaddr *, + socklen_t) const; + + /** + * Get specific socket kernel structure size + */ + virtual socklen_t GetSpecificAddressSize() const; + + /** + * Alloc specific implementation of socket from descriptor + */ + virtual UnixSocket *AllocAcceptedSpecificSocket() const; + + /** + * Alloc specific implementation of socket descriptor + */ + virtual int AllocSpecificDescriptor() const; + + public: + UnixSocket(); + + virtual void Bind(const Address &address); +}; +} +} // namespace DPL + +#endif // DPL_GENERIC_SOCKET_H diff --git a/modules/socket/include/dpl/socket/waitable_input_output_execution_context_support.h b/modules/socket/include/dpl/socket/waitable_input_output_execution_context_support.h new file mode 100644 index 0000000..f02df51 --- /dev/null +++ b/modules/socket/include/dpl/socket/waitable_input_output_execution_context_support.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_input_output_execution_context_support.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file for waitable input-output execution + * context support + */ +#ifndef DPL_WAITABLE_INPUT_OUTPUT_EXECUTION_CONTEXT_SUPPORT_H +#define DPL_WAITABLE_INPUT_OUTPUT_EXECUTION_CONTEXT_SUPPORT_H + +#include +#include +#include + +namespace DPL { +namespace Socket { +class WaitableInputOutputExecutionContextSupport : + private WaitableHandleWatchSupport::WaitableHandleListener +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, AlreadyOpened) + DECLARE_EXCEPTION_TYPE(Base, NotOpened) + DECLARE_EXCEPTION_TYPE(Base, OpenFailed) + DECLARE_EXCEPTION_TYPE(Base, CloseFailed) + }; + + private: + bool m_opened; + AbstractWaitableInputOutput *m_waitableInputOutput; + + // Watch state + bool m_hasReadWatch; + bool m_hasWriteWatch; + + void AddReadWatch(); + void RemoveReadWatch(); + void AddWriteWatch(); + void RemoveWriteWatch(); + + void ReadInput(); + + void CheckedRemoveReadWatch(); + void CheckedRemoveWriteWatch(); + + void CheckedRemoveReadWriteWatch(); + + virtual void OnWaitableHandleEvent(WaitableHandle waitableHandle, + WaitMode::Type mode); + + protected: + // Incoming/Outgoing streams + BinaryQueue m_inputStream; + BinaryQueue m_outputStream; + + // Support calbback methods + virtual void OnInputStreamRead() = 0; + virtual void OnInputStreamClosed() = 0; + virtual void OnInputStreamBroken() = 0; + + // Trigger feeding output - after updating output stream + void FeedOutput(); + + // Open/Close destination waitable input-output + void Open(AbstractWaitableInputOutput *waitableInputOutput); + void Close(); + + public: + /** + * Constructor + */ + explicit WaitableInputOutputExecutionContextSupport(); + + /** + * Destructor + */ + virtual ~WaitableInputOutputExecutionContextSupport(); +}; +} +} // namespace DPL + +#endif // DPL_WAITABLE_INPUT_OUTPUT_EXECUTION_CONTEXT_SUPPORT_H diff --git a/modules/socket/src/generic_socket.cpp b/modules/socket/src/generic_socket.cpp new file mode 100644 index 0000000..aff2d74 --- /dev/null +++ b/modules/socket/src/generic_socket.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file generic_socket.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of generic socket + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/modules/socket/src/unix_socket.cpp b/modules/socket/src/unix_socket.cpp new file mode 100644 index 0000000..36bff51 --- /dev/null +++ b/modules/socket/src/unix_socket.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file unix_socket.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of unix socket + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Socket { +UnixSocket::UnixSocket() +{} + +int UnixSocket::AllocSpecificDescriptor() const +{ + LogPedantic("Creating UNIX socket..."); + + // Create new descriptor + int newSocket = socket(AF_UNIX, SOCK_STREAM, 0); + + if (newSocket == -1) { + Throw(Exception::CreateFailed); + } + + LogPedantic("UNIX socket created"); + + // Return new descriptor + return newSocket; +} + +std::pair UnixSocket::TranslateAddressGenericToSpecific( + const Address &address) const +{ + // Allocate new socket address structure + sockaddr_un *sockAddress = + static_cast(malloc(sizeof(sockaddr_un))); + if (!sockAddress) { + throw std::bad_alloc(); + } + + memset(sockAddress, 0, sizeof(sockaddr_un)); + + // Copy address properties + sockAddress->sun_family = AF_UNIX; + strncpy(sockAddress->sun_path, address.GetAddress().c_str(), + sizeof(sockAddress->sun_path) - 1); + + //Prevent buffer overflows + sockAddress->sun_path[sizeof(sockAddress->sun_path) - 1] = '\0'; + + // Set proper address length + socklen_t sockAddressLength = SUN_LEN(sockAddress); + + // Return new translated address + return std::make_pair(reinterpret_cast(sockAddress), + sockAddressLength); +} + +Address UnixSocket::TranslateAddressSpecificToGeneric(sockaddr *address, + socklen_t) const +{ + // FIXME: Constrain check ? + sockaddr_un *unixAddress = reinterpret_cast(address); + return Address(unixAddress->sun_path); +} + +socklen_t UnixSocket::GetSpecificAddressSize() const +{ + return static_cast(sizeof(sockaddr_un)); +} + +UnixSocket *UnixSocket::AllocAcceptedSpecificSocket() const +{ + return new UnixSocket(); +} + +void UnixSocket::Bind(const Address &address) +{ + // Always remove socket file if any + unlink(address.GetAddress().c_str()); + + // Call base implementation + GenericSocket::Bind(address); + + // Always set proper permissions to the socket file + if (chmod(address.GetAddress().c_str(), 0777) < 0) { + LogError( + "Error setting permissions to the socket file. Errno " << + strerror(errno)); + } +} +} +} // namespace DPL diff --git a/modules/socket/src/waitable_input_output_execution_context_support.cpp b/modules/socket/src/waitable_input_output_execution_context_support.cpp new file mode 100644 index 0000000..35635b5 --- /dev/null +++ b/modules/socket/src/waitable_input_output_execution_context_support.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file waitable_input_output_execution_context_support.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of waitable input-output + * execution context support + */ +#include +#include +#include +#include // FIXME: Remove !!! +#include +#include + +namespace DPL { +namespace Socket { +namespace // anonymous +{ +const size_t DEFAULT_READ_SIZE = 2048; +} // namespace anonymous + +WaitableInputOutputExecutionContextSupport:: + WaitableInputOutputExecutionContextSupport() : + m_opened(false), + m_waitableInputOutput(NULL), + m_hasReadWatch(false), + m_hasWriteWatch(false) +{} + +WaitableInputOutputExecutionContextSupport::~ +WaitableInputOutputExecutionContextSupport() +{ + // Ensure support is closed + Close(); +} + +void WaitableInputOutputExecutionContextSupport::Open( + AbstractWaitableInputOutput *inputOutput) +{ + if (m_opened) { + Throw(Exception::AlreadyOpened); + } + + LogPedantic("Opening waitable input-output execution context support..."); + + // Save IO handle + m_waitableInputOutput = inputOutput; + + // Register read watch + Assert(m_hasReadWatch == false); + + AddReadWatch(); + m_hasReadWatch = true; + + // Done + m_opened = true; + + LogPedantic("Waitable input-output execution context support opened"); +} + +void WaitableInputOutputExecutionContextSupport::Close() +{ + if (!m_opened) { + return; + } + + LogPedantic("Closing waitable input-output execution context support..."); + + // Remove read and write watches + CheckedRemoveReadWriteWatch(); + + // Set proper state + m_opened = false; + + LogPedantic("Waitable input-output execution context support closed"); +} + +void WaitableInputOutputExecutionContextSupport::AddReadWatch() +{ + WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch( + this, + m_waitableInputOutput + ->WaitableReadHandle(), + WaitMode + ::Read); +} + +void WaitableInputOutputExecutionContextSupport::RemoveReadWatch() +{ + WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch( + this, + m_waitableInputOutput->WaitableReadHandle(), + WaitMode::Read); +} + +void WaitableInputOutputExecutionContextSupport::AddWriteWatch() +{ + WaitableHandleWatchSupport::InheritedContext()->AddWaitableHandleWatch( + this, + m_waitableInputOutput + ->WaitableWriteHandle(), + WaitMode + ::Write); +} + +void WaitableInputOutputExecutionContextSupport::RemoveWriteWatch() +{ + WaitableHandleWatchSupport::InheritedContext()->RemoveWaitableHandleWatch( + this, + m_waitableInputOutput->WaitableWriteHandle(), + WaitMode::Write); +} + +void WaitableInputOutputExecutionContextSupport::CheckedRemoveReadWatch() +{ + if (!m_hasReadWatch) { + return; + } + + RemoveReadWatch(); + m_hasReadWatch = false; +} + +void WaitableInputOutputExecutionContextSupport::CheckedRemoveWriteWatch() +{ + if (!m_hasWriteWatch) { + return; + } + + RemoveWriteWatch(); + m_hasWriteWatch = false; +} + +void WaitableInputOutputExecutionContextSupport::CheckedRemoveReadWriteWatch() +{ + // Remove read watch if any + CheckedRemoveReadWatch(); + + // Remove write watch if any + CheckedRemoveWriteWatch(); +} + +void WaitableInputOutputExecutionContextSupport::OnWaitableHandleEvent( + WaitableHandle waitableHandle, + WaitMode::Type mode) +{ + (void)waitableHandle; + + switch (mode) { + case WaitMode::Read: + LogPedantic("Read event occurred"); + + // Read and parse bytes + ReadInput(); + + // Done + break; + + case WaitMode::Write: + LogPedantic("Write event occurred"); + + // Push bytes and unregister from write event + FeedOutput(); + + // Unregister write watch only if no more data is available + if (m_outputStream.Empty()) { + Assert(m_hasWriteWatch == true); + CheckedRemoveWriteWatch(); + } + + // Done + break; + + default: + Assert(0); + break; + } +} + +void WaitableInputOutputExecutionContextSupport::ReadInput() +{ + LogPedantic("Reading input bytes"); + + Try + { + BinaryQueueAutoPtr inputBuffer = m_waitableInputOutput->Read( + DEFAULT_READ_SIZE); + + if (inputBuffer.get() == NULL) { + // No data, should not occur + LogPedantic("WARNING: Spontaneous ReadSocket occurred"); + return; + } + + if (inputBuffer->Empty()) { + // Connection was closed + OnInputStreamClosed(); + + // Unregister from further event insisting + Assert(m_hasReadWatch == true); + CheckedRemoveReadWriteWatch(); + + // Set proper state + m_opened = false; + + // Done + return; + } + + LogPedantic("Read " << inputBuffer->Size() << " input bytes"); + + // Append all read data + m_inputStream.AppendMoveFrom(*inputBuffer); + } + Catch(AbstractSocket::Exception::ConnectionBroken) + { + //FIXME: Inproper exception abstraction!!! + // Some errors occurred while feeding abstract IO + // Interpret connection broken errors, and pass futher other ones + LogPedantic("Abstract IO connection was broken during read"); + + // Signal broken connection + OnInputStreamBroken(); + + // Unregister from further event insisting + Assert(m_hasReadWatch == true); + CheckedRemoveReadWriteWatch(); + + // Set proper state + m_opened = false; + + // Do not continue + return; + } + + // Interpret data + OnInputStreamRead(); +} + +void WaitableInputOutputExecutionContextSupport::FeedOutput() +{ + if (!m_opened) { + Throw(Exception::NotOpened); + } + + // Anything to feed ? + if (m_outputStream.Empty()) { + return; + } + + // OK to feed output + LogPedantic("Feeding output"); + + Try + { + // Try to write some bytes + size_t bytes = m_waitableInputOutput->Write(m_outputStream, + m_outputStream.Size()); + + if (bytes < m_outputStream.Size()) { + // Start exhaustive output feeding if it is blocked and not already + // started + if (!m_hasWriteWatch) { + AddWriteWatch(); + m_hasWriteWatch = true; + + LogPedantic("Started exhaustive output feeding"); + } + } + + // Some bytes were written, consume them + m_outputStream.Consume(bytes); + } + Catch(AbstractSocket::Exception::ConnectionBroken) // FIXME: Inproper + // exception abstraction + // !!! + { + // Some errors occurred while feeding abstract IO + // Interpret connection broken errors, and pass futher other ones + LogPedantic("Abstract IO connection was broken during write"); + + // Signal broken connection + OnInputStreamBroken(); + + // Unregister from further event insisting + Assert(m_hasReadWatch == true); + CheckedRemoveReadWriteWatch(); + + // Set proper state + m_opened = false; + + // Do not continue + return; + } +} +} +} // namespace DPL diff --git a/modules/support/config.cmake b/modules/support/config.cmake new file mode 100644 index 0000000..e2865f6 --- /dev/null +++ b/modules/support/config.cmake @@ -0,0 +1,26 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + + +SET(DPL_WRT_ENGINE_HEADERS + ${PROJECT_SOURCE_DIR}/modules/support/wrt_plugin_export.h + PARENT_SCOPE +) diff --git a/modules/support/wrt_plugin_export.h b/modules/support/wrt_plugin_export.h new file mode 100755 index 0000000..0cf4e37 --- /dev/null +++ b/modules/support/wrt_plugin_export.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file wrt_plugin_export.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for plugin export API + */ +#ifndef WRT_PLUGIN_EXPORT_H +#define WRT_PLUGIN_EXPORT_H + +#include + +/** + * Widget handle type + */ +typedef int widget_handle_t; + +/** + * Parameter which should be used during policy evaluation. + */ +typedef struct ace_param_s +{ + const char *name; + const char *value; +} ace_param_t; + +/** + * List of additional parameters which should be used during policy evaluation. + */ +typedef struct ace_param_list_s +{ + size_t count; + ace_param_t *param; +} ace_param_list_t; + +/** + * Contains list of device capabilities. Each device capability may have + * associated list of function params. + */ +typedef struct ace_device_cap_s +{ + size_t devcapsCount; + const char** dev_cap_names; + size_t paramsCount; + ace_param_list_t* params; +} ace_device_cap_t; + +/** + * List of device capabilities which must be check. + */ +typedef struct ace_device_capabilities_s +{ + size_t count; + const char **device_cap; +} ace_device_capabilities_t; + +/** + * List of api features that must be checked + */ +typedef struct ace_api_features_s +{ + size_t count; + const char **api_feature; +} ace_api_features_t; + +/** + * Data from request will be used to evaluate policy file. + */ +typedef struct ace_request_s +{ + widget_handle_t widget_handle; + const char* feature_api; + const char* function_name; + ace_device_capabilities_t device_capabilities; + ace_param_list_t param_list; +} ace_request_t; + +/** + * Data from request will be used to evaluate policy file. + */ +typedef struct ace_request_2_s +{ + widget_handle_t widget_handle; + ace_api_features_t api_features; + const char* function_name; + ace_device_cap_t device_capabilities; +} ace_request_2_t; + +/** + * info returned by plugin_api_check_access + */ +#define PLUGIN_API_ACCESS_GRANTED 1 +#define PLUGIN_API_ACCESS_DENIED 0 +#define PLUGIN_API_ACCESS_ERROR -1 + +typedef const void* java_script_context_t; + +typedef struct js_object_properties_s +{ + size_t count; + char** properties; +} js_object_properties_t; + +typedef const void* js_class_template_t; +typedef void* js_object_ref_t; +typedef const void* js_value_ref_t; + +typedef js_class_template_t (*js_class_template_getter)(void); +typedef void* (*js_class_constructor_cb_t)(js_class_template_t, + js_object_ref_t, size_t, + js_value_ref_t[], + js_value_ref_t*); + +typedef enum class_definition_type_e +{ + JS_CLASS, + JS_FUNCTION, + JS_INTERFACE +} class_definition_type_t; + +typedef enum class_definition_iframe_behaviour_e +{ + //object should not be initalized in iframes + //it is default one + NONE, + //object should be copied as reference to each iframe + REFERENCE, // deprecated + //object should be created for each iframe and NOT inform plugin + CREATE_INSTANCE +} class_definition_iframe_behaviour_t; + +typedef enum class_definition_iframe_notice_e +{ + //it is default one + NONE_NOTICE, + ALWAYS_NOTICE +} class_definition_iframe_notice_t; + +typedef enum class_definition_iframe_overlay_e +{ + IGNORED, + USE_OVERLAYED, //deprecated + OVERLAYED_BEFORE_ORIGINAL //deprecated +} class_definition_iframe_overlay_t; //deprecated + +typedef void* js_object_instance_t; +//global_context - id +typedef void (*iframe_loaded_cb)(java_script_context_t global_context, + js_object_instance_t iframe, + js_object_instance_t object); + +typedef void* (*js_function_impl)(void*); + +typedef struct class_definition_options_s +{ + class_definition_type_t type; + class_definition_iframe_behaviour_t iframe_option; + class_definition_iframe_notice_t iframe_notice; + class_definition_iframe_overlay_t iframe_overlay; //deprecated + iframe_loaded_cb cb; + void * private_data; + js_function_impl function; +} class_definition_options_t; + +/* + * list of device caps + */ +typedef struct devcaps_s +{ + char** deviceCaps; + size_t devCapsCount; +} devcaps_t; + +/* + * mapping from a feature to corresponding list of device capabilities + */ +typedef struct feature_devcaps_s +{ + char* feature_name; + devcaps_t devCaps; +} feature_devcaps_t; + +/* + * list of feature_devcaps_t structs + */ +typedef struct feature_mapping_s +{ + feature_devcaps_t* features; + size_t featuresCount; +} feature_mapping_t; + +typedef feature_mapping_t* pfeature_mapping_t; + +typedef pfeature_mapping_t (*features_getter)(void); + +typedef const devcaps_t* (*devcaps_getter)(pfeature_mapping_t /*features*/, + const char* /*featureName*/); +typedef void (*deinitializer)(pfeature_mapping_t /*features*/); + +typedef struct feature_mapping_interface_s +{ + features_getter featGetter; /* returns a list of api features */ + devcaps_getter dcGetter; /* + * for a given api feature returns a list of + * corresponding device capabilities + */ + + deinitializer release; /* as memory ownership of features is + * transfered to callee you have to call + * the release function ptr on features + */ +} feature_mapping_interface_t; + +/* + * This is a structure describing a JS entity template (a class, an interface + * or function), object name and it's parent class name (parent_name). JS + * entity will be bind to a parent class name (parent_name.js_entity_name). + * @param parent_name - parent name (ie Widget.Device) + * @param object_name - object name (DeviceStatus) + * @param interface_name - interface name (e.g. Widget) + * @param js_class_template_getter_fun - js_class_template required to create + * JS object + * @param js_class_consturctor_cb - constructor to call to when instance of + * certain interface is created + * @param private_data private data for object creator if required (usually + * NULL) + */ +typedef struct js_entity_definition_s +{ + const char *parent_name; + const char *object_name; + const char *interface_name; + js_class_template_getter js_class_template_getter_fun; + js_class_constructor_cb_t js_class_constructor_cb; + //class options may be null - default + class_definition_options_t* class_options; +} js_entity_definition_t; + +typedef const js_entity_definition_t *js_entity_definition_ptr_t; + +/** + * Plugin export names + */ +#define PLUGIN_WIDGET_START_PROC on_widget_start +#define PLUGIN_WIDGET_INIT_PROC on_widget_init +#define PLUGIN_WIDGET_STOP_PROC on_widget_stop +#define PLUGIN_FRAME_LOAD_PROC on_frame_load +#define PLUGIN_FRAME_UNLOAD_PROC on_frame_unload +#define PLUGIN_CLASS_MAP class_map +#define PLUGIN_GET_CLASS_PROC_MAP get_widget_class_map + +#define PLUGIN_WIDGET_START_PROC_NAME "on_widget_start" +#define PLUGIN_WIDGET_INIT_PROC_NAME "on_widget_init" +#define PLUGIN_WIDGET_STOP_PROC_NAME "on_widget_stop" +#define PLUGIN_FRAME_LOAD_PROC_NAME "on_frame_load" +#define PLUGIN_FRAME_UNLOAD_PROC_NAME "on_frame_unload" +#define PLUGIN_CLASS_MAP_NAME "class_map" +#define PLUGIN_GET_CLASS_MAP_PROC_NAME "get_widget_class_map" + +/** + * Plugin export typedefs + */ +typedef void (*on_widget_start_proc)(int widgetId); + +typedef void (*on_widget_init_proc)(feature_mapping_interface_t *interface); + +/** + * FIXME: Add documentation + */ +typedef void (*on_widget_stop_proc)(int widgetId); + +typedef void (*on_frame_load_proc)(java_script_context_t context); + +typedef void (*on_frame_unload_proc)(java_script_context_t context); + +typedef const js_entity_definition_t* (*get_widget_entity_map_proc)(); + +#endif // WRT_PLUGIN_EXPORT_H diff --git a/modules/test/config.cmake b/modules/test/config.cmake new file mode 100644 index 0000000..8310c3c --- /dev/null +++ b/modules/test/config.cmake @@ -0,0 +1,54 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_TEST_ENGINE_SOURCES + ${PROJECT_SOURCE_DIR}/modules/test/src/test_results_collector.cpp + ${PROJECT_SOURCE_DIR}/modules/test/src/test_runner.cpp + ${PROJECT_SOURCE_DIR}/modules/test/src/test_runner_child.cpp + ${PROJECT_SOURCE_DIR}/modules/test/src/test_runner_multiprocess.cpp + ${PROJECT_SOURCE_DIR}/modules/test/src/process_pipe.cpp + ${PROJECT_SOURCE_DIR}/modules/test/src/value_separated_policies.cpp + ${PROJECT_SOURCE_DIR}/modules/test/src/value_separated_tokens.cpp + PARENT_SCOPE +) + + +SET(DPL_TEST_ENGINE_HEADERS + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_results_collector.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_runner.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_runner_child.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/test_runner_multiprocess.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/process_pipe.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/abstract_input_parser.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/abstract_input_reader.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/abstract_input_tokenizer.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/value_separated_parser.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/value_separated_policies.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/value_separated_reader.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/value_separated_tokenizer.h + ${PROJECT_SOURCE_DIR}/modules/test/include/dpl/test/value_separated_tokens.h + PARENT_SCOPE +) + +SET(DPL_TEST_ENGINE_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/test/include + PARENT_SCOPE +) diff --git a/modules/test/include/dpl/test/abstract_input_parser.h b/modules/test/include/dpl/test/abstract_input_parser.h new file mode 100644 index 0000000..dcb2243 --- /dev/null +++ b/modules/test/include/dpl/test/abstract_input_parser.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input_parser.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Simple parser abstraction to be included into reader + */ + +#ifndef ABSTRACT_INPUT_PARSER_H +#define ABSTRACT_INPUT_PARSER_H + +#include + +#include + +namespace DPL { + +/** + * Abstract class of parser that produces some higher level abstraction + * basing on incoming tokens + */ +template class AbstractInputParser +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, ParserError) + }; + + typedef Result ResultType; + typedef Token TokenType; + + virtual ~AbstractInputParser() {} + + virtual void ConsumeToken(std::unique_ptr && token) = 0; + virtual bool IsStateValid() = 0; + virtual Result GetResult() const = 0; +}; + +} + +#endif diff --git a/modules/test/include/dpl/test/abstract_input_reader.h b/modules/test/include/dpl/test/abstract_input_reader.h new file mode 100644 index 0000000..6b23dd6 --- /dev/null +++ b/modules/test/include/dpl/test/abstract_input_reader.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input_reader.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Simple output reader template + * + * This generic skeleton for parser which assume being composed from abstract two logical components: + * + * - parser, + * - tokenizer/lexer, + * which implements token flow logic. Logic of components may be arbitrary. See depending change for uses. + * + * Components are created at start time of reader (constructor which moves arguments). + * Virtuality (abstract base classes) are for enforcing same token type. + * I assumed it's more clear than writen static asserts in code enforcing this. + */ + +#ifndef ABSTRACT_INPUT_READER_H +#define ABSTRACT_INPUT_READER_H + +#include + +#include +#include +#include +#include + +namespace DPL { + +/** + * Base reader class that can be used with any AbstractInput instance + * + * This class is encapsulation class for tokenizer and reader subelements + * and contains basic calculation pattern + * + * There a waste in form of virtuality for parser and tokenizer + * -> this for forcing same tokenT type in both components + */ +template class AbstractInputReader +{ +public: + typedef ResultT TokenType; + typedef TokenT ResultType; + typedef AbstractInputParser ParserBase; + typedef AbstractInputTokenizer TokenizerBase; + + class Exception + { + public: + typedef typename TokenizerBase::Exception::TokenizerError TokenizerError; + typedef typename ParserBase::Exception::ParserError ParserError; + }; + + AbstractInputReader(std::shared_ptr ia, + std::unique_ptr && parser, + std::unique_ptr && tokenizer) + : m_parser(std::move(parser)), m_tokenizer(std::move(tokenizer)) + { + m_tokenizer->Reset(ia); + } + + virtual ~AbstractInputReader() {} + + ResultT ReadInput() + { + typedef typename Exception::TokenizerError TokenizerError; + typedef typename Exception::ParserError ParserError; + + while(true) + { + std::unique_ptr token = m_tokenizer->GetNextToken(); + if(!token) + { + if(!m_tokenizer->IsStateValid()) + { + ThrowMsg(TokenizerError, "Tokenizer error"); + } + if(!m_parser->IsStateValid()) + { + ThrowMsg(ParserError, "Parser error"); + } + + return m_parser->GetResult(); + } + m_parser->ConsumeToken(std::move(token)); + } + } + +protected: + std::unique_ptr m_parser; + std::unique_ptr m_tokenizer; +}; + +} + +#endif diff --git a/modules/test/include/dpl/test/abstract_input_tokenizer.h b/modules/test/include/dpl/test/abstract_input_tokenizer.h new file mode 100644 index 0000000..a376341 --- /dev/null +++ b/modules/test/include/dpl/test/abstract_input_tokenizer.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input_tokenizer.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Simple tokenizer abstraction + */ + +#ifndef ABSTRACT_INPUT_TOKENIZER_H +#define ABSTRACT_INPUT_TOKENIZER_H + +#include +#include + +#include +#include +#include + +namespace DPL { + +/** + * Tokenizer abstract base class + * + * This class is supposed to accept AbstractInput in constructor + * and produce tokens until end of source. If parsing ends in invalid state + * then IsStateValid() should return false + */ +template class AbstractInputTokenizer +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, TokenizerError) + }; + + typedef Token TokenType; + + AbstractInputTokenizer() {} + virtual ~AbstractInputTokenizer() {} + + /** + * @brief Reset resets data source + * @param wia AbstractWaitableInputAdapter instance + */ + virtual void Reset(std::shared_ptr wia) + { + m_input = wia; + } + + /** + * @brief GetNextToken + * + * Parses next token. + * Returns pointer to token + * @throw TokenizerError in condition of input source error + * If returned empty pointer IsStateValid() == true -> end of input + * IsStateValid() == false -> error + * + * @param token token to be set + * @return + */ + virtual std::unique_ptr GetNextToken() = 0; + virtual bool IsStateValid() = 0; + +protected: + std::shared_ptr m_input; +}; + +} + +#endif diff --git a/modules/test/include/dpl/test/process_pipe.h b/modules/test/include/dpl/test/process_pipe.h new file mode 100644 index 0000000..52ab7e7 --- /dev/null +++ b/modules/test/include/dpl/test/process_pipe.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file process_pipe.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation pipe from process + */ +#ifndef PROCESS_PIPE_H +#define PROCESS_PIPE_H + +#include +#include + +#include + +namespace DPL { + +class ProcessPipe : public FileInput +{ +public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DoubleOpen) + }; + + enum class PipeErrorPolicy + { + NONE, + OFF, + PIPE + }; + + explicit ProcessPipe(PipeErrorPolicy err = PipeErrorPolicy::NONE); + virtual ~ProcessPipe(); + + void Open(const std::string &command); + void Close(); + +private: + FILE * m_file; + PipeErrorPolicy m_errPolicy; +}; + +} + +#endif // PROCESS_PIPE_H diff --git a/modules/test/include/dpl/test/test_results_collector.h b/modules/test/include/dpl/test/test_results_collector.h new file mode 100644 index 0000000..acb2914 --- /dev/null +++ b/modules/test/include/dpl/test/test_results_collector.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_results_collector.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Header file with declaration of TestResultsCollectorBase + */ + +#ifndef DPL_TEST_RESULTS_COLLECTOR_H +#define DPL_TEST_RESULTS_COLLECTOR_H + +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Test { +class TestResultsCollectorBase; +typedef std::shared_ptr +TestResultsCollectorBasePtr; + +class TestResultsCollectorBase : + private DPL::Noncopyable +{ + public: + typedef TestResultsCollectorBase* (*CollectorConstructorFunc)(); + typedef std::list TestCaseIdList; + struct FailStatus + { + enum Type + { + NONE, + FAILED, + IGNORED, + INTERNAL + }; + }; + + virtual ~TestResultsCollectorBase() {} + + virtual bool Configure() + { + return true; + } + virtual void Start(int count) { DPL_UNUSED_PARAM(count); } + virtual void Finish() { } + virtual void CollectCurrentTestGroupName(const std::string& /*groupName*/) + {} + + virtual void CollectTestsCasesList(const TestCaseIdList& /*list*/) {} + virtual void CollectResult(const std::string& id, + const std::string& description, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") = 0; + virtual std::string CollectorSpecificHelp() const + { + return ""; + } + virtual bool ParseCollectorSpecificArg (const std::string& /*arg*/) + { + return false; + } + + static TestResultsCollectorBase* Create(const std::string& name); + static void RegisterCollectorConstructor( + const std::string& name, + CollectorConstructorFunc + constructor); + static std::vector GetCollectorsNames(); + + private: + typedef std::map ConstructorsMap; + static ConstructorsMap m_constructorsMap; +}; +} +} + +#endif /* DPL_TEST_RESULTS_COLLECTOR_H */ diff --git a/modules/test/include/dpl/test/test_runner.h b/modules/test/include/dpl/test/test_runner.h new file mode 100644 index 0000000..cf927ef --- /dev/null +++ b/modules/test/include/dpl/test/test_runner.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the header file of test runner + */ +#ifndef DPL_TEST_RUNNER_H +#define DPL_TEST_RUNNER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Test { +class TestRunner +{ + typedef std::map + TestResultsCollectors; + TestResultsCollectors m_collectors; + + std::string m_startTestId; + bool m_runIgnored; + + public: + TestRunner() : + m_terminate(false) + , m_allowChildLogs(false) + {} + + typedef void (*TestCase)(); + + private: + struct TestCaseStruct + { + std::string name; + TestCase proc; + + bool operator <(const TestCaseStruct &other) const + { + return name < other.name; + } + + bool operator ==(const TestCaseStruct &other) const + { + return name == other.name; + } + + TestCaseStruct(const std::string &n, TestCase p) : + name(n), + proc(p) + {} + }; + + typedef std::list TestCaseStructList; + typedef std::map TestCaseGroupMap; + TestCaseGroupMap m_testGroups; + + typedef std::set SelectedTestNameSet; + SelectedTestNameSet m_selectedTestNamesSet; + typedef std::set SelectedTestGroupSet; + SelectedTestGroupSet m_selectedTestGroupSet; + std::string m_currentGroup; + + DPL::Atomic m_totalAssertions; + + // Terminate without any logs. + // Some test requires to call fork function. + // Child process must not produce any logs and should die quietly. + bool m_terminate; + bool m_allowChildLogs; + + void Banner(); + void InvalidArgs(const std::string& message = "Invalid arguments!"); + void Usage(); + + bool filterGroupsByXmls(const std::vector & files); + bool filterByXML(std::map & casesMap); + void normalizeXMLTag(std::string& str, const std::string& testcase); + + enum Status { FAILED, IGNORED, PASS }; + + Status RunTestCase(const TestCaseStruct& testCase); + + void RunTests(); + + void CollectResult(const std::string& id, + const std::string& description, + const TestResultsCollectorBase::FailStatus::Type status + = TestResultsCollectorBase::FailStatus::NONE, + const std::string& reason = std::string()); + + public: + class TestFailed + { + private: + std::string m_message; + + public: + TestFailed() + {} + + //! \brief Failed test message creator + //! + //! \param[in] aTest string for tested expression + //! \param[in] aFile source file name + //! \param[in] aLine source file line + //! \param[in] aMessage error message + TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage); + + TestFailed(const std::string &message); + + std::string GetMessage() const + { + return m_message; + } + }; + + class Ignored + { + private: + std::string m_message; + + public: + Ignored() + {} + + Ignored(const std::string &message) : + m_message(message) + {} + + std::string GetMessage() const + { + return m_message; + } + }; + + void MarkAssertion(); + + void RegisterTest(const char *testName, TestCase proc); + void InitGroup(const char* name); + + int ExecTestRunner(int argc, char *argv[]); + typedef std::vector ArgsList; + int ExecTestRunner(const ArgsList& args); + bool getRunIgnored() const; + // The runner will terminate as soon as possible (after current test). + void Terminate(); + bool GetAllowChildLogs(); +}; + +typedef DPL::Singleton TestRunnerSingleton; +} +} // namespace DPL + +#define RUNNER_TEST_GROUP_INIT(GroupName) \ + static int Static##GroupName##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().InitGroup(#GroupName); \ + return 0; \ + } \ + const int DPL_UNUSED Static##GroupName##InitVar = \ + Static##GroupName##Init(); + +#define RUNNER_TEST(Proc) \ + void Proc(); \ + static int Static##Proc##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc() + +#define RUNNER_ASSERT_MSG(test, message) \ + do \ + { \ + DPL::Test::TestRunnerSingleton::Instance().MarkAssertion(); \ + \ + if (!(test)) \ + { \ + std::ostringstream assertMsg; \ + assertMsg << message; \ + throw DPL::Test::TestRunner::TestFailed(#test, \ + __FILE__, \ + __LINE__, \ + assertMsg.str()); \ + } \ + } while (0) + +#define RUNNER_ASSERT(test) RUNNER_ASSERT_MSG(test, "") + +#define RUNNER_FAIL RUNNER_ASSERT(false) + +#define RUNNER_IGNORED_MSG(message) do { std::ostringstream assertMsg; \ + assertMsg << message; \ + throw DPL::Test::TestRunner::Ignored( \ + assertMsg.str()); \ +} while (0) + +#endif // DPL_TEST_RUNNER_H diff --git a/modules/test/include/dpl/test/test_runner_child.h b/modules/test/include/dpl/test/test_runner_child.h new file mode 100644 index 0000000..1da0f1b --- /dev/null +++ b/modules/test/include/dpl/test/test_runner_child.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_child.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the header file of test runner + */ +#ifndef DPL_TEST_RUNNER_CHILD_H +#define DPL_TEST_RUNNER_CHILD_H + +#include + +namespace DPL { +namespace Test { + +class PipeWrapper : DPL::Noncopyable +{ + public: + enum Usage { + READONLY, + WRITEONLY + }; + + enum Status { + SUCCESS, + TIMEOUT, + ERROR + }; + + PipeWrapper(); + + bool isReady(); + + void setUsage(Usage usage); + + virtual ~PipeWrapper(); + + Status send(int code, std::string &message); + + Status receive(int &code, std::string &data, time_t deadline); + + void closeAll(); + + protected: + + std::string toBinaryString(int data); + + void closeHelp(int desc); + + Status writeHelp(const void *buffer, int size); + + Status readHelp(void *buf, int size, time_t deadline); + + static const int PIPE_CLOSED = -1; + + int m_pipefd[2]; +}; + +void RunChildProc(TestRunner::TestCase procChild); +} // namespace Test +} // namespace DPL + +#define RUNNER_CHILD_TEST(Proc) \ + void Proc(); \ + void Proc##Child(); \ + static int Static##Proc##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc(){ \ + DPL::Test::RunChildProc(&Proc##Child); \ + } \ + void Proc##Child() + +#endif // DPL_TEST_RUNNER_CHILD_H diff --git a/modules/test/include/dpl/test/test_runner_multiprocess.h b/modules/test/include/dpl/test/test_runner_multiprocess.h new file mode 100644 index 0000000..279b5ef --- /dev/null +++ b/modules/test/include/dpl/test/test_runner_multiprocess.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.h + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the header file of multiprocess test runner + */ +#ifndef DPL_TEST_RUNNER_MULTIPROCESS_H +#define DPL_TEST_RUNNER_MULTIPROCESS_H + +#include + +namespace DPL { +namespace Test { + +class SimplePipeWrapper : + public PipeWrapper +{ + public: + SimplePipeWrapper(); + + virtual ~SimplePipeWrapper(); + + Status send(std::string &message); + Status receive(std::string &data, bool &empty, time_t deadline); +}; + +void RunMultiProc(TestRunner::TestCase procMulti); +} // namespace Test +} // namespace DPL + +#define RUNNER_MULTIPROCESS_TEST(Proc) \ + void Proc(); \ + void Proc##Multi(); \ + static int Static##Proc##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc(){ \ + DPL::Test::RunMultiProc(&Proc##Multi); \ + } \ + void Proc##Multi() + +#endif // DPL_TEST_RUNNER_MULTIPROCESS_H diff --git a/modules/test/include/dpl/test/value_separated_parser.h b/modules/test/include/dpl/test/value_separated_parser.h new file mode 100644 index 0000000..635e548 --- /dev/null +++ b/modules/test/include/dpl/test/value_separated_parser.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_parser.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Parser for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_PARSER_H +#define VALUE_SEPARATED_PARSER_H + +#include +#include +#include + +#include +#include + +namespace DPL { + +typedef std::vector VSLine; +typedef std::vector VSResult; +typedef std::shared_ptr VSResultPtr; + +/** + * Value Seperated parser + * + * Requires following policy class: + * + * template + * struct CSVParserPolicy + * { + * static bool SkipLine(VSLine & ); + * static bool Validate(VSResultPtr& result); + * }; + */ +template +class VSParser : public AbstractInputParser +{ +public: + VSParser() : m_switchLine(true), m_result(new VSResult()) {} + + void ConsumeToken(std::unique_ptr && token) + { + if(m_switchLine) + { + m_result->push_back(VSLine()); + m_switchLine = false; + } + if(token->isNewLine()) + { + if(ParserPolicy::SkipLine(*m_result->rbegin())) + { + m_result->pop_back(); + } + m_switchLine = true; + } + else + { + m_result->rbegin()->push_back(token->cell()); + } + } + + bool IsStateValid() + { + return ParserPolicy::Validate(m_result); + } + + VSResultPtr GetResult() const + { + return m_result; + } + +private: + bool m_switchLine; + VSResultPtr m_result; +}; + +} + +#endif diff --git a/modules/test/include/dpl/test/value_separated_policies.h b/modules/test/include/dpl/test/value_separated_policies.h new file mode 100644 index 0000000..c432703 --- /dev/null +++ b/modules/test/include/dpl/test/value_separated_policies.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_policies.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Example policy classes for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_POLICIES_H +#define VALUE_SEPARATED_POLICIES_H + +#include +#include +#include + +namespace DPL { + +struct CSVTokenizerPolicy +{ + static std::string GetSeperators(); //cells in line are separated by given characters + static bool SkipEmpty(); //if cell is empty, shoudl I skip? + static void PrepareValue(std::string &); //transform each value + static bool TryAgainAtEnd(int); //read is nonblocking so dat may not be yet available, should I retry? +}; + +struct CSVParserPolicy +{ + static bool SkipLine(const std::vector & ); //should I skip whole readline? + static bool Validate(std::shared_ptr > > & result); //validate and adjust output data +}; + +} + +#endif diff --git a/modules/test/include/dpl/test/value_separated_reader.h b/modules/test/include/dpl/test/value_separated_reader.h new file mode 100644 index 0000000..8e78aaa --- /dev/null +++ b/modules/test/include/dpl/test/value_separated_reader.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_reader.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Reader for some value seperated files/data + * + * This is parser for files containing lines with values seperated with custom charaters. + * Purpose of this is to parse output similar to csv and hide (no need for rewriting) + * buffers, reads, code errors. Result is two dimensional array. + * + * Reader is designed as class configured with policies classes: + * http://en.wikipedia.org/wiki/Policy-based_design + */ + +#ifndef VALUE_SEPARATED_READER_H +#define VALUE_SEPARATED_READER_H + +#include +#include +#include +#include +#include + +namespace DPL { + +/** + * Reader for input with values separated with defined characters + * + * Usage: + * - define both policies classes for defining and customize exact behaviour of reader + * - make typedef for VSReader template instance with your policies + * + */ +template +class VSReader : public AbstractInputReader +{ +public: + VSReader(std::shared_ptr wia) + : AbstractInputReader(wia, + std::unique_ptr(new VSParser()), + std::unique_ptr(new VSTokenizer())) + {} +}; + +typedef VSReader CSVReader; + +} + +#endif diff --git a/modules/test/include/dpl/test/value_separated_tokenizer.h b/modules/test/include/dpl/test/value_separated_tokenizer.h new file mode 100644 index 0000000..13403b5 --- /dev/null +++ b/modules/test/include/dpl/test/value_separated_tokenizer.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_tokenizer.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Tokenizer for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_TOKENIZER_H +#define VALUE_SEPARATED_TOKENIZER_H + +#include +#include +#include + + +namespace DPL { + +/** + * Value Sperated tokenizer + * + * Requires following policy class: + * + * struct TokenizerPolicy + * { + * static std::string GetSeperators(); + * static bool SkipEmpty(); + * static void PrepareValue(std::string & value); + * }; + */ +template +class VSTokenizer : public AbstractInputTokenizer +{ +public: + VSTokenizer() {} + + void Reset(std::shared_ptr ia) + { + AbstractInputTokenizer::Reset(ia); + m_queue.Clear(); + m_finished = false; + m_newline = false; + } + + std::unique_ptr GetNextToken() + { + std::unique_ptr token; + std::string data; + char byte; + int tryNumber = 0; + + while(true) + { + //check if newline was approched + if(m_newline) + { + token.reset(new VSToken()); + m_newline = false; + return token; + } + + //read next data + if(m_queue.Empty()) + { + if(m_finished) + { + return token; + } + else + { + auto baptr = m_input->Read(4096); + if(baptr.get() == 0) + { + ThrowMsg(Exception::TokenizerError, "Input read failed"); + } + if(baptr->Empty()) + { + if(TokenizerPolicy::TryAgainAtEnd(tryNumber)) + { + ++tryNumber; + continue; + } + m_finished = true; + return token; + } + m_queue.AppendMoveFrom(*baptr); + } + } + + //process + m_queue.FlattenConsume(&byte, 1); //queue uses pointer to consume bytes, this do not causes reallocations + if(byte == '\n') + { + m_newline = true; + if(!data.empty() || !TokenizerPolicy::SkipEmpty()) + { + ProduceString(token, data); + return token; + } + } + else if(TokenizerPolicy::GetSeperators().find(byte) != std::string::npos) + { + if(!data.empty() || !TokenizerPolicy::SkipEmpty()) + { + ProduceString(token, data); + return token; + } + } + else + { + data += byte; + } + } + } + + bool IsStateValid() + { + if(!m_queue.Empty() && m_finished) return false; + return true; + } + +protected: + void ProduceString(std::unique_ptr & token, std::string & data) + { + TokenizerPolicy::PrepareValue(data); + token.reset(new VSToken(data)); + } + + BinaryQueue m_queue; + bool m_finished; + bool m_newline; +}; + +} + +#endif diff --git a/modules/test/include/dpl/test/value_separated_tokens.h b/modules/test/include/dpl/test/value_separated_tokens.h new file mode 100644 index 0000000..3c49157 --- /dev/null +++ b/modules/test/include/dpl/test/value_separated_tokens.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_tokens.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief Token class for some value seperated files/data + */ + +#ifndef VALUE_SEPARATED_TOKENS_H +#define VALUE_SEPARATED_TOKENS_H + +#include + +namespace DPL { + +class VSToken +{ +public: + VSToken(const std::string & c); + VSToken(); //newline token - no new class to simplify + const std::string & cell() const; + + bool isNewLine(); +private: + bool m_newline; + std::string m_cell; +}; + +} + +#endif diff --git a/modules/test/src/process_pipe.cpp b/modules/test/src/process_pipe.cpp new file mode 100644 index 0000000..68c910f --- /dev/null +++ b/modules/test/src/process_pipe.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file process_pipe.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation pipe from process + */ + +#include +#include + +namespace DPL { + +ProcessPipe::ProcessPipe(PipeErrorPolicy err) : m_file(NULL), m_errPolicy(err) +{ +} + +ProcessPipe::~ProcessPipe() +{ +} + +void ProcessPipe::Open(const std::string & command) +{ + if(m_file != NULL) + { + ThrowMsg(Exception::DoubleOpen, "Trying to open pipe second time. Close it first"); + } + + std::string stdErrRedirection; + switch(m_errPolicy) + { + case PipeErrorPolicy::NONE: break; + case PipeErrorPolicy::OFF: stdErrRedirection = " 2>/dev/null"; break; + case PipeErrorPolicy::PIPE: stdErrRedirection = " 2>&1"; break; + default: break; + } + + std::string fcommand = command + stdErrRedirection; + FILE * file = popen(fcommand.c_str(), "r"); + + // Throw an exception if an error occurred + if (file == NULL) { + ThrowMsg(FileInput::Exception::OpenFailed, fcommand); + } + + // Save new descriptor + m_file = file; + m_fd = fileno(m_file); + + LogPedantic("Opened pipe: " << fcommand); +} + +void ProcessPipe::Close() +{ + if (m_fd == -1) { + return; + } + + if (pclose(m_file) == -1) { + Throw(FileInput::Exception::CloseFailed); + } + + m_fd = -1; + m_file = NULL; + + LogPedantic("Closed pipe"); +} + +} diff --git a/modules/test/src/test_results_collector.cpp b/modules/test/src/test_results_collector.cpp new file mode 100644 index 0000000..665ca7d --- /dev/null +++ b/modules/test/src/test_results_collector.cpp @@ -0,0 +1,987 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_results_collector.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Implementation file some concrete TestResulstsCollector + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define GREEN_RESULT_OK "[%s%s%s]\n", BOLD_GREEN_BEGIN, " OK ", \ + BOLD_GREEN_END + +namespace DPL { +namespace Test { +namespace { +const char *DEFAULT_HTML_FILE_NAME = "index.html"; +const char *DEFAULT_TAP_FILE_NAME = "results.tap"; +const char *DEFAULT_XML_FILE_NAME = "results.xml"; + +bool ParseCollectorFileArg(const std::string &arg, std::string &filename) +{ + const std::string argname = "--file="; + if (arg.find(argname) == 0 ) { + filename = arg.substr(argname.size()); + return true; + } + return false; +} + +class Statistic +{ + public: + Statistic() : + m_failed(0), + m_ignored(0), + m_passed(0), + m_count(0) + {} + + void AddTest(TestResultsCollectorBase::FailStatus::Type type) + { + ++m_count; + switch (type) { + case TestResultsCollectorBase::FailStatus::INTERNAL: + case TestResultsCollectorBase::FailStatus::FAILED: ++m_failed; + break; + case TestResultsCollectorBase::FailStatus::IGNORED: ++m_ignored; + break; + case TestResultsCollectorBase::FailStatus::NONE: ++m_passed; + break; + default: + Assert(false && "Bad FailStatus"); + } + } + + std::size_t GetTotal() const + { + return m_count; + } + std::size_t GetPassed() const + { + return m_passed; + } + std::size_t GetSuccesed() const + { + return m_passed; + } + std::size_t GetFailed() const + { + return m_failed; + } + std::size_t GetIgnored() const + { + return m_ignored; + } + float GetPassedOrIgnoredPercend() const + { + float passIgnoredPercent = + 100.0f * (static_cast(m_passed) + + static_cast(m_ignored)) + / static_cast(m_count); + return passIgnoredPercent; + } + + private: + std::size_t m_failed; + std::size_t m_ignored; + std::size_t m_passed; + std::size_t m_count; +}; + +class ConsoleCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + ConsoleCollector() {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + printf("Starting group %s\n", name.c_str()); + m_currentGroup = name; + } + + virtual void Finish() + { + using namespace DPL::Colors::Text; + + // Show result + FOREACH(group, m_groupsStats) { + PrintStats(group->first, group->second); + } + PrintStats("All tests together", m_stats); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + using namespace DPL::Colors::Text; + std::string tmp = "'" + id + "' ..."; + + printf("Running test case %-60s", tmp.c_str()); + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + printf(GREEN_RESULT_OK); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + PrintfErrorMessage("INTERNAL", reason, true); + break; + default: + Assert(false && "Bad status"); + } + m_stats.AddTest(status); + m_groupsStats[m_currentGroup].AddTest(status); + } + + void PrintfErrorMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Text; + if (verbosity) { + printf("[%s%s%s] %s%s%s\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END, + BOLD_YELLOW_BEGIN, + message.c_str(), + BOLD_YELLOW_END); + } else { + printf("[%s%s%s]\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Text; + if (verbosity) { + printf("[%s%s%s] %s%s%s\n", + CYAN_BEGIN, + type, + CYAN_END, + BOLD_GOLD_BEGIN, + message.c_str(), + BOLD_GOLD_END); + } else { + printf("[%s%s%s]\n", + CYAN_BEGIN, + type, + CYAN_END); + } + } + + void PrintStats(const std::string& title, const Statistic& stats) + { + using namespace DPL::Colors::Text; + printf("\n%sResults [%s]: %s\n", BOLD_GREEN_BEGIN, + title.c_str(), BOLD_GREEN_END); + printf("%s%s%3d%s\n", + CYAN_BEGIN, + "Total tests: ", + stats.GetTotal(), + CYAN_END); + printf(" %s%s%3d%s\n", + CYAN_BEGIN, + "Succeeded: ", + stats.GetPassed(), + CYAN_END); + printf(" %s%s%3d%s\n", + CYAN_BEGIN, + "Failed: ", + stats.GetFailed(), + CYAN_END); + printf(" %s%s%3d%s\n", + CYAN_BEGIN, + "Ignored: ", + stats.GetIgnored(), + CYAN_END); + } + + Statistic m_stats; + std::map m_groupsStats; + std::string m_currentGroup; +}; + +TestResultsCollectorBase* ConsoleCollector::Constructor() +{ + return new ConsoleCollector(); +} + +class HtmlCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + HtmlCollector() : m_filename(DEFAULT_HTML_FILE_NAME) {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + fprintf(m_fp.Get(), "Starting group %s", name.c_str()); + m_currentGroup = name; + } + + virtual bool Configure() + { + m_fp.Reset(fopen(m_filename.c_str(), "w")); + if (!m_fp) { + LogPedantic("Could not open file " << m_filename << " for writing"); + return false; + } + return true; + } + virtual std::string CollectorSpecificHelp() const + { + return "--file= - name of file for output\n" + " default - index.html\n"; + } + + virtual void Start(int count) + { + DPL_UNUSED_PARAM(count); + AssertMsg(!!m_fp, "File handle must not be null"); + fprintf(m_fp.Get(), + "\n"); + fprintf(m_fp.Get(), + "\n"); + fprintf(m_fp.Get(), "\n"); + fprintf(m_fp.Get(), "
\n");
+        fprintf(m_fp.Get(), "\n");
+    }
+
+    virtual void Finish()
+    {
+        using namespace DPL::Colors::Html;
+        // Show result
+        FOREACH(group, m_groupsStats) {
+            PrintStats(group->first, group->second);
+        }
+        PrintStats("All tests together", m_stats);
+        fprintf(m_fp.Get(), "\n");
+        fprintf(m_fp.Get(), "
\n"); + fprintf(m_fp.Get(), "\n"); + fprintf(m_fp.Get(), "\n"); + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + using namespace DPL::Colors::Html; + std::string tmp = "'" + id + "' ..."; + + fprintf(m_fp.Get(), "Running test case %-100s", tmp.c_str()); + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + fprintf(m_fp.Get(), GREEN_RESULT_OK); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + PrintfErrorMessage("INTERNAL", reason, true); + break; + default: + Assert(false && "Bad status"); + } + m_groupsStats[m_currentGroup].AddTest(status); + m_stats.AddTest(status); + } + + void PrintfErrorMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Html; + if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s] %s%s%s\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END, + BOLD_YELLOW_BEGIN, + message.c_str(), + BOLD_YELLOW_END); + } else { + fprintf(m_fp.Get(), + "[%s%s%s]\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Html; + + if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s] %s%s%s\n", + CYAN_BEGIN, + type, + CYAN_END, + BOLD_GOLD_BEGIN, + message.c_str(), + BOLD_GOLD_END); + } else { + fprintf(m_fp.Get(), + "[%s%s%s]\n", + CYAN_BEGIN, + type, + CYAN_END); + } + } + + void PrintStats(const std::string& name, const Statistic& stats) + { + using namespace DPL::Colors::Html; + fprintf( + m_fp.Get(), "\n%sResults [%s]:%s\n", BOLD_GREEN_BEGIN, + name.c_str(), BOLD_GREEN_END); + fprintf( + m_fp.Get(), "%s%s%3d%s\n", CYAN_BEGIN, + "Total tests: ", stats.GetTotal(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3d%s\n", CYAN_BEGIN, + "Succeeded: ", stats.GetPassed(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3d%s\n", CYAN_BEGIN, + "Failed: ", stats.GetFailed(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3d%s\n", CYAN_BEGIN, + "Ignored: ", stats.GetIgnored(), CYAN_END); + } + + std::string m_filename; + ScopedFClose m_fp; + Statistic m_stats; + std::string m_currentGroup; + std::map m_groupsStats; +}; + +TestResultsCollectorBase* HtmlCollector::Constructor() +{ + return new HtmlCollector(); +} + +class XmlCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + XmlCollector() : m_filename(DEFAULT_XML_FILE_NAME) {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + std::size_t pos = GetCurrentGroupPosition(); + if (std::string::npos != pos) { + GroupFinish(pos); + FlushOutput(); + m_stats = Statistic(); + } + + pos = m_outputBuffer.find(""); + if (std::string::npos == pos) { + ThrowMsg(DPL::Exception, "Could not find test suites closing tag"); + } + GroupStart(pos, name); + } + + void GroupStart(const std::size_t pos, const std::string& name) + { + std::stringstream groupHeader; + groupHeader << "\n\t"; + + groupHeader << "\n\t\t"; + groupHeader << + "\n\t\t\t"; + groupHeader << "\n\t\t"; + + groupHeader << "\n\t"; + + m_outputBuffer.insert(pos - 1, groupHeader.str()); + } + + virtual bool Configure() + { + m_fp.Reset(fopen(m_filename.c_str(), "w")); + if (!m_fp) { + LogPedantic("Could not open file " << m_filename << " for writing"); + return false; + } + return true; + } + + virtual std::string CollectorSpecificHelp() const + { + return "--file= - name of file for output\n" + " default - results.xml\n"; + } + + virtual void Start(int count) + { + AssertMsg(!!m_fp, "File handle must not be null"); + m_outputBuffer.append("\n"); + m_outputBuffer.append("= 0) + { + m_outputBuffer.append("total=\""); + m_outputBuffer.append(DPL::lexical_cast(count)); + m_outputBuffer.append("\""); + } + m_outputBuffer.append(" >\n"); + FlushOutput(); + } + + virtual void Finish() + { + std::size_t pos = GetCurrentGroupPosition(); + if (std::string::npos != pos) { + GroupFinish(pos); + FlushOutput(); + } + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + m_resultBuffer.erase(); + m_resultBuffer.append("\t\t\n"); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + m_resultBuffer.append(" status=\"FAILED\">\n"); + PrintfErrorMessage("FAILED", EscapeSpecialCharacters(reason), true); + m_resultBuffer.append("\t\t\n"); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + m_resultBuffer.append(" status=\"Ignored\">\n"); + PrintfIgnoredMessage("Ignored", EscapeSpecialCharacters( + reason), true); + m_resultBuffer.append("\t\t\n"); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + m_resultBuffer.append(" status=\"FAILED\">\n"); + PrintfErrorMessage("INTERNAL", EscapeSpecialCharacters( + reason), true); + m_resultBuffer.append("\t\t"); + break; + default: + Assert(false && "Bad status"); + } + std::size_t group_pos = GetCurrentGroupPosition(); + if (std::string::npos == group_pos) { + ThrowMsg(DPL::Exception, "No current group set"); + } + + std::size_t last_case_pos = m_outputBuffer.find( + "\n"); + } else { + m_resultBuffer.append("\t\t\t\n"); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + if (verbosity) { + m_resultBuffer.append("\t\t\t\n"); + } else { + m_resultBuffer.append("\t\t\t\n"); + } + } + + std::string EscapeSpecialCharacters(std::string s) + { + for (unsigned int i = 0; i < s.size();) { + switch (s[i]) { + case '"': + s.erase(i, 1); + s.insert(i, """); + i += 6; + break; + + case '&': + s.erase(i, 1); + s.insert(i, "&"); + i += 5; + break; + + case '<': + s.erase(i, 1); + s.insert(i, "<"); + i += 4; + break; + + case '>': + s.erase(i, 1); + s.insert(i, ">"); + i += 4; + break; + + case '\'': + s.erase(i, 1); + s.insert(i, "'"); + i += 5; + break; + default: + ++i; + break; + } + } + return s; + } + + std::string m_filename; + ScopedFClose m_fp; + Statistic m_stats; + std::string m_outputBuffer; + std::string m_resultBuffer; +}; + +TestResultsCollectorBase* XmlCollector::Constructor() +{ + return new XmlCollector(); +} + +class CSVCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + CSVCollector() {} + + virtual void Start(int count) + { + DPL_UNUSED_PARAM(count); + printf("GROUP;ID;RESULT;REASON\n"); + } + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + m_currentGroup = name; + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + std::string statusMsg = ""; + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: statusMsg = "OK"; + break; + case TestResultsCollectorBase::FailStatus::FAILED: statusMsg = "FAILED"; + break; + case TestResultsCollectorBase::FailStatus::IGNORED: statusMsg = + "IGNORED"; + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: statusMsg = + "FAILED"; + break; + default: + Assert(false && "Bad status"); + } + printf("%s;%s;%s;%s\n", + m_currentGroup.c_str(), + id.c_str(), + statusMsg.c_str(), + reason.c_str()); + } + + std::string m_currentGroup; +}; + +TestResultsCollectorBase* CSVCollector::Constructor() +{ + return new CSVCollector(); +} +} + +class TAPCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + TAPCollector() : m_filename(DEFAULT_TAP_FILE_NAME) {} + + virtual bool Configure() + { + m_output.open(m_filename.c_str(), std::ios_base::trunc); + if (m_output.fail()) { + LogError("Can't open output file: " << m_filename); + return false; + } + return true; + } + virtual std::string CollectorSpecificHelp() const + { + std::string retVal = "--file= - name of file for output\n" + " default - "; + retVal += DEFAULT_TAP_FILE_NAME; + retVal += "\n"; + return retVal; + } + + virtual void Start(int count) + { + DPL_UNUSED_PARAM(count); + AssertMsg(m_output.good(), "Output file must be opened."); + m_output << "TAP version 13" << std::endl; + m_testIndex = 0; + } + + virtual void Finish() + { + m_output << "1.." << m_testIndex << std::endl; + m_output << m_collectedData.rdbuf(); + m_output.close(); + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& description, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "") + { + m_testIndex++; + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + LogBasicTAP(true, id, description); + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + LogBasicTAP(false, id, description); + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + LogBasicTAP(true, id, description); + m_collectedData << " # skip " << reason; + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + LogBasicTAP(true, id, description); + endTAPLine(); + m_collectedData << " ---" << std::endl; + m_collectedData << " message: " << reason << std::endl; + m_collectedData << " severity: Internal" << std::endl; + m_collectedData << " ..." << std::endl; + break; + default: + Assert(false && "Bad status"); + } + } + + void LogBasicTAP(bool isOK, const std::string& id, + const std::string& description) + { + if (!isOK) { + m_collectedData << "not "; + } + m_collectedData << "ok " << m_testIndex << " [" << + id << "] " << description; + } + + void endTAPLine() + { + m_collectedData << std::endl; + } + + std::string m_filename; + std::stringstream m_collectedData; + std::ofstream m_output; + int m_testIndex; +}; + +TestResultsCollectorBase* TAPCollector::Constructor() +{ + return new TAPCollector(); +} + +void TestResultsCollectorBase::RegisterCollectorConstructor( + const std::string& name, + TestResultsCollectorBase::CollectorConstructorFunc func) +{ + Assert(m_constructorsMap.find(name) == m_constructorsMap.end()); + m_constructorsMap[name] = func; +} + +TestResultsCollectorBase* TestResultsCollectorBase::Create( + const std::string& name) +{ + ConstructorsMap::iterator found = m_constructorsMap.find(name); + if (found != m_constructorsMap.end()) { + return found->second(); + } else { + return NULL; + } +} + +std::vector TestResultsCollectorBase::GetCollectorsNames() +{ + std::vector list; + FOREACH(it, m_constructorsMap) + { + list.push_back(it->first); + } + return list; +} + +TestResultsCollectorBase::ConstructorsMap TestResultsCollectorBase:: + m_constructorsMap; + +namespace { +static int RegisterCollectorConstructors(); +static const int RegisterHelperVariable = RegisterCollectorConstructors(); +int RegisterCollectorConstructors() +{ + (void)RegisterHelperVariable; + + TestResultsCollectorBase::RegisterCollectorConstructor( + "text", + &ConsoleCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "html", + &HtmlCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "csv", + &CSVCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "tap", + &TAPCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "xml", + &XmlCollector::Constructor); + + return 0; +} +} +} +} +#undef GREEN_RESULT_OK diff --git a/modules/test/src/test_runner.cpp b/modules/test/src/test_runner.cpp new file mode 100644 index 0000000..aaac7af --- /dev/null +++ b/modules/test/src/test_runner.cpp @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test runner + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +IMPLEMENT_SINGLETON(DPL::Test::TestRunner) + +namespace { + +std::string getXMLNode(xmlNodePtr node) +{ + std::string ret; + xmlChar * value = xmlNodeGetContent(node); + ret = std::string(reinterpret_cast(value)); + xmlFree(value); + return ret; +} + +} + + +namespace DPL { +namespace Test { +namespace // anonymous +{ +std::string BaseName(std::string aPath) +{ + ScopedFree path(strdup(aPath.c_str())); + if (NULL == path.Get()) { + throw std::bad_alloc(); + } + char* baseName = basename(path.Get()); + std::string retValue = baseName; + return retValue; +} +} // namespace anonymous + +//! \brief Failed test message creator +//! +//! \param[in] aTest string for tested expression +//! \param[in] aFile source file name +//! \param[in] aLine source file line +//! \param[in] aMessage error message +TestRunner::TestFailed::TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage) +{ + std::ostringstream assertMsg; + assertMsg << "[" << BaseName(aFile) << ":" << aLine + << "] Assertion failed (" + << aTest << ") " << aMessage; + m_message = assertMsg.str(); +} + +TestRunner::TestFailed::TestFailed(const std::string &message) +{ + m_message = message; +} + +void TestRunner::RegisterTest(const char *testName, TestCase proc) +{ + m_testGroups[m_currentGroup].push_back(TestCaseStruct(testName, proc)); +} + +void TestRunner::InitGroup(const char* name) +{ + m_currentGroup = name; +} + +void TestRunner::normalizeXMLTag(std::string& str, const std::string& testcase) +{ + //Add testcase if missing + std::string::size_type pos = str.find(testcase); + if(pos != 0) + { + str = testcase + "_" + str; + } + + //dpl test runner cannot have '-' character in name so it have to be replaced + // for TCT case to make comparision works + std::replace(str.begin(), str.end(), '-', '_'); +} + +bool TestRunner::filterGroupsByXmls(const std::vector & files) +{ + DECLARE_EXCEPTION_TYPE(DPL::Exception, XMLError) + + const std::string idPath = "/test_definition/suite/set/testcase/@id"; + + bool success = true; + std::map casesMap; + + std::string testsuite; + if(!m_testGroups.empty()) + { + for(TestCaseGroupMap::const_iterator cit = m_testGroups.begin(); cit != m_testGroups.end(); ++cit) + { + if(!cit->second.empty()) + { + for(TestCaseStructList::const_iterator cj = cit->second.begin(); cj != cit->second.end(); ++cj) + { + std::string name = cj->name; + std::string::size_type st = name.find('_'); + if(st != std::string::npos) + { + name = name.substr(0, st); + testsuite = name; + break; + } + } + if(!testsuite.empty()) break; + } + } + } + + xmlInitParser(); + LIBXML_TEST_VERSION + xmlXPathInit(); + + Try + { + FOREACH(file, files) + { + xmlDocPtr doc; + xmlXPathContextPtr xpathCtx; + + doc = xmlReadFile(file->c_str(), NULL, 0); + if (doc == NULL) { + ThrowMsg(XMLError, "File Problem"); + } else { + //context + xpathCtx = xmlXPathNewContext(doc); + if (xpathCtx == NULL) { + ThrowMsg(XMLError, + "Error: unable to create new XPath context\n"); + } + xpathCtx->node = xmlDocGetRootElement(doc); + } + + std::string result; + xmlXPathObjectPtr xpathObject; + //get requested node's values + xpathObject = xmlXPathEvalExpression(BAD_CAST idPath.c_str(), xpathCtx); + if (xpathObject == NULL) + { + ThrowMsg(XMLError, "XPath evaluation failure: " << idPath); + } + xmlNodeSetPtr nodes = xpathObject->nodesetval; + unsigned size = (nodes) ? nodes->nodeNr : 0; + LogDebug("Found " << size << " nodes matching xpath"); + for(unsigned i = 0; i < size; ++i) + { + LogPedantic("Type: " << nodes->nodeTab[i]->type); + if (nodes->nodeTab[i]->type == XML_ATTRIBUTE_NODE) { + xmlNodePtr curNode = nodes->nodeTab[i]; + result = getXMLNode(curNode); + LogPedantic("Result: " << result); + normalizeXMLTag(result, testsuite); + casesMap.insert(make_pair(result, false)); + } + } + //Cleanup of XPath data + xmlXPathFreeObject(xpathObject); + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + } + } + Catch(XMLError) + { + LogError("Libxml error: " << _rethrown_exception.DumpToString()); + success = false; + } + xmlCleanupParser(); + + if(!filterByXML(casesMap)) + { + success = false; + } + + return success; +} + +bool TestRunner::filterByXML(std::map & casesMap) +{ + FOREACH(group, m_testGroups) { + TestCaseStructList newList; + FOREACH(iterator, group->second) + { + if (casesMap.find(iterator->name) != casesMap.end()) { + casesMap[iterator->name] = true; + newList.push_back(*iterator); + } + } + group->second = newList; + } + FOREACH(cs, casesMap) + { + if(cs->second == false) + { + LogError("Cannot find testcase from XML file: " << cs->first); + return false; + } + } + return true; +} + +TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase) +{ + try { + testCase.proc(); + } catch (const TestFailed &e) { + // Simple test failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::FAILED, + e.GetMessage()); + return FAILED; + } catch (const Ignored &e) { + if (m_runIgnored) { + // Simple test have to be implemented + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::IGNORED, + e.GetMessage()); + } + + return IGNORED; + } catch (const DPL::Exception &e) { + // DPL exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "DPL exception:" + e.GetMessage() + "\n" + e.DumpToString()); + + return FAILED; + } catch (const std::exception &) { + // std exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "std exception"); + + return FAILED; + } catch (...) { + // Unknown exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "unknown exception"); + + return FAILED; + } + + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::NONE); + + // Everything OK + return PASS; +} + +void TestRunner::RunTests() +{ + using namespace DPL::Colors::Text; + + Banner(); + + unsigned count = 0; + FOREACH(group, m_testGroups) { + count += group->second.size(); + } + + std::for_each(m_collectors.begin(), + m_collectors.end(), + [count] (const TestResultsCollectors::value_type & collector) + { + collector.second->Start(count); + }); + + fprintf(stderr, "%sFound %d testcases...%s\n", GREEN_BEGIN, count, GREEN_END); + fprintf(stderr, "%s%s%s\n", GREEN_BEGIN, "Running tests...", GREEN_END); + FOREACH(group, m_testGroups) { + TestCaseStructList list = group->second; + if (!list.empty()) { + std::for_each( + m_collectors.begin(), + m_collectors.end(), + [&group](const TestResultsCollectors::value_type & collector) + { + collector.second-> + CollectCurrentTestGroupName(group->first); + }); + list.sort(); + + for (TestCaseStructList::const_iterator iterator = list.begin(); + iterator != list.end(); + ++iterator) + { + TestCaseStruct test = *iterator; + if (m_startTestId == test.name) { + m_startTestId = ""; + } + + if (m_startTestId.empty()) { + RunTestCase(test); + } + if (m_terminate == true) { + // Terminate quietly without any logs + return; + } + } + } + } + + std::for_each(m_collectors.begin(), + m_collectors.end(), + [] (const TestResultsCollectors::value_type & collector) + { + collector.second->Finish(); + }); + + // Finished + fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END); +} + +void TestRunner::CollectResult( + const std::string& id, + const std::string& description, + const TestResultsCollectorBase::FailStatus::Type status, + const std::string& reason) +{ + std::for_each(m_collectors.begin(), + m_collectors.end(), + [&](const TestResultsCollectors::value_type & collector) + { + collector.second->CollectResult(id, + description, + status, + reason); + }); +} + +void TestRunner::Banner() +{ + using namespace DPL::Colors::Text; + fprintf(stderr, + "%s%s%s\n", + BOLD_GREEN_BEGIN, + "DPL tests runner", + BOLD_GREEN_END); + fprintf(stderr, + "%s%s%s%s\n\n", + GREEN_BEGIN, + "Build: ", + __TIMESTAMP__, + GREEN_END); +} + +void TestRunner::InvalidArgs(const std::string& message) +{ + using namespace DPL::Colors::Text; + fprintf(stderr, + "%s%s%s\n", + BOLD_RED_BEGIN, + message.c_str(), + BOLD_RED_END); +} + +void TestRunner::Usage() +{ + fprintf(stderr, "Usage: runner [options]\n\n"); + fprintf(stderr, "Output type:\n"); + fprintf(stderr, " --output= --output= ...\n"); + fprintf(stderr, "\n possible output types:\n"); + FOREACH(type, TestResultsCollectorBase::GetCollectorsNames()) { + fprintf(stderr, " --output=%s\n", type->c_str()); + } + fprintf(stderr, "\n example:\n"); + fprintf(stderr, + " test-binary --output=text --output=xml --file=output.xml\n\n"); + fprintf(stderr, "Other parameters:\n"); + fprintf(stderr, + " --regexp='regexp'\t Only selected tests" + " which names match regexp run\n\n"); + fprintf(stderr, " --start=\tStart from concrete test id"); + fprintf(stderr, " --group=\t Run tests only from one group\n"); + fprintf(stderr, " --runignored\t Run also ignored tests\n"); + fprintf(stderr, " --list\t Show a list of Test IDs\n"); + fprintf(stderr, " --listgroups\t Show a list of Test Group names \n"); + fprintf(stderr, " --only-from-xml=\t Run only testcases specified in XML file \n" + " XML name is taken from attribute id=\"part1_part2\" as whole.\n" + " If part1 is not found (no _) then it is implicitily " + "set according to suite part1 from binary tests\n"); + fprintf( + stderr, + " --listingroup=\t Show a list of Test IDS in one group\n"); + fprintf(stderr, " --allowchildlogs\t Allow to print logs from child process on screen.\n"); + fprintf(stderr, " When active child process will be able to print logs on stdout and stderr.\n"); + fprintf(stderr, " Both descriptors will be closed after test.\n"); + fprintf(stderr, " --help\t This help\n\n"); + std::for_each(m_collectors.begin(), + m_collectors.end(), + [] (const TestResultsCollectors::value_type & collector) + { + fprintf(stderr, + "Output %s has specific args:\n", + collector.first.c_str()); + fprintf(stderr, + "%s\n", + collector.second-> + CollectorSpecificHelp().c_str()); + }); + fprintf(stderr, "For bug reporting, please write to:\n"); + fprintf(stderr, "\n"); +} + +int TestRunner::ExecTestRunner(int argc, char *argv[]) +{ + std::vector args; + for (int i = 0; i < argc; ++i) { + args.push_back(argv[i]); + } + return ExecTestRunner(args); +} + +void TestRunner::MarkAssertion() +{ + ++m_totalAssertions; +} + +int TestRunner::ExecTestRunner(const ArgsList& value) +{ + m_runIgnored = false; + ArgsList args = value; + // Parse command line + if (args.size() == 1) { + InvalidArgs(); + Usage(); + return -1; + } + + args.erase(args.begin()); + + bool showHelp = false; + bool justList = false; + std::vector xmlFiles; + + TestResultsCollectorBasePtr currentCollector; + + // Parse each argument + FOREACH(it, args) + { + std::string arg = *it; + const std::string regexp = "--regexp="; + const std::string output = "--output="; + const std::string groupId = "--group="; + const std::string runIgnored = "--runignored"; + const std::string listCmd = "--list"; + const std::string startCmd = "--start="; + const std::string listGroupsCmd = "--listgroups"; + const std::string listInGroup = "--listingroup="; + const std::string allowChildLogs = "--allowchildlogs"; + const std::string onlyFromXML = "--only-from-xml="; + + if (currentCollector) { + if (currentCollector->ParseCollectorSpecificArg(arg)) { + continue; + } + } + + if (arg.find(startCmd) == 0) { + arg.erase(0, startCmd.length()); + FOREACH(group, m_testGroups) { + FOREACH(tc, group->second) { + if (tc->name == arg) { + m_startTestId = arg; + break; + } + } + if (!m_startTestId.empty()) { + break; + } + } + if (!m_startTestId.empty()) { + continue; + } + InvalidArgs(); + fprintf(stderr, "Start test id has not been found\n"); + Usage(); + return 0; + } else if (arg.find(groupId) == 0) { + arg.erase(0, groupId.length()); + TestCaseGroupMap::iterator found = m_testGroups.find(arg); + if (found != m_testGroups.end()) { + std::string name = found->first; + TestCaseStructList newList = found->second; + m_testGroups.clear(); + m_testGroups[name] = newList; + } else { + fprintf(stderr, "Group %s not found\n", arg.c_str()); + InvalidArgs(); + Usage(); + return -1; + } + } else if (arg == runIgnored) { + m_runIgnored = true; + } else if (arg == listCmd) { + justList = true; + } else if (arg == listGroupsCmd) { + FOREACH(group, m_testGroups) { + printf("GR:%s\n", group->first.c_str()); + } + return 0; + } else if (arg.find(listInGroup) == 0) { + arg.erase(0, listInGroup.length()); + FOREACH(test, m_testGroups[arg]) { + printf("ID:%s\n", test->name.c_str()); + } + return 0; + } else if (arg.find(allowChildLogs) == 0) { + arg.erase(0, allowChildLogs.length()); + m_allowChildLogs = true; + } else if (arg == "--help") { + showHelp = true; + } else if (arg.find(output) == 0) { + arg.erase(0, output.length()); + if (m_collectors.find(arg) != m_collectors.end()) { + InvalidArgs( + "Multiple outputs of the same type are not supported!"); + Usage(); + return -1; + } + currentCollector.reset(TestResultsCollectorBase::Create(arg)); + if (!currentCollector) { + InvalidArgs("Unsupported output type!"); + Usage(); + return -1; + } + m_collectors[arg] = currentCollector; + } else if (arg.find(regexp) == 0) { + arg.erase(0, regexp.length()); + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') { + arg.erase(0); + arg.erase(arg.length() - 1); + } + + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + pcrecpp::RE re(arg.c_str()); + FOREACH(group, m_testGroups) { + TestCaseStructList newList; + FOREACH(iterator, group->second) + { + if (re.PartialMatch(iterator->name)) { + newList.push_back(*iterator); + } + } + group->second = newList; + } + } else if(arg.find(onlyFromXML) == 0) { + arg.erase(0, onlyFromXML.length()); + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') { + arg.erase(0); + arg.erase(arg.length() - 1); + } + + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + xmlFiles.push_back(arg); + } else { + InvalidArgs(); + Usage(); + return -1; + } + } + + if(!xmlFiles.empty()) + { + if(!filterGroupsByXmls(xmlFiles)) + { + fprintf(stderr, "XML file is not correct\n"); + return 0; + } + } + + if(justList) + { + FOREACH(group, m_testGroups) { + FOREACH(test, group->second) { + printf("ID:%s:%s\n", group->first.c_str(), test->name.c_str()); + } + } + return 0; + } + + currentCollector.reset(); + + // Show help + if (showHelp) { + Usage(); + return 0; + } + + if (m_collectors.empty()) { + TestResultsCollectorBasePtr collector( + TestResultsCollectorBase::Create("text")); + m_collectors["text"] = collector; + } + + for (auto it = m_collectors.begin(); it != m_collectors.end(); ++it) { + if (!it->second->Configure()) { + fprintf(stderr, "Could not configure selected output"); + return 0; + } + } + + // Run tests + RunTests(); + + return 0; +} + +bool TestRunner::getRunIgnored() const +{ + return m_runIgnored; +} + +void TestRunner::Terminate() +{ + m_terminate = true; +} + +bool TestRunner::GetAllowChildLogs() +{ + return m_allowChildLogs; +} + +} +} // namespace DPL diff --git a/modules/test/src/test_runner_child.cpp b/modules/test/src/test_runner_child.cpp new file mode 100644 index 0000000..8e793e8 --- /dev/null +++ b/modules/test/src/test_runner_child.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_child.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test runner + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +const int CHILD_TEST_FAIL = 0; +const int CHILD_TEST_PASS = 1; +const int CHILD_TEST_IGNORED = 2; + +int closeOutput() { + int devnull; + int retcode = -1; + if (-1 == (devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY)))) + return -1; + + // replace stdout with /dev/null + if (-1 == TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO))) + goto end; + + // replace stderr with /dev/null + if (-1 == TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO))) + goto end; + + retcode = 0; + +end: + close(devnull); + return retcode; +} + +} // namespace anonymous + +namespace DPL { +namespace Test { + +PipeWrapper::PipeWrapper() +{ + if (-1 == pipe(m_pipefd)) { + m_pipefd[0] = PIPE_CLOSED; + m_pipefd[1] = PIPE_CLOSED; + } +} + +PipeWrapper::~PipeWrapper() +{ + closeHelp(0); + closeHelp(1); +} + +bool PipeWrapper::isReady() +{ + return m_pipefd[0] != PIPE_CLOSED || m_pipefd[1] != PIPE_CLOSED; +} + +void PipeWrapper::setUsage(Usage usage) +{ + if (usage == READONLY) { + closeHelp(1); + } + if (usage == WRITEONLY) { + closeHelp(0); + } +} + +PipeWrapper::Status PipeWrapper::send(int code, std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + std::ostringstream output; + output << toBinaryString(code); + output << toBinaryString(static_cast(message.size())); + output << message; + + std::string binary = output.str(); + int size = binary.size(); + + if ((writeHelp(&size, + sizeof(int)) == ERROR) || + (writeHelp(binary.c_str(), size) == ERROR)) + { + return ERROR; + } + return SUCCESS; +} + +PipeWrapper::Status PipeWrapper::receive(int &code, std::string &data, time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } + + int size; + Status ret; + + if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS) { + return ret; + } + + std::vector buffer; + buffer.resize(size); + + if ((ret = readHelp(&buffer[0], size, deadline)) != SUCCESS) { + return ret; + } + + try { + DPL::BinaryQueue queue; + queue.AppendCopy(&buffer[0], size); + + queue.FlattenConsume(&code, sizeof(int)); + queue.FlattenConsume(&size, sizeof(int)); + + buffer.resize(size); + + queue.FlattenConsume(&buffer[0], size); + data.assign(buffer.begin(), buffer.end()); + } catch (DPL::BinaryQueue::Exception::Base &e) { + return ERROR; + } + return SUCCESS; +} + +void PipeWrapper::closeAll() +{ + closeHelp(0); + closeHelp(1); +} + +std::string PipeWrapper::toBinaryString(int data) +{ + char buffer[sizeof(int)]; + memcpy(buffer, &data, sizeof(int)); + return std::string(buffer, buffer + sizeof(int)); +} + +void PipeWrapper::closeHelp(int desc) +{ + if (m_pipefd[desc] != PIPE_CLOSED) { + TEMP_FAILURE_RETRY(close(m_pipefd[desc])); + m_pipefd[desc] = PIPE_CLOSED; + } +} + +PipeWrapper::Status PipeWrapper::writeHelp(const void *buffer, int size) +{ + int ready = 0; + const char *p = static_cast(buffer); + while (ready != size) { + int ret = write(m_pipefd[1], &p[ready], size - ready); + + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1) { + closeHelp(1); + return ERROR; + } + + ready += ret; + } + return SUCCESS; +} + +PipeWrapper::Status PipeWrapper::readHelp(void *buf, int size, time_t deadline) +{ + int ready = 0; + char *buffer = static_cast(buf); + while (ready != size) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; + + int pollReturn = poll(&fds, 1, wait * 1000); + + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } + + if (pollReturn < -1) { + return ERROR; + } + + int ret = read(m_pipefd[0], &buffer[ready], size - ready); + + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1 || ret == 0) { + closeHelp(0); + return ERROR; + } + + ready += ret; + } + return SUCCESS; +} + +void RunChildProc(TestRunner::TestCase procChild) +{ + PipeWrapper pipe; + if (!pipe.isReady()) { + throw TestRunner::TestFailed("Pipe creation failed"); + } + + pid_t pid = fork(); + + if (pid == -1) { + throw TestRunner::TestFailed("Child creation failed"); + } + + if (pid != 0) { + // parent code + pipe.setUsage(PipeWrapper::READONLY); + + int code; + std::string message; + + int pipeReturn = pipe.receive(code, message, time(0) + 10); + + if (pipeReturn != PipeWrapper::SUCCESS) { // Timeout or reading error + pipe.closeAll(); + kill(pid, SIGKILL); + } + + int status; + waitpid(pid, &status, 0); + + if (pipeReturn == PipeWrapper::TIMEOUT) { + throw TestRunner::TestFailed("Timeout"); + } + + if (pipeReturn == PipeWrapper::ERROR) { + throw TestRunner::TestFailed("Reading pipe error"); + } + + if (code == CHILD_TEST_FAIL) { + throw TestRunner::TestFailed(message); + } else if (code == CHILD_TEST_IGNORED) { + throw TestRunner::Ignored(message); + } + } else { + // child code + + // End Runner after current test + TestRunnerSingleton::Instance().Terminate(); + + int code = CHILD_TEST_PASS; + std::string msg; + + bool allowLogs = TestRunnerSingleton::Instance().GetAllowChildLogs(); + + close(STDIN_FILENO); + if (!allowLogs) { + closeOutput(); // if fails nothing we can do + } + + pipe.setUsage(PipeWrapper::WRITEONLY); + + try { + procChild(); + } catch (const DPL::Test::TestRunner::TestFailed &e) { + msg = e.GetMessage(); + code = CHILD_TEST_FAIL; + } catch (const DPL::Test::TestRunner::Ignored &e) { + msg = e.GetMessage(); + code = CHILD_TEST_IGNORED; + } catch (...) { // catch all exception generated by "user" code + msg = "unhandled exeception"; + code = CHILD_TEST_FAIL; + } + + if (allowLogs) { + closeOutput(); + } + + pipe.send(code, msg); + } +} +} // namespace Test +} // namespace DPL diff --git a/modules/test/src/test_runner_multiprocess.cpp b/modules/test/src/test_runner_multiprocess.cpp new file mode 100644 index 0000000..691966f --- /dev/null +++ b/modules/test/src/test_runner_multiprocess.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.cpp + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of multiprocess test runner + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +const int MULTI_TEST_ERROR = -1; +const int MULTI_TEST_PASS = 0; +const int MULTI_TEST_FAILED = 1; +const int MULTI_TEST_IGNORED = 2; +const int MULTI_TEST_INTERNAL = 3; + +} + +namespace DPL { +namespace Test { + +SimplePipeWrapper::SimplePipeWrapper() +: PipeWrapper() +{ + +} + +SimplePipeWrapper::~SimplePipeWrapper() +{ + +} + +PipeWrapper::Status SimplePipeWrapper::send(std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + if (message.size() > PIPE_BUF-1) { + return ERROR; + } + + char buffer[PIPE_BUF] = { 0 }; + + + for(unsigned int i = 0; i < message.size(); ++i) { + buffer[i] = message[i]; + } + + return writeHelp(buffer, PIPE_BUF); +} + +PipeWrapper::Status SimplePipeWrapper::receive(std::string &data, bool &empty, time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } + + empty = false; + + data.resize(PIPE_BUF); + + char buffer[PIPE_BUF] = { 0 }; + + int ready = 0; + while (ready != PIPE_BUF) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; + + int pollReturn = poll(&fds, 1, wait * 1000); + + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } + + if (pollReturn < -1) { + return ERROR; + } + int ret = read(m_pipefd[0], &buffer[ready], PIPE_BUF - ready); + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1) { + closeHelp(0); + return ERROR; + } + if (ret == 0) { + empty = true; + break; + } + + ready += ret; + } + + + for(unsigned int i = 0; i < PIPE_BUF; ++i){ + if(buffer[i] == 0) { + data.resize(i); + return SUCCESS; + } + data[i] = buffer[i]; + } + + return ERROR; +} + +void RunMultiProc(TestRunner::TestCase procMulti) +{ + SimplePipeWrapper pipe; + int code = MULTI_TEST_PASS; + std::string msg = ""; + int pipeReturn; + + int waitStatus; + + pid_t top_pid = getpid(); + + if (!pipe.isReady()) { + throw TestRunner::TestFailed("Pipe creation failed"); + } + // pipe + + try { + procMulti(); + } catch (const TestRunner::TestFailed &e) { + code = MULTI_TEST_FAILED; + msg = e.GetMessage(); + } catch (const TestRunner::Ignored &e) { + code = MULTI_TEST_IGNORED; + msg = e.GetMessage(); + } catch (const DPL::Exception &e) { + code = MULTI_TEST_INTERNAL; + msg = "DPL exception:" + e.GetMessage(); + } catch (const std::exception &) { + code = MULTI_TEST_INTERNAL; + msg = "std exception"; + } catch (...) { + // Unknown exception failure + code = MULTI_TEST_INTERNAL; + msg = "unknown exception"; + } + + while (true) { + pid_t child_pid = wait(&waitStatus); + if (child_pid == -1) { + if (errno == ECHILD) { + if (top_pid == getpid()) { + std::string recMsg=""; + + pipe.setUsage(PipeWrapper::READONLY); + + bool empty=false; + while(true) { + pipeReturn = pipe.receive(recMsg, empty, time(0) + 10); + + if (empty) { + break; + } + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + throw TestRunner::TestFailed("Reading pipe error"); + } else if (pipeReturn == PipeWrapper::TIMEOUT) { + pipe.closeAll(); + throw TestRunner::TestFailed("Timeout error"); + } + msg = msg + "\n" + recMsg; + } + pipe.closeAll(); + + switch(code) { + case MULTI_TEST_PASS: + return; + case MULTI_TEST_FAILED: + throw TestRunner::TestFailed(msg); + case MULTI_TEST_IGNORED: + throw TestRunner::Ignored(msg); + case MULTI_TEST_INTERNAL: + throw TestRunner::TestFailed(msg); + default: + throw TestRunner::TestFailed(msg); + } + } else { + pipe.setUsage(PipeWrapper::WRITEONLY); + + pipeReturn = pipe.send(msg); + + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + code = MULTI_TEST_ERROR; + } + + exit(code); + } + } + } else if (WIFEXITED(waitStatus)) { + if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_FAILED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_IGNORED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_IGNORED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_INTERNAL) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_FAILED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) != MULTI_TEST_PASS) { + code = MULTI_TEST_ERROR; + msg = "PROCESS BAD CODE RETURN"; + } + } + } +} +} // namespace Test +} // namespace DPL diff --git a/modules/test/src/value_separated_policies.cpp b/modules/test/src/value_separated_policies.cpp new file mode 100644 index 0000000..0ecf599 --- /dev/null +++ b/modules/test/src/value_separated_policies.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_policies.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief ... + */ + +#include +#include +#include + +namespace DPL { + +std::string CSVTokenizerPolicy::GetSeperators() +{ + return ","; +} + +bool CSVTokenizerPolicy::SkipEmpty() +{ + return false; +} + +void CSVTokenizerPolicy::PrepareValue(std::string &) +{ +} + +bool CSVTokenizerPolicy::TryAgainAtEnd(int) +{ + return false; +} + +bool CSVParserPolicy::SkipLine(const std::vector & ) +{ + return false; +} + +bool CSVParserPolicy::Validate(std::shared_ptr > > & result) +{ + int num = -1; + FOREACH(r, *result) + { + int size = r->size(); + if(num != -1 && num != size) + { + LogError("Columns not matches"); + return false; + } + num = size; + } + return true; +} + +} diff --git a/modules/test/src/value_separated_tokens.cpp b/modules/test/src/value_separated_tokens.cpp new file mode 100644 index 0000000..4b53e27 --- /dev/null +++ b/modules/test/src/value_separated_tokens.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file value_separated_tokens.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief ... + */ + +#include + +namespace DPL { + +VSToken::VSToken(const std::string & c) : m_newline(false), m_cell(c) +{ +} + +VSToken::VSToken() : m_newline(true) +{ +} + +const std::string & VSToken::cell() const +{ + return m_cell; +} + +bool VSToken::isNewLine() +{ + return m_newline; +} + +} diff --git a/modules/utils/config.cmake b/modules/utils/config.cmake new file mode 100644 index 0000000..828ca6c --- /dev/null +++ b/modules/utils/config.cmake @@ -0,0 +1,49 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Soyoung Kim(sy037.kim@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_UTILS_SOURCES + ${PROJECT_SOURCE_DIR}/modules/utils/src/bash_utils.cpp + ${PROJECT_SOURCE_DIR}/modules/utils/src/folder_size.cpp + ${PROJECT_SOURCE_DIR}/modules/utils/src/mime_type_utils.cpp + ${PROJECT_SOURCE_DIR}/modules/utils/src/warp_iri.cpp + ${PROJECT_SOURCE_DIR}/modules/utils/src/widget_version.cpp + ${PROJECT_SOURCE_DIR}/modules/utils/src/wrt_global_settings.cpp + ${PROJECT_SOURCE_DIR}/modules/utils/src/wrt_utility.cpp + ${PROJECT_SOURCE_DIR}/modules/utils/src/path.cpp + PARENT_SCOPE +) + +SET(DPL_UTILS_HEADERS + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/bash_utils.h + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/folder_size.h + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/mime_type_utils.h + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/warp_iri.h + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/widget_version.h + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/wrt_global_settings.h + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/wrt_utility.h + ${PROJECT_SOURCE_DIR}/modules/utils/include/dpl/utils/path.h + PARENT_SCOPE +) + +SET(DPL_UTILS_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/modules/utils/include + PARENT_SCOPE +) diff --git a/modules/utils/include/dpl/utils/bash_utils.h b/modules/utils/include/dpl/utils/bash_utils.h new file mode 100644 index 0000000..33a5f9d --- /dev/null +++ b/modules/utils/include/dpl/utils/bash_utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file bash_utils.h + * @author Iwanek Tomasz + * @version 1.0 + */ + +#ifndef BASH_UTILS_H +#define BASH_UTILS_H + +#include + +namespace BashUtils { +/** + * Escapes bash special characters in string and return string in double quotes + * @param source string to be escaped + * @return escaped string + */ +std::string escape_arg(const std::string & source); +} + +#endif // BASH_UTILS_H diff --git a/modules/utils/include/dpl/utils/folder_size.h b/modules/utils/include/dpl/utils/folder_size.h new file mode 100644 index 0000000..71a77bd --- /dev/null +++ b/modules/utils/include/dpl/utils/folder_size.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * + * @file folder_size.h + * @author Jaroslaw Osmanski (j.osmanski@samsung.com) + * @version 1.0 + * @brief Declaration for function calculating directory size + */ + +#ifndef SRC_COMMON_FOLDER_SIZE_H_ +#define SRC_COMMON_FOLDER_SIZE_H_ + +#include + +#include + +namespace Utils { +size_t getFolderSize(const std::string& path); + +DPL::String fromFileSizeString(size_t fileSize); +} + +#endif /* SRC_COMMON_FOLDER_SIZE_H_ */ diff --git a/modules/utils/include/dpl/utils/mime_type_utils.h b/modules/utils/include/dpl/utils/mime_type_utils.h new file mode 100644 index 0000000..1d93385 --- /dev/null +++ b/modules/utils/include/dpl/utils/mime_type_utils.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MIME_TYPE_UTILS_H +#define MIME_TYPE_UTILS_H + +#include +#include + +class MimeTypeUtils +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InvalidFileName) + }; + + private: + //TODO use hash_map if possible + static const std::set& getMimeTypesSupportedForIcon(); + static const std::set& getMimeTypesSupportedForStartFile(); + + typedef std::map FileIdentificationMap; + + static DPL::String getFileNameFromPath(const DPL::String& path); + static const FileIdentificationMap& getFileIdentificationMap(); + static DPL::String stripMimeParameters(const DPL::String& mimeType); + + public: + typedef std::map MimeAttributes; + static bool isValidIcon(const DPL::String& path); + static bool isValidStartFile(const DPL::String& path, + const DPL::OptionalString& providedMimeType); + static bool isMimeTypeSupportedForStartFile(const DPL::String& mimeType); + static bool isMimeTypeSupportedForIcon(const DPL::String& mimeType); + static MimeAttributes getMimeAttributes(const DPL::String& mimeType); + ///implements 9.1.10. (Rule for Identifying the Media Type of a File) + ///from W3C packaging specification + static DPL::String identifyFileMimeType(const DPL::String& path); +}; + +#endif /* MIME_TYPE_UTILS_H */ + diff --git a/modules/utils/include/dpl/utils/path.h b/modules/utils/include/dpl/utils/path.h new file mode 100644 index 0000000..83290d0 --- /dev/null +++ b/modules/utils/include/dpl/utils/path.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file path.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + */ +#ifndef PATH_H +#define PATH_H + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace DPL { +namespace Utils { +class Path; +} +} + +std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path); + +namespace DPL { +namespace Utils { +/** + * @brief The Path class path abstraction + * + * Class for expressing paths not limited not existing ones. + * It's possible to check if path exists, remove it or iterate it if it's directory + * + * Created Path object allways contains absolute path, never relative path. + * Simplifies common usage cases: + * - path construction (with /= and / operators) + * - directory iterator (begin(), end(), iterator construction) + * - receiving filenames and directory names of given paths + * - checking what is pointed by path (Exists(), IsFile(), IsDir()) + * + * Check tests for details of usage. + */ +class Path +{ +public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, BaseException) + DECLARE_EXCEPTION_TYPE(BaseException, AlreadyExists) //path already exists + DECLARE_EXCEPTION_TYPE(BaseException, NotPrefix) //given path is not prefix of this path + DECLARE_EXCEPTION_TYPE(BaseException, NotExists) //file not exists + DECLARE_EXCEPTION_TYPE(BaseException, NotDirectory) //directory nto exists + DECLARE_EXCEPTION_TYPE(BaseException, OperationFailed) //operation failed due to system error(permission etc..) + DECLARE_EXCEPTION_TYPE(BaseException, EmptyPath) //object cannot be constructed with empty path + DECLARE_EXCEPTION_TYPE(BaseException, InternalError) //internal error / wrong path usage + DECLARE_EXCEPTION_TYPE(BaseException, CannotCopy) //cannot make copy + DECLARE_EXCEPTION_TYPE(BaseException, RootDirectoryError) //operation cannot be done with root diretory + + class Iterator : public std::iterator + { + public: + Iterator(); + Iterator(const char *); + Iterator& operator++(); + Iterator operator++(int); + bool operator==(const Iterator& rhs) const; + bool operator!=(const Iterator& rhs) const; + const Path & operator*(); + const Path * operator->(); + private: + void ReadNext(); + + std::shared_ptr m_dir; + std::shared_ptr m_path; + std::shared_ptr m_root; + }; + + explicit Path(const DPL::String & str); + explicit Path(const std::string & str); + explicit Path(const char * str); + Path(); + + /** + * @brief DirectoryPath shell's dirname equivalent as path + * @return directory path + */ + Path DirectoryPath() const; + /** + * @brief DirectoryName shell's dirname equivalent + * @return directory name of given path + */ + std::string DirectoryName() const; + /** + * @brief Basename shell's basename equivalent + * @return base name of given path + */ + std::string Filename() const; + /** + * @brief Fullpath fullpath based on current working diretory + * @return full path + */ + std::string Fullpath() const; + /** + * @brief Extension + * @return extension + */ + std::string Extension() const; + + bool Exists() const; + bool IsDir() const; + bool IsFile() const; + bool ExistsAndIsFile() const; + bool ExistsAndIsDir() const; + bool IsSymlink() const; + std::size_t Size() const; + /** + * @brief isSubPath Returns relative path to given base + * @param prefix base path + * @return reltive path + * + * @throws If prefix does not match to this path object + */ + bool isSubPath(const Path & other) const; + bool hasExtension(const std::string& extension) const; + + bool operator==(const Path & other) const; + bool operator!=(const Path & other) const; + + //appending to path + Path operator/(const DPL::String& part) const; + Path operator/(const std::string& part) const; + Path operator/(const char * part) const; + + Path & operator/=(const DPL::String& part); + Path & operator/=(const std::string& part); + Path & operator/=(const char * part); + + //foreach + Iterator begin() const; + Iterator end() const; + + //root error - throws error on root directory + void RootGuard() const; + +private: + + void Append(const std::string& part); + void Construct(const std::string & src); + + std::vector m_parts; + + friend std::ostream & ::operator<<(std::ostream & str, const DPL::Utils::Path & path); +}; + +/** + * @brief MkDir creates 'current path' as directory + * @param path path + * @param mode mode + */ +void MakeDir(const Path & path, mode_t mode = 0755); + +/** + * @brief MkFile creates 'current path' as empty file + * @param path path + */ +void MakeEmptyFile(const Path & path); + +/** + * @brief Remove removes 'current path' + * @param path path to remove + */ +void Remove(const Path & path); + +/** + * @brief TryRemove tries to remvoe path + * @param path returns status of removal + */ +bool TryRemove(const Path & path); + +/** + * @brief Rename renames(moves) current path + * + * If you uses this method string to path is internally change + * and this object will store new path not only anymore + * @param from source path + * @param to target path + */ +void Rename(const Path & from, const Path & to); + +/** + * @brief Exists Checks if given path exists + * @param path path + * @return true if path exists + */ +bool Exists(const Path & path); + +/** + * @brief Copy file + * + * @param from source path + * @param to target path + */ +void CopyFile(const Path & from, const Path & to); + +/** + * @brief Copy directory recursively + * + * @param from source directory path + * @param to target directory path + */ +void CopyDir(const Path & from, const Path & to); + +Path CreateTempPath(const Path & path); +} + +} + +//TODO: uncomment when user defiend literals are supported +///Path operator"" p(const char * str); + +#endif // PATH_H diff --git a/modules/utils/include/dpl/utils/warp_iri.h b/modules/utils/include/dpl/utils/warp_iri.h new file mode 100644 index 0000000..71773cb --- /dev/null +++ b/modules/utils/include/dpl/utils/warp_iri.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _WARPIRI_H_ +#define _WARPIRI_H_ + +#include + +#include +#include + +class WarpIRI +{ + static const unsigned int UNKNOWN_PORT = 0; + + public: + WarpIRI(); + + void set(const char *iri, + bool domain); + void set(const DPL::String &iristring, + bool domain); + + /* It also checks port and schema */ + bool isSubDomain(const WarpIRI &second) const; + bool isAccessDefinition() const; + bool getSubDomain() const; + + static bool isIRISchemaIgnored(const char *iri); + + bool operator ==(const WarpIRI &other) const + { + return m_domain == other.m_domain && + m_host == other.m_host && + m_schema == other.m_schema && + m_port == other.m_port && + m_isAccessDefinition == other.m_isAccessDefinition && + m_isIRIValid == other.m_isIRIValid; + } + + private: + unsigned int getPort(const DPL::String &schema) const; + + bool m_domain; + std::vector m_host; + DPL::String m_schema; + unsigned int m_port; + bool m_isAccessDefinition; + bool m_isIRIValid; +}; + +#endif // _WarpIRI_H_ diff --git a/modules/utils/include/dpl/utils/widget_version.h b/modules/utils/include/dpl/utils/widget_version.h new file mode 100644 index 0000000..de3d3aa --- /dev/null +++ b/modules/utils/include/dpl/utils/widget_version.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file widget_version.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for widget version + */ +#ifndef WIDGET_VERSION_H +#define WIDGET_VERSION_H + +#include +#include +#include + +/* + * Note: This class also support non-WAC compliant version numbers + * + * WAC Waikiki Beta Release Core Specification: Widget Runtime + * 10 Dec 2010 + * + * WL-3370 The WRT MUST process widget packages as an update when received under + * the following conditions: + * + * - the Widget Id matches the Widget Id of an installed widget + * - the Widget version number is greater (as a compared string) than that of + * the installed widget, or no version + * information was provided for the installed widget + * + * To ensure that a string comparison of widget versions can reliably determine + * which version is an updated widget, + * WAC will mandate a specific version string format for WAC widgets. All + * widgets coming through the WAC channel + * will be required to have version strings in this format. Side-loaded widgets + * may have any format and, in this + * case, there is no requirement that the WRT support version detection for + * update of these widgets. + * + * The widget version format is the rec-version-tag grammar as described in + * [Widget Packaging]: + * + * rec-version-tag = 1*DIGIT "." 1*DIGIT [ "." 1*DIGIT] *[ 1*ALPHA / SP / + * 1*DIGIT ] + * + * Examples of rec-version-tag: + * + * 1.0 + * 1.10.1 beta1 + * 1.02.12 RC1 + * + * WL-3371 The WRT MUST use the following widget version comparison algorithm to + * compare WAC widget version strings: + * + * - prepare the version strings for comparison: + * - all leading zeros are discarded + * - the optional *[ 1*ALPHA / SP / 1*DIGIT ] part, if present, is discarded + * - the resulting numbers are then in the format major.minor[.micro] + * - Version A = Amajor.Aminor[.Amicro] is equal to Version B = + * Bmajor.Bminor[.Bmicro] if and only if: + * - Amajor Bmajor + * - Aminor Bminor + * - both Amicro and Bmicro are present and Amicro == Bmicro; or both Amicro + * and Bmicro are absent. + * - Version A = Amajor.Aminor[.Amicro] is greater than Version B = + * Bmajor.Bminor[.Bmicro] if and only if: + * - Amajor > Bmajor; or + * - Amajor Bmajor && Aminor > Bminor; or + * - Amajor Bmajor && Aminor == Bminor && both Amicro and Bmicro are present + * and Amicro > Bmicro; or Bmicro is absent. + */ +class WidgetVersion +{ + private: + bool m_isWac; + DPL::String m_raw; + + DPL::String m_major; + DPL::String m_minor; + DPL::Optional m_micro; + DPL::Optional m_optional; + + void WacCertify(const DPL::String &major, + const DPL::String &minor, + const DPL::Optional µ, + const DPL::Optional &optional); + + public: + explicit WidgetVersion(const DPL::String &str = DPL::String()); + WidgetVersion(const DPL::String &major, + const DPL::String &minor, + const DPL::Optional µ, + const DPL::Optional &optional); + + bool IsWac() const; + const DPL::String &Raw() const; + + const DPL::String &Major() const; + const DPL::String &Minor() const; + const DPL::Optional &Micro() const; + const DPL::Optional &Optional() const; +}; + +bool operator<(const WidgetVersion &left, + const WidgetVersion &right); +bool operator<=(const WidgetVersion &left, + const WidgetVersion &right); +bool operator>(const WidgetVersion &left, + const WidgetVersion &right); +bool operator>=(const WidgetVersion &left, + const WidgetVersion &right); +bool operator==(const WidgetVersion &left, + const WidgetVersion &right); +bool operator!=(const WidgetVersion &left, + const WidgetVersion &right); +std::ostream & operator<<(std::ostream& stream, + const WidgetVersion& version); + +#endif // WIDGET_VERSION_H diff --git a/modules/utils/include/dpl/utils/wrt_global_settings.h b/modules/utils/include/dpl/utils/wrt_global_settings.h new file mode 100644 index 0000000..14407ae --- /dev/null +++ b/modules/utils/include/dpl/utils/wrt_global_settings.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file wrt_global_settings.h + * @version 0.6 + * @author Pawel Sikorski(p.sikorski@samsung.com) + * @brief Header file for global predefined wrt setting + */ + +#ifndef WRT_COMMON_GLOBAL_SETTINGS_H_ +#define WRT_COMMON_GLOBAL_SETTINGS_H_ + +namespace GlobalSettings { +// Methods for getting test mode environment flag +bool TestModeEnabled(); +bool PopupsTestModeEnabled(); +bool WarpTestModeEnabled(); +bool RoamingTestModeEnabled(); +bool OCSPTestModeEnabled(); +bool CrlTestModeEnabled(); +bool MakeScreenTestModeEnabled(); +bool IsEmulator(); +} + +#endif /* WRT_COMMON_GLOBAL_SETTINGS_H_ */ diff --git a/modules/utils/include/dpl/utils/wrt_utility.h b/modules/utils/include/dpl/utils/wrt_utility.h new file mode 100644 index 0000000..165e167 --- /dev/null +++ b/modules/utils/include/dpl/utils/wrt_utility.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file wrt_utility.h + * @version 0.8 + * @author Janusz Majnert + * @brief Common utility functions + */ + +#ifndef _WRT_UTILITY_H_ +#define _WRT_UTILITY_H_ + +#include + +/** + * Joins two paths into one + * + * @param[out] joined String for storing joined paths + * @param[in] parent String containing the first part of path + * @param[in] child String containing the second part of the path + * + * Data stored in joined before the function call will be replaced with joined + * paths. + */ +void WrtUtilJoinPaths(std::string &joined, + const std::string &parent, + const std::string &child); + +/** + * Creates directories specified by path + * + * @param[in] path Path to create + * @param[in] mode access flags, default to 0755 + * @return true on success, false on failure + * + * Function creates directory specified by path argument and all directories + * leading up to it, if they don't exist. Note that if yout wish to create + * several nested directories, you must make sure that the mode flag allows you + * to write and search the direcotries you create. + */ +bool WrtUtilMakeDir(const std::string &newpath, mode_t mode = 0755); + +/** + * This function removes the directory or file pointed to by path + * + * @param[in] path Path to the file/directory to be deleted + * + * @return true on success, false otherwise + */ +bool WrtUtilRemove(const std::string &path); + +/** + * Checks if path exists and is a regular file + * + * @param[in] path the string representing path to check + * + * @return true if regular file is accessible under path, false otherwise + */ +bool WrtUtilFileExists(const std::string &path); + +/** + * Checks if path exists and is a directory + * + * @param[in] path the string representing path to check + * + * @return true if directory is accessible under path, false otherwise + */ +bool WrtUtilDirExists(const std::string &path); + +#endif //_WRT_UTILITY_H_ + diff --git a/modules/utils/src/bash_utils.cpp b/modules/utils/src/bash_utils.cpp new file mode 100644 index 0000000..1222eda --- /dev/null +++ b/modules/utils/src/bash_utils.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file bash_utils.cpp + * @author Iwanek Tomasz + * @version 1.0 + */ +#include +#include +#include + +#include + +namespace BashUtils { +std::string escape_arg(const std::string & source) +{ + static const std::string special("!$`\\\""); + std::string ret = "\""; + for (std::string::const_iterator iter = source.begin(); + iter != source.end(); + ++iter) + { + if (special.find(*iter) != std::string::npos) { + ret += std::string("\\") + *iter; + } else { + ret += *iter; + } + } + return ret + "\""; +} +} diff --git a/modules/utils/src/folder_size.cpp b/modules/utils/src/folder_size.cpp new file mode 100644 index 0000000..522216a --- /dev/null +++ b/modules/utils/src/folder_size.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * + * @file folder_size.cpp + * @author Jaroslaw Osmanski (j.osmanski@samsung.com) + * @version 1.0 + * @brief Implementation for function calculating directory size + */ +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace Utils { +size_t getFolderSize(const std::string& path) +{ + size_t size = 0; + FTS *fts; + FTSENT *ftsent; + char * const paths[] = { const_cast(path.c_str()), NULL }; + + if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) { + //ERROR + int error = errno; + LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: " + << strerror(error)); + return 0; + } + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_DP: + case FTS_DC: + //directory in postorder and directory causing a loop + break; + case FTS_F: + case FTS_D: + case FTS_NSOK: + case FTS_SL: + case FTS_SLNONE: + case FTS_DEFAULT: + //regular files and other objects that can be counted + size += ftsent->fts_statp->st_size; + break; + case FTS_NS: + case FTS_DOT: + case FTS_DNR: + case FTS_ERR: + default: + LogWarning(__PRETTY_FUNCTION__ + << ": traversal failed on file: " + << ftsent->fts_path + << " with error: " + << strerror(ftsent->fts_errno)); + return 0; + } + } + + if (fts_close(fts) == -1) { + int error = errno; + LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: " + << strerror(error)); + return 0; + } + + return size; +} + +namespace { +#define DECLARE_PREFIX_STRUCT(name) \ + struct Prefix##name \ + { \ + static std::string get() \ + { \ + return std::string(#name); \ + } \ + }; \ + +DECLARE_PREFIX_STRUCT(B) +DECLARE_PREFIX_STRUCT(KB) +DECLARE_PREFIX_STRUCT(MB) +DECLARE_PREFIX_STRUCT(GB) + +#undef DECLARE_PREFIX_STRUCT + +const int stepSize = 1024; +template +struct Pre; + +template +struct Pre +{ + static const double value; + static std::string printSize(double fileSize) + { + if (fileSize >= Pre::value) { + double now = fileSize / Pre::value; + std::ostringstream outputStream; + outputStream.setf(std::ios::fixed, std::ios::floatfield); + outputStream.precision(2); + outputStream << now << Postfix::get(); + return outputStream.str(); + } else { + return Pre::printSize(fileSize); + } + } +}; + +template<> +struct Pre<> +{ + static const double value; + static std::string printSize(double /*fileSize*/) + { + return "0B"; + } +}; + +const double Pre<>::value = 1.0; +template const double Pre:: + value(Pre<>::value * stepSize); + +typedef Pre FolderSizeToStringType; +} //anonymous namespace + +DPL::String fromFileSizeString(size_t fileSize) +{ + std::string output = + FolderSizeToStringType::printSize(static_cast(fileSize)); + return DPL::FromUTF8String(output); +} +} // end of namespace Utils diff --git a/modules/utils/src/mime_type_utils.cpp b/modules/utils/src/mime_type_utils.cpp new file mode 100644 index 0000000..18a72fe --- /dev/null +++ b/modules/utils/src/mime_type_utils.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include +#include + +#include + +const std::set& MimeTypeUtils::getMimeTypesSupportedForIcon() +{ + static std::set set; + DPL::String (*s)(const std::string&) = DPL::FromASCIIString; + if (set.empty()) { + set.insert(s("image/gif")); + set.insert(s("image/png")); + set.insert(s("image/vnd.microsoft.icon")); + set.insert(s("image/svg+xml")); + set.insert(s("image/jpeg")); + } + return set; +} + +const std::set& MimeTypeUtils::getMimeTypesSupportedForStartFile() +{ + static std::set set; + DPL::String (*s)(const std::string&) = DPL::FromASCIIString; + if (set.empty()) { + set.insert(s("text/html")); + set.insert(s("application/xhtml+xml")); + set.insert(s("image/svg+xml")); + } + return set; +} + +bool MimeTypeUtils::isMimeTypeSupportedForStartFile(const DPL::String& mimeType) +{ + return getMimeTypesSupportedForStartFile().count(stripMimeParameters( + mimeType)) > 0; +} + +const MimeTypeUtils::FileIdentificationMap& MimeTypeUtils:: + getFileIdentificationMap() +{ + static FileIdentificationMap map; + DPL::String (*s)(const std::string&) = DPL::FromASCIIString; + if (map.empty()) { + map[s(".html")] = s("text/html"); + map[s(".htm")] = s("text/html"); + map[s(".css")] = s("text/css"); + map[s(".js")] = s("application/javascript"); + map[s(".xml")] = s("application/xml"); + map[s(".txt")] = s("text/plain"); + map[s(".wav")] = s("audio/x-wav"); + map[s(".xhtml")] = s("application/xhtml+xml"); + map[s(".xht")] = s("application/xhtml+xml"); + map[s(".gif")] = s("image/gif"); + map[s(".png")] = s("image/png"); + map[s(".ico")] = s("image/vnd.microsoft.icon"); + map[s(".svg")] = s("image/svg+xml"); + map[s(".jpg")] = s("image/jpeg"); + } + return map; +} + +bool MimeTypeUtils::isMimeTypeSupportedForIcon(const DPL::String& mimeType) +{ + return getMimeTypesSupportedForIcon().count(stripMimeParameters(mimeType)) + > 0; +} + +DPL::String MimeTypeUtils::stripMimeParameters(const DPL::String& mimeType) +{ + size_t parametersStart = mimeType.find_first_of(L';'); + if (parametersStart != DPL::String::npos) { + return mimeType.substr(0, parametersStart); + } else { + return mimeType; + } +} + +MimeTypeUtils::MimeAttributes MimeTypeUtils::getMimeAttributes( + const DPL::String& mimeType) +{ + MimeAttributes attributes; + std::vector tokens; + DPL::Tokenize(mimeType, L";=", std::back_inserter(tokens)); + for (unsigned int i = 1; i < tokens.size(); i += 2) { + attributes[tokens[i]] = tokens[i + 1]; + } + return attributes; +} + +bool MimeTypeUtils::isValidIcon(const DPL::String& path) +{ + return getMimeTypesSupportedForIcon().count(identifyFileMimeType(path)) > 0; +} + +bool MimeTypeUtils::isValidStartFile( + const DPL::String& path, + const DPL::OptionalString& + providedMimeType) +{ + DPL::String mimeType = (!!providedMimeType) ? stripMimeParameters( + *providedMimeType) : identifyFileMimeType(path); + return getMimeTypesSupportedForStartFile().count(mimeType) > 0; +} + +DPL::String MimeTypeUtils::getFileNameFromPath(const DPL::String& path) +{ + size_t lastSlashPos = path.find_last_of(L'/'); + return path.substr(lastSlashPos + 1); +} + +DPL::String MimeTypeUtils::identifyFileMimeType(const DPL::String& path) +{ + DPL::String name = getFileNameFromPath(path); //step 4 + + if (name.size() == 0) { + ThrowMsg(Exception::InvalidFileName, "Path should contain a file name."); + } + + size_t lastFullStop = name.find_last_of(L'.'); + if (lastFullStop != 0 && lastFullStop != DPL::String::npos) { //step 5 + DPL::String extension = name.substr(lastFullStop); //step 6 & 7 + if (extension.size() > 0) { //step 8 + //step 9 + std::transform(extension.begin(), extension.end(), + extension.begin(), ::towlower); + FileIdentificationMap::const_iterator it = + getFileIdentificationMap().find(extension); + if (it != getFileIdentificationMap().end()) { + return it->second; + } + } + } + + // step 10 - sniff + std::string filePath = DPL::ToUTF8String(path); + + std::string mime = xdg_mime_get_mime_type_for_file(filePath.c_str(), 0); + if (!mime.empty()) { + return DPL::FromASCIIString(mime); + } + return DPL::FromASCIIString("application/sniff"); +} diff --git a/modules/utils/src/path.cpp b/modules/utils/src/path.cpp new file mode 100644 index 0000000..0a41837 --- /dev/null +++ b/modules/utils/src/path.cpp @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file path.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + */ + +#include "dpl/utils/path.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace DPL { + +namespace Utils { + +namespace { +const char * const TEMPORARY_PATH_POSTFIX = "temp"; +const mode_t TEMPORARY_PATH_MODE = 0775; +} // namespace + +Path::Iterator::Iterator() //end iterator by default +{ +} + +Path::Iterator::Iterator(const char * str) +{ + m_root = std::shared_ptr(new Path(str)); + m_dir = std::shared_ptr(opendir(str), [](DIR * d){ if(d)closedir(d); }); //custom delete + if(m_dir.get() == NULL) + { + ThrowMsg(NotDirectory, "Not directory"); + } + ReadNext(); +} + +Path::Iterator& Path::Iterator::operator++() +{ + ReadNext(); + return *this; +} + +Path::Iterator Path::Iterator::operator++(int) +{ + Path::Iterator copy(*this); + ReadNext(); + return copy; +} + +void Path::Iterator::ReadNext() +{ + struct dirent * entry = readdir(m_dir.get()); + while(entry && (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0)) + { + entry = readdir(m_dir.get()); + } + if(entry) + { + m_path = std::shared_ptr(new Path(*m_root)); + m_path->Append(entry->d_name); + } + else //transform into end iterator + { + m_path.reset(); + m_dir.reset(); + } +} + +bool Path::Iterator::operator==(const Path::Iterator& rhs) const +{ + if(m_dir.get() == NULL) + { + if(rhs.m_dir.get() == NULL) return true; + else return false; + } + else + { + if(rhs.m_dir.get() == NULL) return false; + } + return *m_path == *rhs.m_path; +} + +bool Path::Iterator::operator!=(const Path::Iterator& rhs) const +{ + return !this->operator==(rhs); +} + +const Path & Path::Iterator::operator*() +{ + return *m_path; +} + +const Path * Path::Iterator::operator->() +{ + return m_path.get(); +} + +Path::Path(const DPL::String & str) +{ + Construct(ToUTF8String(str)); +} + +Path::Path(const std::string & str) +{ + Construct(str); +} + +Path::Path(const char * str) +{ + Construct(std::string(str)); +} + +void Path::Construct(const std::string & src) +{ + if(src.empty()) ThrowMsg(EmptyPath, "Path cannot be empty"); + if(src[0] != '/') + { + DPL::ScopedFree root(getcwd(NULL,0)); + Tokenize(std::string(root.Get()), "\\/", std::inserter(m_parts, m_parts.begin()), true); + } + Tokenize(src, "\\/", std::inserter(m_parts, m_parts.end()), true); +} + +Path::Path() +{ +} + +std::string Path::DirectoryName() const +{ + if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryName for root directory"); + std::string ret = Join(m_parts.begin(), --m_parts.end(), "/"); + return std::string("/") + ret; +} + +std::string Path::Filename() const +{ + if(m_parts.empty()) return ""; + else return m_parts.back(); +} + +std::string Path::Fullpath() const +{ + std::string ret = Join(m_parts.begin(), m_parts.end(), "/"); + return std::string ("/") + ret; +} + +std::string Path::Extension() const +{ + if(m_parts.empty()) return ""; + + const std::string& last = *--m_parts.end(); + + std::string::size_type pos = last.find_last_of("."); + if(pos != std::string::npos) + { + return last.substr(pos + 1); + } + else + { + return ""; + } +} + +//foreach +Path::Iterator Path::begin() const +{ + if(IsDir()) + { + return Iterator(Fullpath().c_str()); + } + else + { + ThrowMsg(NotDirectory, "Cannot iterate not a directory"); + } +} + +Path::Iterator Path::end() const +{ + return Iterator(); +} + +void Path::RootGuard() const +{ + if(m_parts.empty()) Throw(RootDirectoryError); +} + +bool Path::Exists() const +{ + struct stat tmp; + memset(&tmp, 0, sizeof(struct stat)); + return (0 == lstat(Fullpath().c_str(), &tmp)); +} + +bool Path::IsDir() const +{ + struct stat tmp; + memset(&tmp, 0, sizeof(struct stat)); + if (-1 == lstat(Fullpath().c_str(), &tmp)) + { + ThrowMsg(NotExists, DPL::GetErrnoString()); + } + return S_ISDIR(tmp.st_mode); +} + +bool Path::IsFile() const +{ + struct stat tmp; + memset(&tmp, 0, sizeof(struct stat)); + if (-1 == lstat(Fullpath().c_str(), &tmp)) + { + ThrowMsg(NotExists, DPL::GetErrnoString()); + } + return S_ISREG(tmp.st_mode); +} + +bool Path::ExistsAndIsFile() const +{ + bool flag = false; + Try + { + flag = this->IsFile(); + } Catch (Path::NotExists) { + LogPedantic(*this << "is not a file."); + } + return flag; +} + +bool Path::ExistsAndIsDir() const +{ + bool flag = false; + Try + { + flag = this->IsDir(); + } Catch (Path::NotExists) { + LogPedantic(*this << "is not a directory."); + } + return flag; +} + +bool Path::IsSymlink() const +{ + struct stat tmp; + memset(&tmp, 0, sizeof(struct stat)); + if (-1 == lstat(Fullpath().c_str(), &tmp)) + { + ThrowMsg(NotExists, DPL::GetErrnoString()); + } + return S_ISLNK(tmp.st_mode); +} + +bool Path::operator==(const Path & other) const +{ + return m_parts == other.m_parts; +} + +bool Path::operator!=(const Path & other) const +{ + return m_parts != other.m_parts; +} + +Path Path::operator/(const DPL::String& part) const +{ + Path newOne(*this); + newOne.Append(ToUTF8String(part)); + return newOne; +} + +Path Path::operator/(const std::string& part) const +{ + Path newOne(*this); + newOne.Append(part); + return newOne; +} + +Path Path::operator/(const char * part) const +{ + Path newOne(*this); + newOne.Append(std::string(part)); + return newOne; +} + +Path & Path::operator/=(const DPL::String& part) +{ + Append(ToUTF8String(part)); + return *this; +} + +Path & Path::operator/=(const std::string& part) +{ + Append(part); + return *this; +} + +Path & Path::operator/=(const char * part) +{ + Append(std::string(part)); + return *this; +} + +void Path::Append(const std::string& part) +{ + std::vector tokens; + Tokenize(part, "\\/", std::inserter(tokens, tokens.end()), true); + std::copy(tokens.begin(), tokens.end(), std::inserter(m_parts, m_parts.end())); +} + +Path Path::DirectoryPath() const +{ + Path npath; + if(m_parts.empty()) ThrowMsg(InternalError, "Asking DirectoryPath for root directory"); + std::copy(m_parts.begin(), --m_parts.end(), std::back_inserter(npath.m_parts)); + return npath; +} + +std::size_t Path::Size() const +{ + struct stat tmp; + memset(&tmp, 0, sizeof(struct stat)); + if (-1 == lstat(Fullpath().c_str(), &tmp)) + { + ThrowMsg(NotExists, DPL::GetErrnoString()); + } + return tmp.st_size; +} + +bool Path::isSubPath(const Path & other) const +{ + typedef std::vector::const_iterator Iter; + Iter otherIter = other.m_parts.begin(); + for(Iter iter = m_parts.begin(); iter != m_parts.end(); iter++) + { + if(otherIter == other.m_parts.end()) return false; + if(*iter != *otherIter) return false; + otherIter++; + } + return true; +} + +bool Path::hasExtension(const std::string& extension) const +{ + LogPedantic("Looking for extension " << extension); + + if(Extension() == extension) + { + return true; + } + else + { + return false; + } +} + +void MakeDir(const Path & path, mode_t mode) +{ + path.RootGuard(); + if(!WrtUtilMakeDir(path.Fullpath(), mode)) + ThrowMsg(Path::OperationFailed, "Cannot make directory"); +} + +void MakeEmptyFile(const Path & path) +{ + path.RootGuard(); + int ret = 0; + ret = mknod(path.Fullpath().c_str(), S_IFREG, 0); + if(ret != 0) + { + if(errno == EEXIST) + { + ThrowMsg(Path::AlreadyExists, "File already exists: " << path); + } + else + { + ThrowMsg(Path::OperationFailed, "Operation failed"); + } + } +} + +void Remove(const Path & path) +{ + path.RootGuard(); + if(!WrtUtilRemove(path.Fullpath())) ThrowMsg(Path::OperationFailed, "Cannot remove path"); +} + +bool TryRemove(const Path & path) +{ + path.RootGuard(); + return WrtUtilRemove(path.Fullpath()); +} + +void Rename(const Path & from, const Path & to) +{ + from.RootGuard(); + to.RootGuard(); + if(from == to) + { + return; + } + if(0 != rename(from.Fullpath().c_str(), to.Fullpath().c_str())) + { + if(errno == EXDEV) + { + if(from.IsDir()) + { + CopyDir(from, to); + Remove(from); + } + else if(from.IsFile() || from.IsSymlink()) + { + CopyFile(from, to); + Remove(from); + } + else + { + ThrowMsg(Path::OperationFailed, DPL::GetErrnoString()); + } + } + else + { + ThrowMsg(Path::OperationFailed, DPL::GetErrnoString()); + } + } +} + +void CopyFile(const Path & from, const Path & to) +{ + from.RootGuard(); + to.RootGuard(); + Try + { + DPL::FileInput input(from.Fullpath()); + DPL::FileOutput output(to.Fullpath()); + DPL::Copy(&input, &output); + } + Catch(DPL::FileInput::Exception::Base) + { + LogError("File input error"); + ReThrowMsg(DPL::CopyFailed, std::string("File input error") + from.Fullpath()); + } + Catch(DPL::FileOutput::Exception::Base) + { + LogError("File output error"); + ReThrowMsg(DPL::CopyFailed, std::string("File output error") + to.Fullpath()); + } + Catch(DPL::CopyFailed) + { + LogError("File copy error"); + ReThrowMsg(DPL::CopyFailed, std::string("File copy error") + from.Fullpath()); + } +} + +void CopyDir(const Path & from, const Path & to) +{ + from.RootGuard(); + to.RootGuard(); + if(from.isSubPath(to)) + { + ThrowMsg(Path::CannotCopy, "Cannot copy content of directory to it's sub directory"); + } + MakeDir(to); + FOREACH(item, from) + { + if(item->IsDir()) + { + CopyDir(*item, to / item->Filename()); + } + else if(item->IsFile() || item->IsSymlink()) + { + CopyFile(*item, to / item->Filename()); + } + else + { + Throw(Path::OperationFailed); + } + } +} + +Path CreateTempPath(const Path & basePath) +{ + LogDebug("Step: Creating temporary path"); + + // Temporary path + Path tempPath = basePath; + tempPath /= WrtDB::GlobalConfig::GetTmpDirPath(); + + timeval tv; + gettimeofday(&tv, NULL); + unsigned long long nr = (static_cast(tv.tv_sec) * 1000000ULL + static_cast(tv.tv_usec)); + std::stringstream relPath; + relPath << TEMPORARY_PATH_POSTFIX << "_" << nr; + tempPath /= relPath.str(); + + MakeDir(tempPath, TEMPORARY_PATH_MODE); + return tempPath; +} + +bool Exists(const Path & path) +{ + return path.Exists(); +} + +} + +} + +std::ostream & operator<<(std::ostream & str, const DPL::Utils::Path & path) +{ + str << path.Fullpath(); + return str; +} + +//TODO: uncomment when used defiend literals are supported +///DPL::Utils::Path operator""p(const char * str, size_t) +//{ +// return DPL::Utils::Path(str); +//} diff --git a/modules/utils/src/warp_iri.cpp b/modules/utils/src/warp_iri.cpp new file mode 100644 index 0000000..bd8650a --- /dev/null +++ b/modules/utils/src/warp_iri.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file have been implemented in compliance with W3C WARP SPEC. + * but there are some patent issue between W3C WARP SPEC and APPLE. + * so if you want to use this file, refer to the README file in root directory + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +namespace { +// All schemes which are supported by external application should be ignored +// by WARP engine. +// +// Warp specification require from iri to have host element. File protocol +// does not contain host element so it's always denied by warp. +// Unfortunatly all widgets are using file protocol to load its data from +// hard drive. What's why we cannot check any iri with file schema. + +const char *IRI_IGNORED_SCHEME[] = { "file://", "widget://", "app://", "tel:", + "sms:", "smsto:", "mmsto:", "mailto:", "data:", "blob:", + "tizen-service:", 0 }; + +const DPL::String SCHEMA_HTTP = DPL::FromUTF8String("http"); +const DPL::String SCHEMA_HTTPS = DPL::FromUTF8String("https"); +const DPL::String SCHEMA_FTP = DPL::FromUTF8String("ftp"); +} // namespace anonymous + +WarpIRI::WarpIRI() : + m_domain(false), + m_port(UNKNOWN_PORT), + m_isAccessDefinition(false), + m_isIRIValid(false) +{} + +void WarpIRI::set(const char *p_iri, + bool domain) +{ + if (!p_iri) { + m_isAccessDefinition = m_isIRIValid = false; + return; + } + + m_domain = domain; + m_isAccessDefinition = true; + m_isIRIValid = true; + m_host.clear(); + + if (strcmp(p_iri, "*") == 0) { + return; + } + std::unique_ptr iri(iri_parse(p_iri), iri_destroy); + + if (!iri.get()) { + LogError("Error in iri_parse!"); + m_isIRIValid = false; + m_isAccessDefinition = false; + return; + } + + if (iri->scheme == NULL || iri->host == NULL) { + m_isIRIValid = false; + m_isAccessDefinition = false; + return; + } + + // all of this must be NULL in WARP definition + if (iri->user || iri->path || iri->query || iri->anchor) { + m_isAccessDefinition = false; + } + + m_schema = DPL::FromASCIIString(std::string(iri->scheme)); + m_port = static_cast(iri->port); + + if (m_port == 0) { + m_port = getPort(m_schema); + if (m_port == UNKNOWN_PORT) { + m_isAccessDefinition = false; + return; + } + } + + std::string utf8host = iri->host; + std::list hostTokenList; + DPL::Tokenize(utf8host, ".", std::front_inserter(hostTokenList)); + + if (SCHEMA_HTTP == m_schema || SCHEMA_HTTPS == m_schema) { + FOREACH(i, hostTokenList) { + char *output = NULL; + int rc = idna_to_ascii_8z(i->c_str(), + &output, + IDNA_USE_STD3_ASCII_RULES); + + if (IDNA_SUCCESS != rc) { + LogWarning("libidn error: " << rc << " " << + idna_strerror((Idna_rc)rc)); + m_isIRIValid = false; + m_isAccessDefinition = false; + } else { + std::string token(output); + std::transform(token.begin(), + token.end(), + token.begin(), + ::tolower); + m_host.push_back(DPL::FromUTF8String(token)); + } + free(output); + } + } else { + FOREACH(i, hostTokenList){ + m_host.push_back(DPL::FromUTF8String(*i)); + } + } +} + +void WarpIRI::set(const DPL::String &iristring, + bool domain) +{ + set(DPL::ToUTF8String(iristring).c_str(), domain); +} + +unsigned int WarpIRI::getPort(const DPL::String &schema) const +{ + unsigned int port = UNKNOWN_PORT; + if (schema == SCHEMA_HTTP) { + port = 80; + } else if (schema == SCHEMA_HTTPS) { + port = 443; + } else if (schema == SCHEMA_FTP) { + port = 21; + } + return port; +} + +bool WarpIRI::isSubDomain(const WarpIRI &second) const +{ + if (!m_isAccessDefinition || !second.m_isIRIValid) { + return false; + } + if (m_schema != second.m_schema) { + return false; + } + if (m_port != second.m_port) { + return false; + } + + size_t size = m_host.size() < second.m_host.size() ? + m_host.size() : second.m_host.size(); + + if (m_host.size() > second.m_host.size()) { + return false; + } + + if (!m_domain && (m_host.size() != second.m_host.size())) { + return false; + } + + for (size_t i = 0; i < size; ++i) { + if (DPL::StringCompare(m_host[i], second.m_host[i])) { + return false; + } + } + return true; +} + +bool WarpIRI::isAccessDefinition() const +{ + return m_isAccessDefinition; +} + +bool WarpIRI::getSubDomain() const +{ + return m_domain; +} + +bool WarpIRI::isIRISchemaIgnored(const char *iri) +{ + for (int i = 0; IRI_IGNORED_SCHEME[i]; ++i) { + if (0 == + strncmp(iri, IRI_IGNORED_SCHEME[i], + strlen(IRI_IGNORED_SCHEME[i]))) + { + return true; + } + } + return false; +} diff --git a/modules/utils/src/widget_version.cpp b/modules/utils/src/widget_version.cpp new file mode 100644 index 0000000..6ba7933 --- /dev/null +++ b/modules/utils/src/widget_version.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file widget_version.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Implementation file for widget version + */ +#include +#include +#include +#include +#include +#include + +namespace // anonymous +{ +size_t WAC_CERTIFY_MANDATORY_PART_LOW_COUNT = 2; +size_t WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT = 3; +size_t WAC_CERTIFY_MANDATORY_PART_MAJOR_INDEX = 0; +size_t WAC_CERTIFY_MANDATORY_PART_MINOR_INDEX = 1; +size_t WAC_CERTIFY_MANDATORY_PART_MICRO_INDEX = 2; +DPL::String::value_type WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR = L' '; +DPL::String::value_type WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR = L'.'; +DPL::String::value_type LEADING_ZERO_CHAR = L'0'; + +// +// [ABNF] +// Augmented BNF for Syntax Specifications: ABNF. RFC5234. D. Crocker and P. +// Overell. January 2008. +// +// ALPHA = %x41-5A / %x61-7A +inline bool IsAlpha(int c) +{ + return (c >= 0x41 && c <= 0x5A) || + (c >= 0x61 && c <= 0x7A); +} + +// DIGIT = %x30-39 +inline bool IsDigit(int c) +{ + return c >= 0x30 && c <= 0x39; +} + +// SP = %x20 +inline bool IsSp(int c) +{ + return c == 0x20; +} + +DPL::String RemoveLeadingZeroes(const DPL::String &str) +{ + Assert(!str.empty()); + + if (str[0] != LEADING_ZERO_CHAR) { + return str; + } + + size_t pos = 0; + + while (pos + 1 < str.size()) { + ++pos; + + if (str[pos] != LEADING_ZERO_CHAR) + break; + } + + return str.substr(pos); +} + +// operator < +bool NumberLessOperator(const DPL::String &left, + const DPL::String &right) +{ + // Assume: No leading zeroes + if (left.size() < right.size()) { + return true; + } + + if (left.size() > right.size()) { + return false; + } + + // Now: left.size() == right.size() + for (ssize_t i = static_cast(left.size()) - 1; i >= 0; --i) { + if (left[i] < right[i]) { + return true; + } + + if (left[i] > right[i]) { + return false; + } + } + + // Equal + return false; +} + +bool WacCertifyNumberString(const DPL::String &str) +{ + for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) { + if (!IsDigit(*i)) { + return false; + } + } + + return true; +} + +bool WacCertifyAlphaNumberStringSpace(const DPL::String &str) +{ + for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) { + if (!IsDigit(*i) && !IsAlpha(*i) && !IsSp(*i)) { + return false; + } + } + + return true; +} +} // anonymous + +WidgetVersion::WidgetVersion(const DPL::String &str) : + m_isWac(false), + m_raw(str) +{ + LogDebug("Parsing version string: " << str); + + // Split optional an mandatory parts + size_t optionalPartPosition = str.find( + WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR); + + DPL::String mandatoryPart; + DPL::Optional optionalPart; + + if (optionalPartPosition == DPL::String::npos) { + mandatoryPart = str; + } else { + mandatoryPart = str.substr(0, optionalPartPosition); + optionalPart = str.substr(optionalPartPosition + 1, DPL::String::npos); + } + + LogDebug("Mandatory part is: " << mandatoryPart); + LogDebug("Optional part is: " << optionalPart); + + // Split string and construct version + std::vector parts; + DPL::Tokenize(mandatoryPart, + WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR, + std::back_inserter(parts), + false); + + LogDebug("Tokenized mandatory parts: " << parts.size()); + + if (parts.size() != WAC_CERTIFY_MANDATORY_PART_LOW_COUNT && + parts.size() != WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT) + { + return; + } + + DPL::String major; + DPL::String minor; + DPL::Optional micro; + + // Certify for Wac + major = parts[WAC_CERTIFY_MANDATORY_PART_MAJOR_INDEX]; + minor = parts[WAC_CERTIFY_MANDATORY_PART_MINOR_INDEX]; + + if (parts.size() == WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT) { + micro = parts[WAC_CERTIFY_MANDATORY_PART_MICRO_INDEX]; + } + + WacCertify(major, minor, micro, optionalPart); +} + +WidgetVersion::WidgetVersion(const DPL::String &major, + const DPL::String &minor, + const DPL::Optional µ, + const DPL::Optional &optional) : + m_isWac(false) +{ + // Create Raw version + m_raw += major; + m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR; + m_raw += minor; + + if (!!micro) { + m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR; + m_raw += *micro; + } + + if (!!optional) { + m_raw += WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR; + m_raw += *optional; + } + + // Certify for Wac + WacCertify(major, minor, micro, optional); +} + +void WidgetVersion::WacCertify(const DPL::String &major, + const DPL::String &minor, + const DPL::Optional µ, + const DPL::Optional &optional) +{ + LogDebug("Certyfing..."); + + LogDebug("Major candidate: " << major); + LogDebug("Minor candidate: " << minor); + LogDebug("Micro candidate: " << micro); + LogDebug("Optional candidate: " << optional); + + // Check strings + if (major.empty() || !WacCertifyNumberString(major)) { + LogDebug("Major version not certified!"); + return; + } + + if (minor.empty() || !WacCertifyNumberString(minor)) { + LogDebug("Minor version not certified!"); + return; + } + + if (!!micro && (micro->empty() || !WacCertifyNumberString(*micro))) { + LogDebug("Microversion not certified!"); + return; + } + + if (!!optional && + (optional->empty() || !WacCertifyAlphaNumberStringSpace(*optional))) + { + LogDebug("Optional version not certified!"); + return; + } + + // OK + m_major = major; + m_minor = minor; + m_micro = micro; + m_optional = optional; + + m_isWac = true; + + LogDebug("Certified."); +} + +bool WidgetVersion::IsWac() const +{ + return m_isWac; +} + +const DPL::String &WidgetVersion::Raw() const +{ + return m_raw; +} + +const DPL::String &WidgetVersion::Major() const +{ + return m_major; +} + +const DPL::String &WidgetVersion::Minor() const +{ + return m_minor; +} + +const DPL::Optional &WidgetVersion::Micro() const +{ + return m_micro; +} + +const DPL::Optional &WidgetVersion::Optional() const +{ + return m_optional; +} + +bool operator<(const WidgetVersion &left, + const WidgetVersion &right) +{ + AssertMsg( + left.IsWac() && right.IsWac(), + "Only WAC version strings are comparable!"); + + if (NumberLessOperator(RemoveLeadingZeroes(left.Major()), + RemoveLeadingZeroes(right.Major()))) + { + return true; + } + if (NumberLessOperator(RemoveLeadingZeroes(right.Major()), + RemoveLeadingZeroes(left.Major()))) + { + return false; + } + + if (NumberLessOperator(RemoveLeadingZeroes(left.Minor()), + RemoveLeadingZeroes(right.Minor()))) + { + return true; + } + if (NumberLessOperator(RemoveLeadingZeroes(right.Minor()), + RemoveLeadingZeroes(left.Minor()))) + { + return false; + } + + if (!!left.Micro() && !!right.Micro() && + NumberLessOperator(RemoveLeadingZeroes(*left.Micro()), + RemoveLeadingZeroes(*right.Micro()))) + { + return true; + } + if (!left.Micro() && !!right.Micro()) { + return true; + } + + return false; +} + +bool operator<=(const WidgetVersion &left, + const WidgetVersion &right) +{ + AssertMsg( + left.IsWac() && right.IsWac(), + "Only WAC version strings are comparable!"); + + return (left == right) || (left < right); +} + +bool operator>(const WidgetVersion &left, + const WidgetVersion &right) +{ + AssertMsg( + left.IsWac() && right.IsWac(), + "Only WAC version strings are comparable!"); + + return !(left <= right); +} + +bool operator>=(const WidgetVersion &left, + const WidgetVersion &right) +{ + AssertMsg( + left.IsWac() && right.IsWac(), + "Only WAC version strings are comparable!"); + + return (left == right) || (left > right); +} + +bool operator==(const WidgetVersion &left, + const WidgetVersion &right) +{ + AssertMsg( + left.IsWac() && right.IsWac(), + "Only WAC version strings are comparable!"); + + //Major are equal + //and + //Minor are equal + //and + //Both Micro exist and are equal + //or both Micro do not exist + return RemoveLeadingZeroes(left.Major()) == + RemoveLeadingZeroes(right.Major()) && + RemoveLeadingZeroes(left.Minor()) == + RemoveLeadingZeroes(right.Minor()) && + ( + (!!left.Micro() && !!right.Micro() && + RemoveLeadingZeroes(*left.Micro()) == + RemoveLeadingZeroes(*right.Micro())) || + (!left.Micro() && !right.Micro()) + ); +} + +bool operator!=(const WidgetVersion &left, + const WidgetVersion &right) +{ + AssertMsg( + left.IsWac() && right.IsWac(), + "Only WAC version strings are comparable!"); + + return !(left == right); +} + +std::ostream & operator<<(std::ostream& stream, + const WidgetVersion& version) +{ + stream << version.Raw(); + return stream; +} diff --git a/modules/utils/src/wrt_global_settings.cpp b/modules/utils/src/wrt_global_settings.cpp new file mode 100644 index 0000000..4f005c5 --- /dev/null +++ b/modules/utils/src/wrt_global_settings.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file wrt_global_settings.cpp + * @version 1.0 + * @author Pawel Sikorski(p.sikorski@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @brief runtime + */ +#include +#include +#include +#include +#include +#include +#include + +namespace GlobalSettings { +namespace { +const int ROAMING_TEST = 0x00000001; +const int POPUPS_TEST = 0x00000002; +const int OCSP_TEST = 0x00000004; +const int WARP_TEST = 0x00000008; +const int CRL_TEST = 0x00000010; +const int SCREEN_SHOT_TEST = 0x00000020; +const int ALL_TEST = (ROAMING_TEST | POPUPS_TEST | OCSP_TEST | WARP_TEST + | CRL_TEST | SCREEN_SHOT_TEST); +const char* WRT_TEST_MODE = "WRT_TEST_MODE"; +const char* MACHINE_NAME_EMUL = "emulated"; // "arch_emulated" +enum MachineType +{ + MACHINE_TYPE_TARGET, + MACHINE_TYPE_EMULATOR, + MACHINE_TYPE_UNKNOWN +}; + +struct Settings { + bool isEmulator; + int testModes; + + Settings() : + isEmulator(false), testModes(0) + {} +}; + +Settings gSettings; + +bool initializeGlobalSettings(); +bool initHelper = initializeGlobalSettings(); + +MachineType getMachineType() +{ + // get current machine name + struct utsname u; + if (0 == uname(&u)) { + if (0 == strlen(u.machine)) { + return MACHINE_TYPE_UNKNOWN; + } else { + // If current machine is emul, + // machine name include "_emulated" + std::string machine = u.machine; + // find "emulated" string in the u.machine + if (std::string::npos != machine.find(MACHINE_NAME_EMUL)) { + return MACHINE_TYPE_EMULATOR; + } else { + return MACHINE_TYPE_TARGET; + } + } + } + + return MACHINE_TYPE_UNKNOWN; +} + +bool initializeGlobalSettings() +{ + (void)initHelper; + + // ignore environment variables if this flag is not set +#ifdef GLOBAL_SETTINGS_CONTROL + char * envStr = getenv(WRT_TEST_MODE); + if (NULL != envStr) { + std::string env = envStr; + int testMode = 0; + if ("1" == env) { + testMode = ALL_TEST; + } else { + std::istringstream str(envStr); + while (std::getline(str, env, '|')) { + if ("popups" == env) { + testMode |= POPUPS_TEST; + } else if ("roaming" == env) { + testMode |= ROAMING_TEST; + } else if ("ocsp" == env) { + testMode |= OCSP_TEST; + } else if ("warp" == env) { + testMode |= WARP_TEST; + } else if ("crl" == env) { + testMode |= CRL_TEST; + } else if ("screen" == env) { + testMode |= SCREEN_SHOT_TEST; + } + } + } + gSettings.testModes = testMode; + } + // TODO other settings initialization + +#endif + gSettings.isEmulator = (MACHINE_TYPE_EMULATOR == getMachineType()); + return false; +} +} // namespace + +bool TestModeEnabled() +{ + return ((gSettings.testModes & ALL_TEST) == ALL_TEST); +} + +bool PopupsTestModeEnabled() +{ + return (gSettings.testModes & POPUPS_TEST); +} +bool WarpTestModeEnabled() +{ + return (gSettings.testModes & WARP_TEST); +} +bool RoamingTestModeEnabled() +{ + return (gSettings.testModes & ROAMING_TEST); +} +bool OCSPTestModeEnabled() +{ + return (gSettings.testModes & OCSP_TEST); +} +bool CrlTestModeEnabled() +{ + return (gSettings.testModes & CRL_TEST); +} +bool MakeScreenTestModeEnabled() +{ + return (gSettings.testModes & SCREEN_SHOT_TEST); +} + +bool IsEmulator() +{ + return gSettings.isEmulator; +} +} // GlobalSettings diff --git a/modules/utils/src/wrt_utility.cpp b/modules/utils/src/wrt_utility.cpp new file mode 100644 index 0000000..44044f2 --- /dev/null +++ b/modules/utils/src/wrt_utility.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file wrt_utility.cpp + * @version 0.8 + * @author Janusz Majnert + * @brief Implementation of some common utility functions + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void WrtUtilJoinPaths(std::string &joined, + const std::string &parent, + const std::string &child) +{ + size_t parent_len = parent.length(); + joined = parent; + joined += child; + //In case someone used windows-style paths + std::replace(joined.begin(), joined.end(), '\\', '/'); + + if (parent_len != 0 && child.length() != 0) { + if (joined[parent_len - 1] != '/' && joined[parent_len] != '/') { + joined.insert(parent_len, "/"); + } else if (joined[parent_len - 1] == '/' && joined[parent_len] == + '/') + { + joined.erase(parent_len, 1); + } + } +} + +bool WrtUtilMakeDir(const std::string &newpath, mode_t mode) +{ + size_t pos = 0; + int error; + + if (newpath.length() == 0) { + return false; + } + + std::string path = newpath; + + if (*(path.rbegin()) != '/') { + path += '/'; + } + + while ((pos = path.find('/', pos + 1)) != std::string::npos) { + if (mkdir(path.substr(0, pos).c_str(), mode) != 0) { + error = errno; + if (error == EEXIST) { + continue; + } + LogWarning(__PRETTY_FUNCTION__ << ": failed to create directory " + << path.substr(0, pos) + << ". Error: " + << strerror(error)); + return false; + } + } + return true; +} + +bool WrtUtilRemove(const std::string &path) +{ + FTS *fts; + FTSENT *ftsent; + bool rv = true; + int error = 0; + char * const paths[] = { const_cast(path.c_str()), NULL }; + + if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) { + //ERROR + error = errno; + LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: " + << strerror(error)); + return false; + } + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_D: + //directory in preorder - do nothing + break; + case FTS_DP: + //directory in postorder - remove + if (rmdir(ftsent->fts_accpath) != 0) { + error = errno; + LogWarning(__PRETTY_FUNCTION__ + << ": rmdir failed with error: " + << strerror(error)); + rv = false; + } + break; + case FTS_DC: + case FTS_F: + case FTS_NSOK: + case FTS_SL: + case FTS_SLNONE: + case FTS_DEFAULT: + //regular files and other objects that can safely be removed + if (unlink(ftsent->fts_accpath) != 0) { + error = errno; + LogWarning(__PRETTY_FUNCTION__ + << ": unlink failed with error: " + << strerror(error)); + rv = false; + } + break; + case FTS_NS: + LogWarning(__PRETTY_FUNCTION__ + << ": couldn't get stat info for file: " + << ftsent->fts_path + << ". The error was: " + << strerror(ftsent->fts_errno)); + rv = false; + break; + case FTS_DOT: + case FTS_DNR: + case FTS_ERR: + default: + LogWarning(__PRETTY_FUNCTION__ + << ": traversal failed with error: " + << strerror(ftsent->fts_errno)); + rv = false; + break; + } + } + + if (fts_close(fts) == -1) { + error = errno; + LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: " + << strerror(error)); + rv = false; + } + return rv; +} + +bool WrtUtilFileExists(const std::string &path) +{ + struct stat tmp; + if (stat(path.c_str(), &tmp) == 0) { + return S_ISREG(tmp.st_mode); + } else { + return false; + } +} + +bool WrtUtilDirExists(const std::string &path) +{ + struct stat tmp; + if (stat(path.c_str(), &tmp) == 0) { + return S_ISDIR(tmp.st_mode); + } else { + return false; + } +} + diff --git a/modules/widget_dao/CMakeLists.txt b/modules/widget_dao/CMakeLists.txt new file mode 100644 index 0000000..269f37f --- /dev/null +++ b/modules/widget_dao/CMakeLists.txt @@ -0,0 +1,141 @@ +SET(TARGET_WRT_DAO_DB "Sqlite3DbWRT") + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_BINARY_DIR}/modules/widget_dao/database_checksum.h + COMMAND ${CMAKE_SOURCE_DIR}/modules/widget_dao/orm/gen_db_md5.sh + ARGS ${CMAKE_BINARY_DIR}/modules/widget_dao/database_checksum.h + ${CMAKE_SOURCE_DIR}/modules/widget_dao/orm/wrt_db + DEPENDS ${CMAKE_SOURCE_DIR}/modules/widget_dao/orm/wrt_db + ${CMAKE_SOURCE_DIR}/modules/widget_dao/orm/gen_db_md5.sh + COMMENT "Generating WRT database checksum" + ) + +ADD_CUSTOM_COMMAND( OUTPUT .wrt.db + COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/.wrt.db + COMMAND gcc -Wall -include ${CMAKE_BINARY_DIR}/modules/widget_dao/database_checksum.h -I${PROJECT_SOURCE_DIR}/modules/db/include -I${PROJECT_SOURCE_DIR}/modules/widget_dao/orm -E ${PROJECT_SOURCE_DIR}/modules/widget_dao/orm/wrt_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_BINARY_DIR}/wrt_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_BINARY_DIR}/.wrt.db ".read ${CMAKE_CURRENT_BINARY_DIR}/wrt_db.sql" || rm -f ${CMAKE_CURRENT_BINARY_DIR}/.wrt.db + DEPENDS ${CMAKE_BINARY_DIR}/modules/widget_dao/database_checksum.h ${PROJECT_SOURCE_DIR}/modules/widget_dao/orm/wrt_db_sql_generator.h ${PROJECT_SOURCE_DIR}/modules/widget_dao/orm/wrt_db + ) + +ADD_CUSTOM_COMMAND( OUTPUT .wrt.db-journal + COMMAND touch + ARGS ${CMAKE_CURRENT_BINARY_DIR}/.wrt.db-journal + ) + +ADD_CUSTOM_TARGET(${TARGET_WRT_DAO_DB} ALL DEPENDS .wrt.db .wrt.db-journal) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/wrt_db.sql + DESTINATION share/wrt-engine/ + ) + +############################################################################### + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(WRT_DAO_DEPS + appcore-efl + db-util + dlog + ecore + libxml-2.0 + dlog + openssl + REQUIRED) + +SET(WRT_DAO_RO_SOURCES + dao/config_parser_data.cpp + dao/common_dao_types.cpp + dao/feature_dao_read_only.cpp + dao/path_builder.cpp + dao/plugin_dao_read_only.cpp + dao/property_dao_read_only.cpp + dao/widget_dao_read_only.cpp + dao/webruntime_database.cpp + dao/WrtDatabase.cpp + dao/widget_dao_types.cpp +) + +SET(WRT_DAO_RW_SOURCES + dao/feature_dao.cpp + dao/plugin_dao.cpp + dao/property_dao.cpp + dao/widget_dao.cpp +) + +SET(WRT_DAO_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/modules/widget_dao/include + ${PROJECT_SOURCE_DIR}/modules/event/include + ${PROJECT_SOURCE_DIR}/modules/widget_dao/orm + ${PROJECT_SOURCE_DIR}/modules/core/include + ${PROJECT_SOURCE_DIR}/modules/db/include + ${PROJECT_SOURCE_DIR}/modules/log/include + ${PROJECT_SOURCE_DIR}/modules/localization/include +) + +INCLUDE_DIRECTORIES(${WRT_DAO_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(SYSTEM ${WRT_DAO_DEPS_INCLUDE_DIRS}) + +ADD_LIBRARY(${TARGET_WRT_DAO_RO_LIB} SHARED + ${WRT_DAO_RO_SOURCES} +) +SET_TARGET_PROPERTIES(${TARGET_WRT_DAO_RO_LIB} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION}) + +SET_TARGET_PROPERTIES(${TARGET_WRT_DAO_RO_LIB} PROPERTIES + COMPILE_FLAGS -fPIC) + +SET_TARGET_PROPERTIES(${TARGET_WRT_DAO_RO_LIB} PROPERTIES + COMPILE_FLAGS "-include ${CMAKE_BINARY_DIR}/modules/widget_dao/database_checksum.h") + +TARGET_LINK_LIBRARIES(${TARGET_WRT_DAO_RO_LIB} + ${TARGET_DPL_EFL} + ${TARGET_DPL_DB_EFL} + ${WRT_DAO_DEPS_LIBRARIES}) +ADD_DEPENDENCIES(${TARGET_WRT_DAO_RO_LIB} ${TARGET_WRT_DAO_DB}) + +ADD_LIBRARY(${TARGET_WRT_DAO_RW_LIB} SHARED ${WRT_DAO_RW_SOURCES}) + +SET_TARGET_PROPERTIES(${TARGET_WRT_DAO_RW_LIB} PROPERTIES + SOVERSION ${API_VERSION} + VERSION ${VERSION}) + +SET_TARGET_PROPERTIES(${TARGET_WRT_DAO_RW_LIB} PROPERTIES COMPILE_FLAGS -fPIC) + +SET_TARGET_PROPERTIES(${TARGET_WRT_DAO_RW_LIB} PROPERTIES + COMPILE_FLAGS "-include ${CMAKE_BINARY_DIR}/modules/widget_dao/database_checksum.h") + +TARGET_LINK_LIBRARIES(${TARGET_WRT_DAO_RW_LIB} + ${TARGET_WRT_DAO_RO_LIB}) +ADD_DEPENDENCIES(${TARGET_WRT_DAO_RW_LIB} ${TARGET_WRT_DAO_DB}) + +INSTALL(TARGETS ${TARGET_WRT_DAO_RO_LIB} + DESTINATION lib) + +INSTALL(TARGETS ${TARGET_WRT_DAO_RW_LIB} + DESTINATION lib) + +INSTALL(FILES + include/dpl/wrt-dao-ro/config_parser_data.h + include/dpl/wrt-dao-ro/common_dao_types.h + include/dpl/wrt-dao-ro/feature_dao_read_only.h + include/dpl/wrt-dao-ro/feature_model.h + include/dpl/wrt-dao-ro/global_config.h + include/dpl/wrt-dao-ro/path_builder.h + include/dpl/wrt-dao-ro/plugin_dao_read_only.h + include/dpl/wrt-dao-ro/property_dao_read_only.h + include/dpl/wrt-dao-ro/widget_config.h + include/dpl/wrt-dao-ro/widget_dao_read_only.h + include/dpl/wrt-dao-ro/wrt_db_types.h + include/dpl/wrt-dao-ro/WrtDatabase.h + include/dpl/wrt-dao-ro/widget_dao_types.h + DESTINATION include/dpl-efl/dpl/wrt-dao-ro + ) + +INSTALL(FILES + include/dpl/wrt-dao-rw/feature_dao.h + include/dpl/wrt-dao-rw/plugin_dao.h + include/dpl/wrt-dao-rw/property_dao.h + include/dpl/wrt-dao-rw/widget_dao.h + DESTINATION include/dpl-efl/dpl/wrt-dao-rw + ) diff --git a/modules/widget_dao/dao/WrtDatabase.cpp b/modules/widget_dao/dao/WrtDatabase.cpp new file mode 100644 index 0000000..1cf6773 --- /dev/null +++ b/modules/widget_dao/dao/WrtDatabase.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include +#include +#include +#include +#include + +namespace WrtDB { +const char* WrtDatabase::Address() +{ + using namespace WrtDB; + return GlobalConfig::GetWrtDatabaseFilePath(); +} + +DPL::DB::SqlConnection::Flag::Type WrtDatabase::Flags() +{ + return DPL::DB::SqlConnection::Flag::UseLucene; +} + +DPL::DB::ThreadDatabaseSupport WrtDatabase::m_interface( + WrtDatabase::Address(), + WrtDatabase::Flags()); + +void WrtDatabase::attachToThreadRO() +{ + m_interface.AttachToThread(DPL::DB::SqlConnection::Flag::RO); +} + +void WrtDatabase::attachToThreadRW() +{ + m_interface.AttachToThread(DPL::DB::SqlConnection::Flag::RW); +} + +void WrtDatabase::detachFromThread() +{ + m_interface.DetachFromThread(); +} + +DPL::DB::ThreadDatabaseSupport& WrtDatabase::interface() +{ + return m_interface; +} + +bool WrtDatabase::CheckTableExist(const char *name) +{ + return m_interface.CheckTableExist(name); +} +} diff --git a/modules/widget_dao/dao/common_dao_types.cpp b/modules/widget_dao/dao/common_dao_types.cpp new file mode 100644 index 0000000..4f65da5 --- /dev/null +++ b/modules/widget_dao/dao/common_dao_types.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file common_dao_types.h + * @author Michal Ciepielski (m.ciepielski@samsung.com) + * @version 1.0 + * @brief This file contains the implementation of common data types for wrtdb + */ +#include +namespace WrtDB {} diff --git a/modules/widget_dao/dao/config_parser_data.cpp b/modules/widget_dao/dao/config_parser_data.cpp new file mode 100644 index 0000000..827f3cd --- /dev/null +++ b/modules/widget_dao/dao/config_parser_data.cpp @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file config_parser_data.cpp + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 0.1 + * @brief + */ +#include +#include +#include +#include +#include + +namespace WrtDB { +bool IsSpace(const xmlChar* str); +bool CopyChar(xmlChar* out, xmlChar* in); + +bool IsSpace(const xmlChar* str) +{ + int charlen = xmlUTF8Size(str); + + switch (charlen) { + case 1: + switch (*str) { + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x20: + return true; + + default: + return false; + } + + case 2: + if( *(str) == 0xc2 ){ + switch (*(str + 1)) { + case 0x85: + case 0xa0: + return true; + default: + return false; + } + }else + return false; + case 3: + switch (*str) { + case 0xe1: + { + unsigned char c2 = *(str + 1); + unsigned char c3 = *(str + 2); + if ((c2 == 0x9a && c3 == 0x80) || (c2 == 0xa0 && c3 == 0x8e)) { + return true; + } else { + return false; + } + } + + case 0xe2: + switch (*(str + 1)) { + case 0x80: + switch (*(str + 2)) { + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0xa8: + case 0xa9: + case 0xaf: + return true; + default: + return false; + } + case 0x81: + if (*(str + 2) == 0x9f) { + return true; + } else { + return false; + } + + default: + return false; + } + case 0xe3: + if (*(str + 1) == 0x80 && *(str + 2) == 0x80) { + return true; + } else { + return false; + } + + default: + return false; + } + + default: + return false; + } +} + +bool CopyChar(xmlChar* out, + xmlChar* in) +{ + int size = xmlUTF8Size(in); + switch (size) { + case 6: + out[5] = in[5]; + case 5: + out[4] = in[4]; + case 4: + out[3] = in[3]; + case 3: + out[2] = in[2]; + case 2: + out[1] = in[1]; + case 1: + out[0] = in[0]; + return true; + + default: + return false; + } +} + +//TODO temporary fix until commits the rewrite of this functionality. +void NormalizeString(DPL::String& str) +{ + DPL::Optional opt = str; + NormalizeString(opt); + str = *opt; +} + +void NormalizeString (DPL::Optional& txt, bool isTrimSpace) +{ + if (!!txt) { + std::string tmp = DPL::ToUTF8String(*txt); + const xmlChar* str = reinterpret_cast(tmp.c_str()); + if (!xmlCheckUTF8(str)) { + LogError("Not valid UTF8"); + return; + } + + int i = 0; + xmlChar* c; + while ((c = const_cast(xmlUTF8Strpos(str, i))) != NULL) { + if (!IsSpace(c)) { + break; + } + ++i; + } + + xmlChar* tmpnew = xmlUTF8Strndup(c, xmlUTF8Strlen(c) + 1); + if (tmpnew == NULL) { + LogError("can't do xmlUTF*Strndup();"); + return; + } + + bool first = false; + xmlChar* s = tmpnew; + while ((c = const_cast(xmlUTF8Strpos(str, i))) != NULL) { + if (IsSpace(c)) { + first = true; + ++i; + } else { + if (c[0] == 0x0) { + break; + } + if (first && !isTrimSpace) { + xmlChar space[6] = { 0x20 }; + CopyChar(s, space); + s += xmlUTF8Size(s); + first = false; + } + CopyChar(s, c); + s += xmlUTF8Size(s); + ++i; + } + } + s[0] = 0x0; + txt = DPL::FromUTF8String(reinterpret_cast(tmpnew)); + xmlFree(tmpnew); + } +} + +void NormalizeAndTrimSpaceString(DPL::OptionalString& txt) +{ + NormalizeString(txt, true); +} + +#if ENABLE(ELEMENT_ATTR_MAX_LENGTH) +void NormalizeString(DPL::String& str, const unsigned int length, +#if ENABLE(ADD_ELLIPSIS) + bool showEllipsis +#else + bool /*showEllipsis*/ +#endif + ) +{ +#if ENABLE(ADD_ELLIPSIS) + bool hasExceededMaxLength = false; + if (str.size() > length) { + hasExceededMaxLength = true; + str.resize(length); + } +#else + if (str.size() > length) { + str.resize(length); + } +#endif + + DPL::Optional opt = str; + NormalizeString(opt); + str = *opt; +#if ENABLE(ADD_ELLIPSIS) + if (showEllipsis && hasExceededMaxLength && (str.size() == length)) { + str = DPL::FromUTF8String(DPL::ToUTF8String(str).append("...")); + } +#endif +} + +void NormalizeString(DPL::Optional& str, const unsigned int length, +#if ENABLE(ADD_ELLIPSIS) + bool showEllipsis +#else + bool /*showEllipsis*/ +#endif + ) +{ +#if ENABLE(ADD_ELLIPSIS) + bool hasExceededMaxLength = false; + if (!!str) { + if ((*str).size() > length) { + hasExceededMaxLength = true; + (*str).resize(length); + } +#else + if (!!str) { + if ((*str).size() > length) { + (*str).resize(length); + } +#endif + + NormalizeString(str); +#if ENABLE(ADD_ELLIPSIS) + if (showEllipsis && hasExceededMaxLength && ((*str).size() == length)) { + str = DPL::FromUTF8String(DPL::ToUTF8String(*str).append("...")); + } +#endif + } +} + +void NormalizeAndTrimSpaceString(DPL::OptionalString& str, const unsigned int length) +{ + if (!!str) { + if ((*str).size() > length) { + (*str).resize(length); + } + NormalizeString(str, true); + } +} +#endif //ELEMENT_ATTR_MAX_LENGTH + +bool ConfigParserData::Feature::operator==(const Feature& other) const +{ + return name == other.name; +} + +bool ConfigParserData::Feature::operator!=(const Feature& other) const +{ + return name != other.name; +} + +bool ConfigParserData::Feature::operator >(const Feature& other) const +{ + return name > other.name; +} + +bool ConfigParserData::Feature::operator>=(const Feature& other) const +{ + return name >= other.name; +} + +bool ConfigParserData::Feature::operator <(const Feature& other) const +{ + return name < other.name; +} + +bool ConfigParserData::Feature::operator<=(const Feature& other) const +{ + return name <= other.name; +} + +bool ConfigParserData::Privilege::operator==(const Privilege& other) const +{ + return name == other.name; +} + +bool ConfigParserData::Privilege::operator!=(const Privilege& other) const +{ + return name != other.name; +} + +bool ConfigParserData::Privilege::operator >(const Privilege& other) const +{ + return name > other.name; +} + +bool ConfigParserData::Privilege::operator>=(const Privilege& other) const +{ + return name >= other.name; +} + +bool ConfigParserData::Privilege::operator <(const Privilege& other) const +{ + return name < other.name; +} + +bool ConfigParserData::Privilege::operator<=(const Privilege& other) const +{ + return name <= other.name; +} + +bool ConfigParserData::Icon::operator==(const Icon& other) const +{ + return src == other.src && isSmall == other.isSmall; +} + +bool ConfigParserData::Icon::operator!=(const Icon& other) const +{ + return src != other.src || isSmall != other.isSmall; +} + +bool ConfigParserData::Icon::operator >(const Icon& other) const +{ + return src > other.src; +} + +bool ConfigParserData::Icon::operator>=(const Icon& other) const +{ + return operator >(other) || operator==(other); +} + +bool ConfigParserData::Icon::operator <(const Icon& other) const +{ + return src < other.src; +} + +bool ConfigParserData::Icon::operator<=(const Icon& other) const +{ + return operator<(other) || operator==(other); +} + +bool ConfigParserData::Preference::operator==(const Preference& other) const +{ + return name == other.name; +} + +bool ConfigParserData::Preference::operator!=(const Preference& other) const +{ + return name != other.name; +} + +bool ConfigParserData::Preference::operator >(const Preference& other) const +{ + return name > other.name; +} + +bool ConfigParserData::Preference::operator>=(const Preference& other) const +{ + return name >= other.name; +} + +bool ConfigParserData::Preference::operator <(const Preference& other) const +{ + return name < other.name; +} + +bool ConfigParserData::Preference::operator<=(const Preference& other) const +{ + return name <= other.name; +} + +bool ConfigParserData::AccessInfo::operator== (const AccessInfo& info) const +{ + return m_strIRI == info.m_strIRI && m_bSubDomainAccess == + info.m_bSubDomainAccess; +} + +bool ConfigParserData::AccessInfo::operator!= (const AccessInfo& info) const +{ + return !(*this == info); +} + +bool ConfigParserData::AccessInfo::operator <(const AccessInfo& info) const +{ + if (m_strIRI == info.m_strIRI) { + return m_bSubDomainAccess < info.m_bSubDomainAccess; + } else { + return m_strIRI < info.m_strIRI; + } +} + +bool ConfigParserData::Setting::operator==(const Setting& other) const +{ + return m_name == other.m_name && + m_value == other.m_value; +} + +bool ConfigParserData::Setting::operator!=(const Setting& other) const +{ + return !(*this == other); +} + +bool ConfigParserData::Setting::operator >(const Setting& other) const +{ + return m_name > other.m_name; +} + +bool ConfigParserData::Setting::operator>=(const Setting& other) const +{ + return m_name >= other.m_name; +} + +bool ConfigParserData::Setting::operator <(const Setting& other) const +{ + return m_name < other.m_name; +} + +bool ConfigParserData::Setting::operator<=(const Setting& other) const +{ + return m_name <= other.m_name; +} + +bool ConfigParserData::AppControlInfo::operator== (const AppControlInfo& info) const +{ + return m_src == info.m_src && + m_operation == info.m_operation && + m_uriList == info.m_uriList && + m_mimeList == info.m_mimeList && + m_disposition == info.m_disposition; +} + +bool ConfigParserData::AppControlInfo::operator!= (const AppControlInfo& info) const +{ + return !(*this == info); +} + +bool ConfigParserData::LiveboxInfo::operator==(const LiveboxInfo& other) const +{ + return m_liveboxId == other.m_liveboxId && + m_autoLaunch == other.m_autoLaunch && + m_updatePeriod == other.m_updatePeriod && + m_primary == other.m_primary && + m_label == other.m_label && + m_icon == other.m_icon; +} + +bool ConfigParserData::LiveboxInfo::operator!=(const LiveboxInfo& other) const +{ + return !(*this == other); +} + +bool ConfigParserData::Metadata::operator== (const Metadata& other) const +{ + return key == other.key && value == other.value; +} + +bool ConfigParserData::Metadata::operator!= (const Metadata& other) const +{ + return !(*this == other); +} +} // namespace WrtDB diff --git a/modules/widget_dao/dao/feature_dao.cpp b/modules/widget_dao/dao/feature_dao.cpp new file mode 100644 index 0000000..15cd23f --- /dev/null +++ b/modules/widget_dao/dao/feature_dao.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the definition of feature dao class. + * + * @file widget_dao.cpp + * @author Jaroslaw Osmanski (j.osmanski@samsung.com) + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the definition of feature configuration. + */ +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +namespace FeatureDAO { +FeatureHandle RegisterFeature(const PluginMetafileData::Feature &feature, + const DbPluginHandle pluginHandle) +{ + Try + { + LogDebug("Registering Feature " << feature.m_name); + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + if (FeatureDAOReadOnly::isFeatureInstalled(feature.m_name)) { + LogError(" >> Feature " << feature.m_name << + " is already registered."); + transaction.Commit(); + return -1; + } + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + //register feature + { + LogDebug(" |-- Registering feature " << feature.m_name); + + FeaturesList::Row row; + row.Set_FeatureName(DPL::FromUTF8String(feature.m_name)); + row.Set_PluginPropertiesId(pluginHandle); + + WRT_DB_INSERT(insert, FeaturesList, &WrtDatabase::interface()) + insert->Values(row); + insert->Execute(); + } + + FeatureHandle featureHandle = + FeatureDAOReadOnly(feature.m_name).GetFeatureHandle(); + + //register device capabilities + // Device Capabilities is unused in current version + FOREACH(itdev, feature.m_deviceCapabilities) + { + int deviceCapID; + + if (FeatureDAOReadOnly::isDeviceCapabilityInstalled(*itdev)) { + LogDebug(" | |--DeviceCap " << *itdev << + " already installed!"); + + WRT_DB_SELECT(select, + DeviceCapabilities, + &WrtDatabase::interface()) + + select->Where(Equals( + DPL::FromUTF8String(*itdev))); + + deviceCapID = + select->GetSingleValue(); + } else { + LogDebug(" | |--Register DeviceCap: " << *itdev); + + DeviceCapabilities::Row row; + row.Set_DeviceCapName(DPL::FromUTF8String(*itdev)); + + WRT_DB_INSERT(insert, + DeviceCapabilities, + &WrtDatabase::interface()) + insert->Values(row); + deviceCapID = static_cast(insert->Execute()); + } + + FeatureDeviceCapProxy::Row row; + row.Set_FeatureUUID(featureHandle); + row.Set_DeviceCapID(deviceCapID); + + WRT_DB_INSERT(insert, + FeatureDeviceCapProxy, + &WrtDatabase::interface()) + insert->Values(row); + insert->Execute(); + } + + transaction.Commit(); + + return featureHandle; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during Registering Feature"); + } +} + +void UnregisterFeature(FeatureHandle featureHandle) +{ + Try + { + LogDebug("Unregistering Feature " << featureHandle); + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + if (!FeatureDAOReadOnly::isFeatureInstalled(featureHandle)) { + LogError("Feature handle is invalid"); + return; + } + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + // Unregister DeviceCapabilities + FeatureDAOReadOnly::DeviceCapabilitiesList capabilitiesList = + FeatureDAOReadOnly(featureHandle).GetDeviceCapabilities(); + + FOREACH(it, capabilitiesList) { + WRT_DB_DELETE(del, DeviceCapabilities, &WrtDatabase::interface()) + del->Where( + Equals( + DPL::FromUTF8String(*it))); + del->Execute(); + } + + // Unregister Feature + WRT_DB_DELETE(del, FeaturesList, &WrtDatabase::interface()) + del->Where(Equals(featureHandle)); + del->Execute(); + transaction.Commit(); + + return; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Fail to unregister Feature"); + } +} +} // namespace FeatureDAO +} // namespace WrtDB diff --git a/modules/widget_dao/dao/feature_dao_read_only.cpp b/modules/widget_dao/dao/feature_dao_read_only.cpp new file mode 100644 index 0000000..ee188bd --- /dev/null +++ b/modules/widget_dao/dao/feature_dao_read_only.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file feature_dao_read_only.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the implementation of feature dao read only + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +FeatureDAOReadOnly::FeatureDAOReadOnly(FeatureHandle featureHandle) : + m_featureHandle(featureHandle) +{ + if (!isFeatureInstalled(m_featureHandle)) { + std::ostringstream exc; + exc << "Feature " << m_featureHandle << " not installed."; + LogError(exc.str()); + ThrowMsg(FeatureDAOReadOnly::Exception::FeatureNotExist, exc.str()); + } +} + +FeatureDAOReadOnly::FeatureDAOReadOnly(const std::string &featureName) +{ + LogDebug("FeatureDAOReadOnly ( " << featureName << " )"); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(Equals( + DPL::FromUTF8String(featureName))); + + m_featureHandle = select->GetSingleValue(); + LogDebug(" >> FeatureHandle retrieved: " << m_featureHandle); + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during creating FeatureDAOReadOnly"); + } +} + +#define GET_PLUGIN_DATA(func) \ + Try { \ + DPL::DB::ORM::wrt::ScopedTransaction transaction( \ + &WrtDatabase::interface()); \ + LogDebug(#func << ". FeatureHandle: " << m_featureHandle); \ + std::string ret = PluginDAOReadOnly(GetPluginHandle()).func(); \ + transaction.Commit(); \ + return ret; \ + } \ + Catch(DPL::DB::SqlConnection::Exception::Base) { \ + std::ostringstream failure("Failure during "); \ + failure << #func; \ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, \ + failure.str()); \ + } + +std::string FeatureDAOReadOnly::GetLibraryPath() const +{ + GET_PLUGIN_DATA(getLibraryPath) +} + +std::string FeatureDAOReadOnly::GetLibraryName() const +{ + GET_PLUGIN_DATA(getLibraryName) +} + +#undef GET_PLUGIN_DATA + +FeatureHandle FeatureDAOReadOnly::GetFeatureHandle() const +{ + return m_featureHandle; +} + +std::string FeatureDAOReadOnly::GetName() const +{ + LogDebug("Getting Feature Name. Handle: " << m_featureHandle); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(Equals(m_featureHandle)); + + std::string ret = DPL::ToUTF8String( + select->GetSingleValue< FeaturesList::FeatureName>()); + + LogDebug(" >> Feature name: " << ret); + return ret; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting GetName"); + } +} + +DbPluginHandle FeatureDAOReadOnly::GetPluginHandle() const +{ + LogDebug("Getting Plugin handle. FHandle: " << m_featureHandle); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(Equals(m_featureHandle)); + + DbPluginHandle pluginHandle = + select->GetSingleValue< FeaturesList::PluginPropertiesId>(); + + LogDebug(" >> Plugin Handle: " << pluginHandle); + return pluginHandle; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting Plugin Handle"); + } +} + +FeatureHandleList FeatureDAOReadOnly::GetHandleList() +{ + LogDebug("Getting FeatureHandle list."); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + + FeatureHandleList ret = + select->GetValueList(); + + std::ostringstream handles; + FOREACH(it, ret) + handles << *it << " "; + LogDebug(" >> FeatureHandle list retrieved: (" << handles << ")"); + + return ret; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting FeatureHandle list"); + } +} + +bool FeatureDAOReadOnly::isFeatureInstalled(const std::string &featureName) +{ + LogDebug("Check if Feature is installed. Name: " << featureName); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(Equals( + DPL::FromUTF8String(featureName))); + + FeaturesList::Select::RowList rows = select->GetRowList(); + + bool flag = !rows.empty(); + LogDebug(" >> Feature " << featureName << + (flag ? " found." : " not found.")); + + return flag; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during checking if Feature is installed"); + } +} + +bool FeatureDAOReadOnly::isFeatureInstalled(FeatureHandle handle) +{ + LogDebug("Check if Feature is installed. Handle: " << handle); + Try + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(Equals(handle)); + + FeaturesList::Select::RowList rows = select->GetRowList(); + + bool flag = !rows.empty(); + LogDebug(" >> Feature " << handle << + (flag ? " found." : " not found.")); + + return flag; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during checking if Feature is installed"); + } +} + +bool FeatureDAOReadOnly::isDeviceCapabilityInstalled( + const std::string &deviceCapName) +{ + LogDebug("Check if DeviceCap is installed. Name: " << deviceCapName); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, DeviceCapabilities, &WrtDatabase::interface()) + select->Where(Equals( + DPL::FromUTF8String(deviceCapName))); + + DeviceCapabilities::Select::RowList rows = select->GetRowList(); + + bool flag = !rows.empty(); + LogDebug(" >> Device Cap " << deviceCapName << + (flag ? "found." : "not found.")); + + return flag; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during checking if DeviceCap is installed"); + } +} + +FeatureDAOReadOnly::DeviceCapabilitiesList +FeatureDAOReadOnly::GetDeviceCapabilities() const +{ + Try { + LogDebug("Get DeviceCap. FeatureHandle: " << m_featureHandle); + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(selectDevCP, + FeatureDeviceCapProxy, + &WrtDatabase::interface()) + selectDevCP->Where(Equals( + m_featureHandle)); + + DeviceCapabilitiesList devCap; + + std::list deviceIDs = + selectDevCP->GetValueList(); + FOREACH(devCId, deviceIDs) + { + WRT_DB_SELECT(selectDevC, + DeviceCapabilities, + &WrtDatabase::interface()) + selectDevC->Where(Equals(*devCId)); + + DPL::String devNames = + selectDevC->GetSingleValue(); + + devCap.insert(DPL::ToUTF8String(devNames)); + } + + transaction.Commit(); + return devCap; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting DeviceCapabilities names"); + } +} + +FeatureHandleListPtr FeatureDAOReadOnly::GetFeatureHandleListForPlugin( + DbPluginHandle pluginHandle) +{ + LogDebug("Getting FeatureHandle list for pluginHandle: " << pluginHandle); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(Equals(pluginHandle)); + + FeatureHandleListPtr handles(new FeatureHandleList); + FeatureHandleList ret = + select->GetValueList(); + + FOREACH(it, ret) + { + LogDebug("feature handle: " << *it); + handles->push_back(*it); + } + + return handles; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg( + FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting FeatureHandle Set for plugin handle"); + } +} + +FeatureDAOReadOnly::NameMap +FeatureDAOReadOnly::GetNames() +{ + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + + NameMap nameMap; + + FeaturesList::Select::RowList rows = select->GetRowList(); + FOREACH(rowIt, rows) + { + nameMap.insert(std::pair(rowIt->Get_FeatureUUID(), + DPL::ToUTF8String(rowIt-> + Get_FeatureName()))); + } + + return nameMap; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting GetNames"); + } +} + +FeatureDAOReadOnly::DeviceCapabilitiesMap +FeatureDAOReadOnly::GetDevCapWithFeatureHandle() +{ + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + DECLARE_COLUMN_TYPE_LIST() + SELECTED_COLUMN(FeatureDeviceCapProxy, FeatureUUID) + SELECTED_COLUMN(DeviceCapabilities, DeviceCapName) + DECLARE_COLUMN_TYPE_LIST_END(DevCapNameList) + + WRT_DB_SELECT(select, FeatureDeviceCapProxy, &WrtDatabase::interface()) + select->Join(Equal()); + + DeviceCapabilitiesMap devCap; + + std::list< CustomRow > rowList = + select->GetCustomRowList< DevCapNameList, CustomRow >(); + FOREACH(rowIt, rowList) + { + FeatureHandle featureHandle = + (*rowIt).GetColumnData(); + std::string devName = + DPL::ToUTF8String((*rowIt).GetColumnData()); + devCap.insert(std::pair(featureHandle, + devName)); + } + + return devCap; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting DeviceCapabilities names"); + } +} + +DeviceCapabilitySet FeatureDAOReadOnly::GetDeviceCapability( + const DPL::String &apifeature) +{ + // This could be done with one simply sql query but support for join is + // needed in orm. + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + int featureUUID; + FeatureDeviceCapProxy::Select::RowList rows; + DeviceCapabilitySet result; + + { + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(Equals(apifeature)); + featureUUID = select->GetSingleValue(); + } + + { + WRT_DB_SELECT(select, + FeatureDeviceCapProxy, + &WrtDatabase::interface()) + select->Where(Equals( + featureUUID)); + rows = select->GetRowList(); + } + + FOREACH(it, rows){ + WRT_DB_SELECT(select, DeviceCapabilities, &WrtDatabase::interface()) + select->Where(Equals( + it->Get_DeviceCapID())); + result.insert(select-> + GetSingleValue()); + } + + return result; + } Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failed to get device capability"); + } +} + +FeatureDAOReadOnly::FeatureMap +FeatureDAOReadOnly::GetFeatures(const std::list& featureNames) +{ + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + std::set nameList; + FOREACH(nm, featureNames) { + nameList.insert(DPL::FromUTF8String(*nm)); + } + + WRT_DB_SELECT(select, FeaturesList, &WrtDatabase::interface()) + select->Where(In(nameList)); + + FeatureMap featureMap; + FeatureData featureData; + FeaturesList::Select::RowList rows = select->GetRowList(); + FOREACH(rowIt, rows) { + featureData.featureName = DPL::ToUTF8String( + rowIt->Get_FeatureName()); + featureData.pluginHandle = rowIt->Get_PluginPropertiesId(); + featureMap.insert(std::pair( + rowIt->Get_FeatureUUID(), featureData)); + } + + return featureMap; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(FeatureDAOReadOnly::Exception::DatabaseError, + "Failure during getting GetFeatures"); + } +} +} // namespace WrtDB diff --git a/modules/widget_dao/dao/path_builder.cpp b/modules/widget_dao/dao/path_builder.cpp new file mode 100644 index 0000000..ab55476 --- /dev/null +++ b/modules/widget_dao/dao/path_builder.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file PathBuilder.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief Implementation file for PathBuilde class. + */ +#include +#include +#include + +namespace WrtDB { +namespace { +const char PATH_SEPARATOR = '/'; +} + +class PathBuilderImpl : DPL::Noncopyable +{ + public: + PathBuilderImpl() + {} + + explicit PathBuilderImpl(const std::string& path) : + m_stream(path, std::ios_base::app) + {} + + void Append(const std::string& path) + { + // TODO Check additionally if last char is not separator. + if (m_stream.tellp() > 0) { + m_stream << PATH_SEPARATOR; + } + m_stream << path; + } + + void Concat(const std::string& arg) + { + m_stream << arg; + } + + void Concat(int arg) + { + m_stream << arg; + } + + void Reset() + { + m_stream.clear(); + m_stream.str(""); + } + + bool Empty() + { + return (m_stream.tellp() == 0); + } + + std::string GetFullPath() const + { + return m_stream.str(); + } + + private: + std::ostringstream m_stream; +}; + +PathBuilder::PathBuilder() : m_impl(new PathBuilderImpl()) +{} + +PathBuilder::PathBuilder(const std::string& path) : + m_impl(new PathBuilderImpl(path)) +{} + +PathBuilder::~PathBuilder() +{ + delete m_impl; +} + +PathBuilder& PathBuilder::Append(const std::string& path) +{ + m_impl->Append(path); + return *this; +} + +PathBuilder& PathBuilder::Concat(const std::string& arg) +{ + m_impl->Concat(arg); + return *this; +} + +PathBuilder& PathBuilder::Concat(int arg) +{ + m_impl->Concat(arg); + return *this; +} + +PathBuilder& PathBuilder::Reset() +{ + m_impl->Reset(); + return *this; +} + +bool PathBuilder::Empty() const +{ + return m_impl->Empty(); +} + +std::string PathBuilder::GetFullPath() const +{ + return m_impl->GetFullPath(); +} +} // namespace WrtDB diff --git a/modules/widget_dao/dao/plugin_dao.cpp b/modules/widget_dao/dao/plugin_dao.cpp new file mode 100644 index 0000000..5b899c3 --- /dev/null +++ b/modules/widget_dao/dao/plugin_dao.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file plugin_dao.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @author Grzegorz Krawczyk (g.krawczyk@samsung.com) + * @version 1.0 + * @brief This file contains the definition of plugin dao class. + */ +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +PluginDAO::PluginDAO(DbPluginHandle pluginHandle) : + PluginDAOReadOnly(pluginHandle) +{} + +PluginDAO::PluginDAO(const std::string &libraryName) : + PluginDAOReadOnly(libraryName) +{} + +DbPluginHandle PluginDAO::registerPlugin(const PluginMetafileData& metafile, + const std::string& pluginPath) +{ + LogDebug("Registering plugin. Path: " << pluginPath); + + Try { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + DbPluginHandle handle; + + if (isPluginInstalled(metafile.m_libraryName)) { + handle = PluginDAO(metafile.m_libraryName).getPluginHandle(); + LogDebug(" >> Library " << metafile.m_libraryName << + " is already registered. Handle: " << handle); + } else { + LogDebug("Register Plugin: " << metafile.m_libraryName); + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + typedef PluginProperties::Row PluginPropertiesRow; + + PluginPropertiesRow row; + row.Set_PluginLibraryName( + DPL::FromUTF8String(metafile.m_libraryName)); + row.Set_InstallationState(INSTALLATION_IN_PROGRESS); + row.Set_PluginLibraryPath( + DPL::FromUTF8String(pluginPath)); + + WRT_DB_INSERT(insert, PluginProperties, &WrtDatabase::interface()) + insert->Values(row); + handle = static_cast(insert->Execute()); + LogDebug(" >> Plugin Registered. Handle: " << handle); + } + transaction.Commit(); + return handle; + } + Catch(DPL::DB::SqlConnection::Exception::Base) + { + ReThrowMsg(PluginDAO::Exception::DatabaseError, + "Failed in RegisterPlugin"); + } +} + +void PluginDAO::registerPluginImplementedObject(const std::string& objectName, + DbPluginHandle pluginHandle) +{ + LogDebug("Registering plugin object: " << objectName); + + Try { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + LogDebug("Register Object: " << objectName); + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + typedef PluginImplementedObjects::Row PluginObjectsRow; + + PluginObjectsRow row; + row.Set_PluginObject(DPL::FromUTF8String(objectName)); + row.Set_PluginPropertiesId(pluginHandle); + + WRT_DB_INSERT(insert, PluginImplementedObjects, &WrtDatabase::interface()) + insert->Values(row); + insert->Execute(); + transaction.Commit(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) + { + ReThrowMsg(PluginDAO::Exception::DatabaseError, + "Failed in RegisterPluginObject"); + } +} + +void PluginDAO::registerPluginRequiredObject(const std::string& objectName, + DbPluginHandle pluginHandle) +{ + LogDebug("Registering plugin object: " << objectName); + + Try { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + LogDebug("Register Object: " << objectName); + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + typedef PluginRequiredObjects::Row PluginObjectsRow; + + PluginObjectsRow row; + row.Set_PluginPropertiesId(pluginHandle); + row.Set_PluginObject(DPL::FromUTF8String(objectName)); + + WRT_DB_INSERT(insert, PluginRequiredObjects, &WrtDatabase::interface()) + insert->Values(row); + insert->Execute(); + transaction.Commit(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) + { + ReThrowMsg(PluginDAO::Exception::DatabaseError, + "Failed in RegisterPluginObject"); + } +} + +void PluginDAO::registerPluginLibrariesDependencies( + DbPluginHandle pluginHandle, + const PluginHandleSetPtr& dependencies) +{ + LogDebug("Registering plugin library dependencies: " << pluginHandle); + + Try { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + typedef PluginDependencies::Row PluginDependeciesRow; + PluginDependeciesRow row; + + FOREACH(it, *dependencies) + { + row.Set_PluginPropertiesId(pluginHandle); + row.Set_RequiredPluginPropertiesId(*it); + + WRT_DB_INSERT(insert, PluginDependencies, &WrtDatabase::interface()) + insert->Values(row); + insert->Execute(); + transaction.Commit(); + } + } + Catch(DPL::DB::SqlConnection::Exception::Base) + { + ReThrowMsg(PluginDAO::Exception::DatabaseError, + "Failed in RegisterPluginObject"); + } +} + +void PluginDAO::setPluginInstallationStatus(DbPluginHandle pluginHandle, + PluginInstallationState state) +{ + Try { + LogDebug( + "Set installation state: " << state << " handle " << pluginHandle); + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + ScopedTransaction transaction(&WrtDatabase::interface()); + + typedef wrt::PluginProperties::Row PluginPropertiesRow; + + PluginPropertiesRow row; + row.Set_InstallationState(state); + + WRT_DB_UPDATE(update, PluginProperties, &WrtDatabase::interface()) + update->Where( + Equals(pluginHandle)); + + update->Values(row); + update->Execute(); + transaction.Commit(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) + { + ReThrowMsg(PluginDAO::Exception::DatabaseError, + "Failed in RegisterLibraryDependencies"); + } +} + +void PluginDAO::unregisterPlugin(DbPluginHandle pluginHandle) +{ + LogDebug("unregisterPlugin plugin. Handle: " << pluginHandle); + + Try { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + if (!isPluginInstalled(pluginHandle)) { + LogDebug("PluginHandle is invalid. Handle: " << pluginHandle); + return; + } else { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WRT_DB_DELETE(del, PluginProperties, &WrtDatabase::interface()) + del->Where( + Equals(pluginHandle)); + del->Execute(); + + transaction.Commit(); + LogDebug(" >> Plugin Unregistered. Handle: " << pluginHandle); + } + } + Catch(DPL::DB::SqlConnection::Exception::Base) + { + ReThrowMsg(PluginDAO::Exception::DatabaseError, + "Failed in UnregisterPlugin"); + } +} +} // namespace WrtDB diff --git a/modules/widget_dao/dao/plugin_dao_read_only.cpp b/modules/widget_dao/dao/plugin_dao_read_only.cpp new file mode 100644 index 0000000..a90e013 --- /dev/null +++ b/modules/widget_dao/dao/plugin_dao_read_only.cpp @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file plugin_dao_read_only.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the implementation of plugin dao read only + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +namespace { +typedef DPL::DB::ORM::wrt::PluginProperties::Row PluginRow; + +PluginRow getPluginRow(DbPluginHandle pluginHandle) +{ + LogDebug("Getting plugin row. Handle: " << pluginHandle); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + select->Where(Equals( + pluginHandle)); + + PluginProperties::Select::RowList rows = select->GetRowList(); + if (rows.empty()) { + ThrowMsg(PluginDAOReadOnly::Exception::PluginNotExist, + "Cannot find plugin. Handle: " + pluginHandle); + } + return rows.front(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetPluginRow"); + } +} +} + +PluginDAOReadOnly::PluginDAOReadOnly(DbPluginHandle pluginHandle) : + m_pluginHandle(pluginHandle) +{ + if (!isPluginInstalled(m_pluginHandle)) { + LogError("Plugin " << m_pluginHandle << " not installed."); + Throw(PluginDAOReadOnly::Exception::PluginNotExist); + } + + checkInstallationCompleted(); +} + +PluginDAOReadOnly::PluginDAOReadOnly(const std::string &libraryName) +{ + LogDebug("PluginDAOReadOnly ( " << libraryName << " )"); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + select->Where(Equals( + DPL::FromUTF8String(libraryName))); + + PluginProperties::Select::RowList rows = select->GetRowList(); + if (!rows.empty()) { + m_pluginHandle = rows.front().Get_PluginPropertiesId(); + } else { + ThrowMsg(PluginDAOReadOnly::Exception::PluginNotExist, + "Cannot find plugin: [" + libraryName + "]"); + } + LogDebug(" >> Handle for this plugin: " << m_pluginHandle); + + checkInstallationCompleted(); + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed to connect to database"); + } +} + +void PluginDAOReadOnly::checkInstallationCompleted() +{ + if (getInstallationStateForHandle(m_pluginHandle) + != PluginDAOReadOnly::INSTALLATION_COMPLETED) + { + LogError("Plugin " << m_pluginHandle << " installation not completed"); + Throw(PluginDAOReadOnly::Exception::PluginInstallationNotCompleted); + } +} + +bool PluginDAOReadOnly::isPluginInstalled(const std::string &libraryName) +{ + LogDebug("Check if Library is installed. LibraryName: " << libraryName); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + select->Where(Equals( + DPL::FromUTF8String(libraryName))); + + PluginProperties::Select::RowList rows = select->GetRowList(); + + bool flag = !rows.empty(); + LogDebug(" >> Plugin " << libraryName << + (flag ? " found." : " not found.")); + + return flag; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in isPluginInstalled"); + } +} + +PluginHandleList PluginDAOReadOnly::getPluginHandleList() +{ + LogDebug("Getting plugin handle list."); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + + PluginHandleList ret = + select->GetValueList(); + + std::ostringstream handles; + FOREACH(it, ret) + handles << *it << " "; + LogDebug(" >> PluginHandle list retrieved: (" << handles << ")"); + + return ret; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetPluginHandleList"); + } +} + +PluginHandleList PluginDAOReadOnly::getRootPluginHandleList() +{ + LogDebug("Getting root plugin handle list."); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + PluginHandleList handleList = select->GetValueList(); + + WRT_DB_SELECT(select_2nd, PluginDependencies, &WrtDatabase::interface()) + PluginDependencies::Select::RowList dependenciesRows = select_2nd->GetRowList(); + + if (!dependenciesRows.empty()) + { + FOREACH(it, dependenciesRows) + { + handleList.remove(it->Get_PluginPropertiesId()); + } + } + + return handleList; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in getRootPluginHandleList"); + } +} + +DbPluginHandle PluginDAOReadOnly::getPluginHandle() const +{ + return m_pluginHandle; +} + +//"value" cannot be null, as in registerPlugin it is always set +#define RETURN_STD_STRING(in, what) \ + std::string ret = ""; \ + if (!in.IsNull()) { \ + ret = DPL::ToUTF8String(*in); } \ + LogDebug(" >> Plugin " << what << ": " << ret); \ + return ret; + +std::string PluginDAOReadOnly::getLibraryPath() const +{ + LogDebug("Getting plugin library path. Handle: " << m_pluginHandle); + PluginRow row = getPluginRow(m_pluginHandle); + RETURN_STD_STRING(row.Get_PluginLibraryPath(), "library path") +} + +std::string PluginDAOReadOnly::getLibraryName() const +{ + LogDebug("Getting plugin library name. Handle: " << m_pluginHandle); + PluginRow row = getPluginRow(m_pluginHandle); + std::string ret = DPL::ToUTF8String(row.Get_PluginLibraryName()); + LogDebug(" >> Plugin library name: " << ret); + return ret; +} + +#undef RETURN_STD_STRING + +PluginHandleSetPtr PluginDAOReadOnly::getLibraryDependencies() const +{ + Try + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + PluginHandleSetPtr dependencies(new PluginHandleSet); + + WRT_DB_SELECT(select, PluginDependencies, &WrtDatabase::interface()) + select->Where( + Equals(m_pluginHandle)); + + PluginDependencies::Select::RowList rows = select->GetRowList(); + + if (!rows.empty()) { + FOREACH(it, rows) + { + dependencies->insert(it->Get_RequiredPluginPropertiesId()); + } + } + + return dependencies; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetLibraryDependencies"); + } +} + +DbPluginHandle PluginDAOReadOnly::getPluginHandleForImplementedObject( + const std::string& objectName) +{ + LogDebug("GetPluginHandle for object: " << objectName); + + Try + { + DbPluginHandle pluginHandle = INVALID_PLUGIN_HANDLE; + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WRT_DB_SELECT(select, PluginImplementedObjects, &WrtDatabase::interface()) + select->Where( + Equals( + DPL::FromUTF8String(objectName))); + + PluginImplementedObjects::Select::RowList rows = select->GetRowList(); + + if (!rows.empty()) { + pluginHandle = rows.front().Get_PluginPropertiesId(); + } else { + LogWarning("PluginHandle for object not found"); + } + return pluginHandle; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetPluginHandleForImplementedObject"); + } +} + +ImplementedObjectsList PluginDAOReadOnly::getImplementedObjects() +{ + LogDebug("getImplementedObjects"); + + Try + { + ImplementedObjectsList objectList; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WRT_DB_SELECT(select, PluginImplementedObjects, &WrtDatabase::interface()) + std::list valueList = select->GetValueList(); + + if (!valueList.empty()) { + FOREACH(it, valueList) + { + objectList.push_back(DPL::ToUTF8String(*it)); + } + } else { + LogWarning("PluginHandle for object not found"); + } + return objectList; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetPluginHandleForImplementedObject"); + } +} + +ImplementedObjectsList PluginDAOReadOnly::getImplementedObjectsForPluginHandle( + DbPluginHandle handle) +{ + LogDebug("getImplementedObjects for pluginHandle: " << handle); + + Try + { + ImplementedObjectsList objectList; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WRT_DB_SELECT(select, PluginImplementedObjects, &WrtDatabase::interface()) + select->Where( + Equals(handle)); + + PluginImplementedObjects::Select::RowList rows = select->GetRowList(); + + if (!rows.empty()) { + FOREACH(it, rows) + { + objectList.push_back(DPL::ToUTF8String(it->Get_PluginObject())); + } + } else { + LogWarning("PluginHandle for object not found"); + } + return objectList; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetPluginHandleForImplementedObject"); + } +} + +PluginObjectsDAO::ObjectsPtr PluginDAOReadOnly:: + getRequiredObjectsForPluginHandle( + DbPluginHandle handle) +{ + Try + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + PluginObjectsDAO::ObjectsPtr objects = + PluginObjectsDAO::ObjectsPtr(new PluginObjectsDAO::Objects); + + WRT_DB_SELECT(select, PluginRequiredObjects, &WrtDatabase::interface()) + select->Where( + Equals(handle)); + + PluginRequiredObjects::Select::RowList rows = select->GetRowList(); + + if (!rows.empty()) { + FOREACH(it, rows) + { + objects->insert(DPL::ToUTF8String(it->Get_PluginObject())); + } + } + + return objects; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetRequiredObjectsForPluginHandle"); + } +} + +PluginHandleSetPtr PluginDAOReadOnly::getPluginHandleByStatus( + PluginInstallationState state) +{ + Try + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + PluginHandleSetPtr handleSet(new PluginHandleSet); + + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + select->Where( + Equals(ToInt(state))); + + PluginProperties::Select::RowList rows = select->GetRowList(); + + if (!rows.empty()) { + FOREACH(it, rows) + { + handleSet->insert(it->Get_PluginPropertiesId()); + } + } + + return handleSet; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetPluginHandleByStatus"); + } +} + +PluginDAOReadOnly::PluginInstallationState PluginDAOReadOnly:: + getInstallationStatus() const +{ + PluginRow row = getPluginRow(m_pluginHandle); + return ToState(row.Get_InstallationState()); +} + +PluginDAOReadOnly::PluginInstallationState PluginDAOReadOnly:: + getInstallationStateForHandle( + DbPluginHandle handle) +{ + Try + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + select->Where( + Equals(handle)); + + PluginProperties::Select::RowList rows = select->GetRowList(); + + if (!rows.empty()) { + return ToState(rows.front().Get_InstallationState()); + } + LogError("Data in DB are invalid. Missing field"); + return UNKNOWN_ERROR; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in GetStatusForHandle"); + } +} + +bool PluginDAOReadOnly::isPluginInstalled(DbPluginHandle pluginHandle) +{ + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, PluginProperties, &WrtDatabase::interface()) + select->Where( + Equals(pluginHandle)); + + PluginProperties::Select::RowList rows = select->GetRowList(); + + bool flag = !rows.empty(); + + return flag; + } + Catch(DPL::DB::SqlConnection::Exception::Base) { + ReThrowMsg(PluginDAOReadOnly::Exception::DatabaseError, + "Failed in isPluginInstalled"); + } +} +} // namespace WrtDB diff --git a/modules/widget_dao/dao/property_dao.cpp b/modules/widget_dao/dao/property_dao.cpp new file mode 100644 index 0000000..fa6412a --- /dev/null +++ b/modules/widget_dao/dao/property_dao.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file property_dao.h + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the definition of property dao class. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +namespace PropertyDAO { +void RemoveProperty(TizenAppId tzAppid, + const PropertyDAOReadOnly::WidgetPropertyKey &key) +{ + //TODO below there are two queries. + // First query asks if given property can be removed, + // Second removes it. Maybe it should be combined two one. + + LogDebug("Removing Property. appid: " << tzAppid << ", key: " << key); + Try { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + DPL::OptionalInt readonly = PropertyDAOReadOnly::CheckPropertyReadFlag( + tzAppid, + key); + if (!readonly.IsNull() && *readonly == 1) { + LogError("'" << key << + "' key is readonly. Cannot remove property !"); + ThrowMsg(PropertyDAOReadOnly::Exception::ReadOnlyProperty, + "Property is readonly"); + } + + // Key is not readonly, or has no flag defined + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_DELETE(del, WidgetPreference, &WrtDatabase::interface()) + del->Where(And( + Equals(tzAppid), + Equals(key))); + del->Execute(); + + transaction.Commit(); + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(PropertyDAOReadOnly::Exception::DatabaseError, + "Failure during removing property"); + } +} + +//deprecated +void SetProperty(DbWidgetHandle widgetHandle, + const PropertyDAOReadOnly::WidgetPropertyKey &key, + const PropertyDAOReadOnly::WidgetPropertyValue &value, + bool readOnly) +{ + SetProperty(WidgetDAOReadOnly::getTizenAppId( + widgetHandle), key, value, readOnly); +} + +void SetProperty(TizenAppId tzAppid, + const PropertyDAOReadOnly::WidgetPropertyKey &key, + const PropertyDAOReadOnly::WidgetPropertyValue &value, + bool readOnly) +{ + LogDebug("Setting/updating Property. appid: " << tzAppid << + ", key: " << key); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + DPL::OptionalInt readonly = PropertyDAOReadOnly::CheckPropertyReadFlag( + tzAppid, + key); + if (!readonly.IsNull() && *readonly == 1) { + LogError("'" << key << + "' key is readonly. Cannot remove property !"); + ThrowMsg(PropertyDAOReadOnly::Exception::ReadOnlyProperty, + "Property is readonly"); + } + DbWidgetHandle widgetHandle(WidgetDAOReadOnly::getHandle(tzAppid)); + + if (readonly.IsNull()) { + WidgetPreference::Row row; + row.Set_app_id(widgetHandle); + row.Set_tizen_appid(tzAppid); + row.Set_key_name(key); + row.Set_key_value(value); + row.Set_readonly(readOnly ? 1 : 0); + + WRT_DB_INSERT(insert, WidgetPreference, &WrtDatabase::interface()) + insert->Values(row); + insert->Execute(); + } else { + WidgetPreference::Row row; + row.Set_key_value(value); + + WRT_DB_UPDATE(update, WidgetPreference, &WrtDatabase::interface()) + update->Where(And( + Equals(tzAppid), + Equals(key))); + + update->Values(row); + update->Execute(); + } + transaction.Commit(); + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(PropertyDAOReadOnly::Exception::DatabaseError, + "Failure during setting/updating property"); + } +} + +void RegisterProperties(DbWidgetHandle widgetHandle, TizenAppId tzAppid, + const WidgetRegisterInfo ®Info) +{ + LogDebug("Registering proferences for widget. appid: " << tzAppid); + + // Try-Catch in WidgetDAO + + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + const ConfigParserData& widgetConfigurationInfo = regInfo.configInfo; + + FOREACH(it, widgetConfigurationInfo.preferencesList) + { + { // Insert into table Widget Preferences + WidgetPreference::Row row; + row.Set_app_id(widgetHandle); + row.Set_tizen_appid(tzAppid); + row.Set_key_name(it->name); + row.Set_key_value(it->value); + int readonly = true == it->readonly ? 1 : 0; + row.Set_readonly(readonly); + + WRT_DB_INSERT(insert, WidgetPreference, &WrtDatabase::interface()) + insert->Values(row); + insert->Execute(); + } + } +} +} // namespace PropertyDAO +} // namespace WrtDB diff --git a/modules/widget_dao/dao/property_dao_read_only.cpp b/modules/widget_dao/dao/property_dao_read_only.cpp new file mode 100644 index 0000000..4916ebc --- /dev/null +++ b/modules/widget_dao/dao/property_dao_read_only.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * property_dao_read_only.cpp + * + * Created on: Nov 16, 2011 + * Author: Krzysztof Jackiewicz(k.jackiewicz@samsung.com) + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +namespace PropertyDAOReadOnly { +namespace { +typedef DPL::DB::ORM::wrt::WidgetPreference::key_name::ColumnType +ORMWidgetPropertyKey; +typedef DPL::DB::ORM::wrt::WidgetPreference::key_value::ColumnType +ORMWidgetPropertyValue; +typedef std::list +ORMWidgetPreferenceList; +typedef std::list ORMWidgetPropertyKeyList; + +void convertPropertyKey(const ORMWidgetPropertyKey& ormKey, + WidgetPropertyKey& key) +{ + key = ormKey; +} + +void convertPropertyValue(const ORMWidgetPropertyValue& ormPropertyVal, + WidgetPropertyValue& propertyVal) +{ + propertyVal = ormPropertyVal; +} + +void convertWidgetPreferenceRow(const ORMWidgetPreferenceList& ormWidgetPrefRow, + WidgetPreferenceList& prefRow) +{ + FOREACH(it, ormWidgetPrefRow) { + WidgetPreferenceRow row; + + row.appId = it->Get_app_id(); + row.tizen_appid = it->Get_tizen_appid(); + row.key_name = it->Get_key_name(); + row.key_value = it->Get_key_value(); + row.readonly = it->Get_readonly(); + + prefRow.push_back(row); + } +} + +void convertWidgetPropertyKeyList(const ORMWidgetPropertyKeyList& propKeyList, + WidgetPropertyKeyList& keyList) +{ + FOREACH(it, propKeyList) { + keyList.push_back(*it); + } +} + +WidgetPreferenceList GetPropertyListRows(DbWidgetHandle widgetHandle) +{ + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, WidgetPreference, &WrtDatabase::interface()) + select->Where(Equals(widgetHandle)); + ORMWidgetPreferenceList ormPrefList = select->GetRowList(); + WidgetPreferenceList prefList; + convertWidgetPreferenceRow(ormPrefList, prefList); + return prefList; + }Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(Exception::DatabaseError, + "Failure during getting property list"); + } +} +} + +//deprecated +DPL::OptionalInt CheckPropertyReadFlag(DbWidgetHandle widgetHandle, + const WidgetPropertyKey &key) +{ + return CheckPropertyReadFlag(WidgetDAOReadOnly::getTizenAppId(widgetHandle), + key); +} + +DPL::OptionalInt CheckPropertyReadFlag(TizenAppId tzAppid, + const WidgetPropertyKey &key) +{ + LogDebug("Checking Property flag. appid: " << tzAppid << + ", key: " << key); + + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + DbWidgetHandle widgetHandle(WidgetDAOReadOnly::getHandle(tzAppid)); + + WRT_DB_SELECT(select, WidgetPreference, &WrtDatabase::interface()) + select->Where(And(Equals(widgetHandle), + Equals(key))); + + return select->GetSingleValue(); + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(Exception::DatabaseError, + "Failure during checking readonly flag for property"); + } +} + +WidgetPropertyKeyList GetPropertyKeyList(TizenAppId tzAppid) +{ + LogDebug("Get PropertyKey list. appid: " << tzAppid); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + DbWidgetHandle widgetHandle(WidgetDAOReadOnly::getHandle(tzAppid)); + + ORMWidgetPropertyKeyList keyList; + WRT_DB_SELECT(select, WidgetPreference, &WrtDatabase::interface()) + select->Where(Equals(widgetHandle)); + keyList = select->GetValueList(); + + WidgetPropertyKeyList retKeyList; + + convertWidgetPropertyKeyList(keyList, retKeyList); + return retKeyList; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(Exception::DatabaseError, + "Failure during getting propertykey list"); + } +} + +WidgetPreferenceList GetPropertyList(DbWidgetHandle widgetHandle) +{ + if(!(WidgetDAOReadOnly::isWidgetInstalled(widgetHandle))) + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget"); + return GetPropertyListRows(widgetHandle); +} + +WidgetPreferenceList GetPropertyList(TizenAppId tzAppId) +{ + LogDebug("Get Property list. tizenAppId: " << tzAppId); + DbWidgetHandle widgetHandle(WidgetDAOReadOnly::getHandle(tzAppId)); + return GetPropertyListRows(widgetHandle); +} + + +WidgetPropertyValue GetPropertyValue(TizenAppId tzAppid, + const WidgetPropertyKey &key) +{ + LogDebug("Get Property value. appid: " << tzAppid << + ", key: " << key); + Try { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + DbWidgetHandle widgetHandle(WidgetDAOReadOnly::getHandle(tzAppid)); + + WRT_DB_SELECT(select, WidgetPreference, &WrtDatabase::interface()) + select->Where(And(Equals(widgetHandle), + Equals(key))); + + ORMWidgetPropertyValue ormPropValue = + select->GetSingleValue(); + + WidgetPropertyValue propValue; + + convertPropertyValue(ormPropValue, propValue); + + return propValue; + } + Catch(DPL::DB::SqlConnection::Exception::Base){ + ReThrowMsg(Exception::DatabaseError, + "Failure during getting property"); + } +} +} // namespace PropertyDAOReadOnly +} // namespace WrtDB diff --git a/modules/widget_dao/dao/webruntime_database.cpp b/modules/widget_dao/dao/webruntime_database.cpp new file mode 100644 index 0000000..5fbb7d7 --- /dev/null +++ b/modules/widget_dao/dao/webruntime_database.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file webruntime_database.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file contains the definition of webruntime database + */ +#include +#include + +DPL::Mutex g_wrtDbQueriesMutex; + diff --git a/modules/widget_dao/dao/widget_dao.cpp b/modules/widget_dao/dao/widget_dao.cpp new file mode 100755 index 0000000..487cb93 --- /dev/null +++ b/modules/widget_dao/dao/widget_dao.cpp @@ -0,0 +1,807 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the definition of widget dao class. + * + * @file widget_dao.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Bartosz Janiak (b.janiak@samsung.com) + * @author Yang Jie (jie2.yang@samsung.com) + * @author Koeun Choi(koeun.choi@samsung.com) + * @author Pawel Sikorski(p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the definition of Configuration. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +//TODO in current solution in each getter there exists a check +//"IsWidgetInstalled". Maybe it should be verified, if it could be done +//differently (check in WidgetDAO constructor) + +#define SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN Try + +#define SQL_CONNECTION_EXCEPTION_HANDLER_END(message) \ + Catch(DPL::DB::SqlConnection::Exception::Base) { \ + LogError(message); \ + ReThrowMsg(WidgetDAO::Exception::DatabaseError, \ + message); \ + } + +WidgetDAO::WidgetDAO(DPL::OptionalString widgetGUID) : + WidgetDAOReadOnly(WidgetDAOReadOnly::getHandle(widgetGUID)) +{} + +WidgetDAO::WidgetDAO(DPL::String tzAppId) : + WidgetDAOReadOnly(WidgetDAOReadOnly::getHandle(tzAppId)) +{} + +WidgetDAO::~WidgetDAO() +{} + +void WidgetDAO::setTizenAppId(const DPL::OptionalString& tzAppId) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + using namespace DPL::DB::ORM; + wrt::ScopedTransaction transaction(&WrtDatabase::interface()); + + if (!isWidgetInstalled(getHandle())) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Cannot find widget. Handle: " << getHandle()); + } + + wrt::WidgetInfo::Row row; + row.Set_tizen_appid(*tzAppId); + + WRT_DB_UPDATE(update, wrt::WidgetInfo, &WrtDatabase::interface()) + update->Where( + Equals(getHandle())); + + update->Values(row); + update->Execute(); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to register widget") +} + +void WidgetDAO::registerWidget( + const TizenAppId & tzAppId, + const WidgetRegisterInfo &widgetRegInfo, + const IWidgetSecurity &widgetSecurity) +{ + LogDebug("Registering widget"); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + registerWidgetInternal(tzAppId, widgetRegInfo, widgetSecurity); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to register widget") +} + +void WidgetDAO::registerService( + const ConfigParserData::ServiceAppInfo &serviceAppInfo, + const WidgetRegisterInfo &widgetRegInfo, + const IWidgetSecurity &widgetSecurity) +{ + LogDebug("Registering service"); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + + registerServiceInternal(serviceAppInfo, widgetRegInfo, widgetSecurity); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to register service") +} + + +TizenAppId WidgetDAO::registerWidgetGeneratePkgId( + const WidgetRegisterInfo &pWidgetRegisterInfo, + const IWidgetSecurity &widgetSecurity) +{ + TizenAppId tzAppId = generatePkgId(); + registerWidget(tzAppId, pWidgetRegisterInfo, widgetSecurity); + return tzAppId; +} + +void WidgetDAO::updateTizenAppId( + const TizenAppId & fromAppId, + const TizenAppId & toAppId) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + ScopedTransaction transaction(&WrtDatabase::interface()); + if (!isWidgetInstalled(fromAppId)) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Cannot find widget. tzAppId: " << fromAppId); + } + + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(fromAppId)); + + WidgetInfo::Row row = select->GetSingleRow(); + + //WidgetInfo::Row row; + row.Set_tizen_appid(toAppId); + + WRT_DB_UPDATE(update, WidgetInfo, &WrtDatabase::interface()) + update->Where(Equals(fromAppId)); + update->Values(row); + update->Execute(); + + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to update appid") +} + +void WidgetDAO::registerWidgetInternal( + const TizenAppId & tzAppId, + const WidgetRegisterInfo &widgetRegInfo, + const IWidgetSecurity &widgetSecurity, + const DPL::Optional handle) +{ + //Register into WidgetInfo has to be first + //as all other tables depend upon that + DbWidgetHandle widgetHandle = registerWidgetInfo(tzAppId, widgetRegInfo.tzPkgid, widgetRegInfo.baseFolder, + widgetRegInfo.webAppType.appType, widgetRegInfo.packagingType.pkgType, + widgetRegInfo.configInfo, widgetSecurity,handle); + + registerWidgetExtendedInfo(widgetHandle, widgetRegInfo.installedTime, + widgetRegInfo.configInfo.splashImgSrc, widgetRegInfo.configInfo.backgroundPage, + widgetRegInfo.widgetInstalledPath); + + registerWidgetLocalizedInfo(widgetHandle, widgetRegInfo.configInfo.localizedDataSet); + + registerWidgetIcons(widgetHandle, widgetRegInfo.localizationData.icons); + + registerWidgetStartFile(widgetHandle, widgetRegInfo.localizationData.startFiles); + + PropertyDAO::RegisterProperties(widgetHandle, tzAppId, widgetRegInfo); + + registerWidgetFeatures(widgetHandle, widgetRegInfo.configInfo.featuresList); + + registerWidgetPrivilege(widgetHandle, widgetRegInfo.configInfo.privilegeList); + + registerWidgetWindowModes(widgetHandle, widgetRegInfo.configInfo.windowModes); + + registerWidgetWarpInfo(widgetHandle, widgetRegInfo.configInfo.accessInfoSet); + + registerWidgetAllowNavigationInfo(widgetHandle, widgetRegInfo.configInfo.allowNavigationInfoList); + + registerWidgetCertificates(widgetHandle, widgetSecurity); + + CertificateChainList list; + widgetSecurity.getCertificateChainList(list, SIGNATURE_DISTRIBUTOR); + registerCertificatesChains(widgetHandle, SIGNATURE_DISTRIBUTOR, list); + + list.clear(); + widgetSecurity.getCertificateChainList(list, SIGNATURE_DISTRIBUTOR2); + registerCertificatesChains(widgetHandle, SIGNATURE_DISTRIBUTOR2, list); + + list.clear(); + widgetSecurity.getCertificateChainList(list, SIGNATURE_AUTHOR); + registerCertificatesChains(widgetHandle, SIGNATURE_AUTHOR, list); + + registerWidgetSettings(widgetHandle, widgetRegInfo.configInfo.settingsList); + + registerAppControl(widgetHandle, widgetRegInfo.configInfo.appControlList); + + registerEncryptedResouceInfo(widgetHandle, widgetRegInfo.encryptedFiles); + + registerExternalLocations(widgetHandle, widgetRegInfo.externalLocations); +} + +#define DO_INSERT(row, table) \ + { \ + WRT_DB_INSERT(insert, table, &WrtDatabase::interface()) \ + insert->Values(row); \ + insert->Execute(); \ + } + +void WidgetDAO::registerWidgetExtendedInfo(DbWidgetHandle widgetHandle, + time_t installedTime, + const DPL::OptionalString & splashImgSrc, const DPL::OptionalString & backgroundPage, + const DPL::OptionalString & widgetInstalledPath) +{ + //Try and transaction not needed + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + WidgetExtendedInfo::Row row; + row.Set_app_id(widgetHandle); + row.Set_install_time(installedTime); + row.Set_splash_img_src(splashImgSrc); + row.Set_background_page(backgroundPage); + row.Set_installed_path(widgetInstalledPath); + + DO_INSERT(row, WidgetExtendedInfo) +} + +DbWidgetHandle WidgetDAO::registerWidgetInfo( + const TizenAppId & tzAppId, + const TizenPkgId & tzPkgId, + const std::string & baseFolder, + AppType appType, + PkgType pkgType, + const ConfigParserData &widgetConfigurationInfo, + const IWidgetSecurity &widgetSecurity, + const DPL::Optional handle) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + // TODO in wrt_db all Columns in WidgetInfo have DEFAULT VALUE set. + // Because of that, "Optional" is not used there + + WidgetInfo::Row row; + if (!!handle) { + row.Set_app_id(*handle); + } + + row.Set_widget_type(appType); + row.Set_widget_id(widgetConfigurationInfo.widget_id); + row.Set_defaultlocale(widgetConfigurationInfo.defaultlocale); + row.Set_widget_version(widgetConfigurationInfo.version); + row.Set_widget_width(widgetConfigurationInfo.width); + row.Set_widget_height(widgetConfigurationInfo.height); + row.Set_author_name(widgetConfigurationInfo.authorName); + row.Set_author_email(widgetConfigurationInfo.authorEmail); + row.Set_author_href(widgetConfigurationInfo.authorHref); + row.Set_csp_policy(widgetConfigurationInfo.cspPolicy); + row.Set_csp_policy_report_only(widgetConfigurationInfo.cspPolicyReportOnly); + row.Set_base_folder(DPL::FromUTF8String(baseFolder)); + row.Set_webkit_plugins_required(widgetConfigurationInfo.flashNeeded); + row.Set_tizen_appid(tzAppId); + row.Set_tizen_pkgid(tzPkgId); + { + if (!!widgetConfigurationInfo.minVersionRequired) { + row.Set_min_version(widgetConfigurationInfo.minVersionRequired); + } else if (!!widgetConfigurationInfo.tizenMinVersionRequired) { + row.Set_min_version(widgetConfigurationInfo.tizenMinVersionRequired); + } + } + row.Set_back_supported(widgetConfigurationInfo.backSupported); + row.Set_access_network(widgetConfigurationInfo.accessNetwork); + row.Set_pkg_type(pkgType); + row.Set_security_model_version( + static_cast(widgetConfigurationInfo.securityModelVersion)); + + Try + { + DO_INSERT(row, WidgetInfo); + } + Catch(DPL::DB::SqlConnection::Exception::Base) + { + ReThrowMsg(WidgetDAO::Exception::DatabaseError, + "Failed to register widget info."); + } + + if (!handle) { + //get autoincremented value of widgetHandle + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(tzAppId)); + return select->GetSingleValue(); + } else { + return *handle; + } +} + +void WidgetDAO::registerWidgetLocalizedInfo(DbWidgetHandle widgetHandle, + const ConfigParserData::LocalizedDataSet &localizedDataSet) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + FOREACH(it, localizedDataSet) + { + const DPL::String& locale = it->first; + const ConfigParserData::LocalizedData& data = it->second; + + LocalizedWidgetInfo::Row row; + row.Set_app_id(widgetHandle); + row.Set_widget_locale(locale); + row.Set_widget_name(data.name); + row.Set_widget_shortname(data.shortName); + row.Set_widget_description(data.description); + row.Set_widget_license(data.license); + row.Set_widget_license_file(data.licenseFile); + row.Set_widget_license_href(data.licenseHref); + + DO_INSERT(row, LocalizedWidgetInfo) + } +} + +void WidgetDAO::registerWidgetIcons(DbWidgetHandle widgetHandle, + const WidgetRegisterInfo::LocalizedIconList &icons) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + FOREACH(i, icons) + { + wrt::WidgetIcon::icon_id::ColumnType icon_id; + { + wrt::WidgetIcon::Row row; + row.Set_app_id(widgetHandle); + row.Set_icon_src(i->src); + row.Set_icon_width(i->width); + row.Set_icon_height(i->height); + + WRT_DB_INSERT(insert, wrt::WidgetIcon, &WrtDatabase::interface()) + insert->Values(row); + icon_id = static_cast(insert->Execute()); + } + + FOREACH(j, i->availableLocales) + { + WidgetLocalizedIcon::Row row; + row.Set_app_id(widgetHandle); + row.Set_icon_id(icon_id); + row.Set_widget_locale(*j); + DO_INSERT(row, WidgetLocalizedIcon) + } + } +} + +void WidgetDAO::registerWidgetStartFile(DbWidgetHandle widgetHandle, + const WidgetRegisterInfo::LocalizedStartFileList &startFiles) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + FOREACH(i, startFiles) + { + WidgetStartFile::start_file_id::ColumnType startFileID; + { + WidgetStartFile::Row row; + row.Set_app_id(widgetHandle); + row.Set_src(i->path); + + WRT_DB_INSERT(insert, WidgetStartFile, &WrtDatabase::interface()) + insert->Values(row); + startFileID = static_cast(insert->Execute()); + } + + FOREACH(j, i->propertiesForLocales) + { + WidgetLocalizedStartFile::Row row; + row.Set_app_id(widgetHandle); + row.Set_start_file_id(startFileID); + row.Set_widget_locale(j->first); + row.Set_type(j->second.type); + row.Set_encoding(j->second.encoding); + + DO_INSERT(row, WidgetLocalizedStartFile) + } + } +} + +void WidgetDAO::registerWidgetFeatures(DbWidgetHandle widgetHandle, + const ConfigParserData::FeaturesList &featuresList) +{ + using namespace DPL::DB::ORM; + FOREACH(pWidgetFeature, featuresList) + { + wrt::WidgetFeature::Row widgetFeature; + widgetFeature.Set_app_id(widgetHandle); + widgetFeature.Set_name(pWidgetFeature->name); + widgetFeature.Set_rejected(false); + + DO_INSERT(widgetFeature, wrt::WidgetFeature) + } +} + +void WidgetDAO::registerWidgetPrivilege(DbWidgetHandle widgetHandle, + const ConfigParserData::PrivilegeList &privilegeList) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + FOREACH(it, privilegeList) + { + WidgetPrivilege::Row widgetPrivilege; + widgetPrivilege.Set_app_id(widgetHandle); + widgetPrivilege.Set_name(it->name); + + DO_INSERT(widgetPrivilege, WidgetPrivilege) + } +} + +void WidgetDAO::updateFeatureRejectStatus(const DbWidgetFeature &widgetFeature) +{ + // This function could be merged with registerWidgetFeature but it requires + // desing change: + // 1. Check "ace step" in installer must be done before "update database + // step" + // And: + // ConfigurationParserData shouldn't be called "ParserData" any more. + using namespace DPL::DB::ORM; + + wrt::ScopedTransaction transaction(&WrtDatabase::interface()); + WRT_DB_SELECT(select, wrt::WidgetFeature, &WrtDatabase::interface()) + select->Where(And(Equals(m_widgetHandle), + Equals(widgetFeature.name))); + + auto row = select->GetSingleRow(); + row.Set_rejected(widgetFeature.rejected); + + WRT_DB_UPDATE(update, wrt::WidgetFeature, &WrtDatabase::interface()) + update->Where(And(Equals(m_widgetHandle), + Equals(widgetFeature.name))); + update->Values(row); + update->Execute(); + transaction.Commit(); +} + +void WidgetDAO::registerWidgetWindowModes(DbWidgetHandle widgetHandle, + const ConfigParserData::StringsList &windowModes) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + FOREACH(i, windowModes) + { + wrt::WidgetWindowModes::Row windowMode; + windowMode.Set_app_id(widgetHandle); + windowMode.Set_window_mode(*i); + + DO_INSERT(windowMode, wrt::WidgetWindowModes) + } +} + +void WidgetDAO::registerWidgetWarpInfo(DbWidgetHandle widgetHandle, + const ConfigParserData::AccessInfoSet &accessInfoSet) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + FOREACH(AccIt, accessInfoSet) + { + WidgetWARPInfo::Row row; + row.Set_app_id(widgetHandle); + row.Set_iri(AccIt->m_strIRI); + row.Set_subdomain_access(static_cast ( + AccIt->m_bSubDomainAccess)); + + DO_INSERT(row, WidgetWARPInfo) + } +} + +void WidgetDAO::registerWidgetAllowNavigationInfo(DbWidgetHandle widgetHandle, + const ConfigParserData::AllowNavigationInfoList &allowNavigationInfoList) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + FOREACH(allowNaviIt, allowNavigationInfoList) + { + WidgetAllowNavigation::Row row; + row.Set_app_id(widgetHandle); + row.Set_scheme(allowNaviIt->m_scheme); + row.Set_host(allowNaviIt->m_host); + DO_INSERT(row, WidgetAllowNavigation) + } +} + +void WidgetDAO::registerWidgetCertificates(DbWidgetHandle widgetHandle, + const IWidgetSecurity &widgetSecurity) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + FOREACH(it, widgetSecurity.getCertificateList()) + { + WidgetCertificateFingerprint::Row row; + row.Set_app_id(widgetHandle); + row.Set_owner(it->owner); + row.Set_chainid(it->chainId); + row.Set_type(it->type); + row.Set_md5_fingerprint(DPL::FromUTF8String(it->strMD5Fingerprint)); + row.Set_sha1_fingerprint(DPL::FromUTF8String(it->strSHA1Fingerprint)); + row.Set_common_name(it->strCommonName); + + DO_INSERT(row, WidgetCertificateFingerprint) + } +} + +void WidgetDAO::registerCertificatesChains( + DbWidgetHandle widgetHandle, + CertificateSource certificateSource, + const CertificateChainList & + certificateChainList) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + FOREACH(certChain, certificateChainList) + { + WidgetCertificate::Row row; + row.Set_app_id(widgetHandle); + row.Set_cert_source(certificateSource); + row.Set_encoded_chain(DPL::FromASCIIString(*certChain)); + + DO_INSERT(row, WidgetCertificate); + } +} + +void WidgetDAO::registerWidgetSettings(DbWidgetHandle widgetHandle, + const ConfigParserData::SettingsList &settingsList) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + FOREACH(pWidgetSetting, settingsList) + { + SettingsList::Row row; + row.Set_appId(widgetHandle); + row.Set_settingName(pWidgetSetting->m_name); + row.Set_settingValue(pWidgetSetting->m_value); + + DO_INSERT(row, SettingsList) + } +} + +void WidgetDAO::insertAppControlInfo(DbWidgetHandle handle, + DPL::String src, + DPL::String operation, + DPL::String uri, + DPL::String mime, + unsigned index, + unsigned disposition) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + AppControlInfo::Row row; + + row.Set_app_id(handle); + row.Set_execute_index(index); + row.Set_src(src); + row.Set_operation(operation); + row.Set_uri(uri); + row.Set_mime(mime); + row.Set_disposition(disposition); + + DO_INSERT(row, AppControlInfo); +} + +void WidgetDAO::registerAppControl(DbWidgetHandle widgetHandle, + const ConfigParserData::AppControlInfoList &appControlList) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + // appControlList + FOREACH(appControl_it, appControlList) + { + DPL::String src = appControl_it->m_src; + DPL::String operation = appControl_it->m_operation; + unsigned index = appControl_it->m_index; + unsigned disposition = + static_cast(appControl_it->m_disposition); + + if (!appControl_it->m_uriList.empty()) + { + FOREACH(uri_it, appControl_it->m_uriList) + { + DPL::String uri = *uri_it; + + if (!appControl_it->m_mimeList.empty()) + { + FOREACH(mime_it, appControl_it->m_mimeList) + { + DPL::String mime = *mime_it; + + insertAppControlInfo(widgetHandle, src, operation, uri, mime, index, disposition); + } + } + else + { + DPL::String mime = L""; + + insertAppControlInfo(widgetHandle, src, operation, uri, mime, index, disposition); + } + } + } + else + { + DPL::String uri = L""; + + if (!appControl_it->m_mimeList.empty()) + { + FOREACH(mime_it, appControl_it->m_mimeList) + { + DPL::String mime = *mime_it; + + insertAppControlInfo(widgetHandle, src, operation, uri, mime, index, disposition); + } + } + else + { + DPL::String mime = L""; + + insertAppControlInfo(widgetHandle, src, operation, uri, mime, index, disposition); + } + } + } +} + +void WidgetDAO::registerEncryptedResouceInfo(DbWidgetHandle widgetHandle, + const EncryptedFileList &encryptedFiles) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + FOREACH(it, encryptedFiles) + { + EncryptedResourceList::Row row; + row.Set_app_id(widgetHandle); + row.Set_resource(it->fileName); + row.Set_size(it->fileSize); + + DO_INSERT(row, EncryptedResourceList) + } +} + +void WidgetDAO::registerServiceInternal(const ConfigParserData::ServiceAppInfo &serviceAppInfo, const WidgetRegisterInfo &widgetRegInfo, const IWidgetSecurity &widgetSecurity) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + DPL::String tzAppId = serviceAppInfo.serviceId; + + + DbWidgetHandle widgetHandle = registerWidgetInfo(tzAppId, widgetRegInfo.tzPkgid, widgetRegInfo.baseFolder, + APP_TYPE_TIZENWEBSERVICE, widgetRegInfo.packagingType.pkgType, + widgetRegInfo.configInfo, widgetSecurity); + + registerWidgetExtendedInfo(widgetHandle, widgetRegInfo.installedTime, + widgetRegInfo.configInfo.splashImgSrc, widgetRegInfo.configInfo.backgroundPage, + widgetRegInfo.widgetInstalledPath); + + registerWidgetLocalizedInfo(widgetHandle, serviceAppInfo.m_localizedDataSet); + + + WidgetRegisterInfo::LocalizedIconList iconList; + LocaleSet localeSet; + FOREACH(it, serviceAppInfo.m_iconsList) { + iconList.push_back(WidgetRegisterInfo::LocalizedIcon(*it, localeSet)); + } + registerWidgetIcons(widgetHandle, iconList); + + WidgetRegisterInfo::LocalizedStartFileList startFileList; + WidgetRegisterInfo::LocalizedStartFile startFile; + WidgetRegisterInfo::StartFileProperties startFileProperties; + startFile.path = serviceAppInfo.serviceContent; + startFileProperties.type = L""; + startFileProperties.encoding = L"UTF-8"; + startFile.propertiesForLocales[L""] = startFileProperties; + startFileList.push_back(startFile); + registerWidgetStartFile(widgetHandle, startFileList); + + + PropertyDAO::RegisterProperties(widgetHandle, tzAppId, widgetRegInfo); + + registerWidgetFeatures(widgetHandle, widgetRegInfo.configInfo.featuresList); + + registerWidgetPrivilege(widgetHandle, widgetRegInfo.configInfo.privilegeList); + + registerWidgetWindowModes(widgetHandle, widgetRegInfo.configInfo.windowModes); + + registerWidgetWarpInfo(widgetHandle, widgetRegInfo.configInfo.accessInfoSet); + + registerWidgetAllowNavigationInfo(widgetHandle, widgetRegInfo.configInfo.allowNavigationInfoList); + + registerWidgetCertificates(widgetHandle, widgetSecurity); + + CertificateChainList list; + widgetSecurity.getCertificateChainList(list, SIGNATURE_DISTRIBUTOR); + registerCertificatesChains(widgetHandle, SIGNATURE_DISTRIBUTOR, list); + + list.clear(); + widgetSecurity.getCertificateChainList(list, SIGNATURE_AUTHOR); + registerCertificatesChains(widgetHandle, SIGNATURE_AUTHOR, list); + + registerWidgetSettings(widgetHandle, widgetRegInfo.configInfo.settingsList); + + registerEncryptedResouceInfo(widgetHandle, widgetRegInfo.encryptedFiles); + + registerExternalLocations(widgetHandle, widgetRegInfo.externalLocations); +} + +void WidgetDAO::registerExternalLocations( + DbWidgetHandle widgetHandle, + const ExternalLocationList & + externals) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + LogDebug("Inserting external files for widgetHandle: " << widgetHandle); + FOREACH(it, externals) + { + WidgetExternalLocations::Row row; + row.Set_app_id(widgetHandle); + row.Set_path(DPL::FromUTF8String(*it)); + + DO_INSERT(row, WidgetExternalLocations) + } + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to register external files"); +} + +void WidgetDAO::unregisterAllExternalLocations() +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + LogDebug("Deleting external files for widgetHandle: " << m_widgetHandle); + WRT_DB_DELETE(del, WidgetExternalLocations, &WrtDatabase::interface()); + del->Where(Equals(m_widgetHandle)); + del->Execute(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to unregister external locations") +} + +void WidgetDAO::unregisterWidget(const TizenAppId & tzAppId) +{ + LogDebug("Unregistering widget from DB. tzAppId: " << tzAppId); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + DPL::DB::ORM::wrt::ScopedTransaction transaction( + &WrtDatabase::interface()); + unregisterWidgetInternal(tzAppId); + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to unregister widget") +} + +void WidgetDAO::unregisterWidgetInternal( + const TizenAppId & tzAppId) +{ + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + + DbWidgetHandle handle = getHandle(tzAppId); + + // Delete from table Widget Info + WRT_DB_DELETE(del, WidgetInfo, &WrtDatabase::interface()) + del->Where(Equals(handle)); + del->Execute(); + + // Deleting in other tables is done via "delete cascade" in SQL +} + +#undef DO_INSERT + +#undef SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN +#undef SQL_CONNECTION_EXCEPTION_HANDLER_END +} // namespace WrtDB diff --git a/modules/widget_dao/dao/widget_dao_read_only.cpp b/modules/widget_dao/dao/widget_dao_read_only.cpp new file mode 100755 index 0000000..84a67ed --- /dev/null +++ b/modules/widget_dao/dao/widget_dao_read_only.cpp @@ -0,0 +1,1192 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of widget dao class. + * + * @file widget_dao_read_only.cpp + * @author Yang Jie (jie2.yang@samsung.com) + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of widget dao + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + unsigned int seed = time(NULL); +} + +namespace WrtDB { +//TODO in current solution in each getter there exists a check +//"IsWidgetInstalled". Maybe it should be verified, if it could be done +//differently (check in WidgetDAOReadOnly constructor) + +#define SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN Try + +#define SQL_CONNECTION_EXCEPTION_HANDLER_END(message) \ + Catch(DPL::DB::SqlConnection::Exception::Base) { \ + LogError(message); \ + ReThrowMsg(WidgetDAOReadOnly::Exception::DatabaseError, \ + message); \ + } + +#define CHECK_WIDGET_EXISTENCE(macro_transaction, macro_handle) \ + if (!WidgetDAOReadOnly::isWidgetInstalled(macro_handle)) \ + { \ + macro_transaction.Commit(); \ + LogWarning("Cannot find widget. Handle: " << macro_handle); \ + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, \ + "Cannot find widget. Handle: " << macro_handle); \ + } + +typedef DPL::DB::ORM::wrt::WidgetInfo::Row WidgetInfoRow; +typedef DPL::DB::ORM::wrt::WidgetFeature::widget_feature_id::ColumnType +WidgetFeatureId; + +namespace { +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::wrt; + +WidgetInfoRow getWidgetInfoRow(int widgetHandle) +{ + LogDebug("Getting WidgetInfo row. Handle: " << widgetHandle); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(widgetHandle)); + + WidgetInfo::Select::RowList rows = select->GetRowList(); + if (rows.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Cannot find widget. Handle: " << widgetHandle); + } + return rows.front(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in GetWidgetInfoRow") +} + +const int MAX_TIZENID_LENGTH = 10; + +TizenAppId getTizenAppIdByHandle(const DbWidgetHandle handle) +{ + LogDebug("Getting TizenAppId by DbWidgetHandle: " << handle); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(handle)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + if (rowList.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget by handle"); + } + TizenAppId tzAppid = rowList.front().Get_tizen_appid(); + + return tzAppid; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in getHandle") +} + +TizenAppId getTizenAppIdByPkgId(const TizenPkgId tzPkgid) +{ + LogDebug("Getting TizenAppId by pkgid : " << tzPkgid); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(tzPkgid)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + if (rowList.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget by handle"); + } + TizenAppId tzAppid = rowList.front().Get_tizen_appid(); + + return tzAppid; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in getHandle") +} + +void getTizenAppIdListByPkgId(const TizenPkgId tzPkgid, std::list& idList) +{ + LogDebug("Getting TizenAppId by pkgid : " << tzPkgid); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(tzPkgid)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + for (WidgetInfo::Select::RowList::iterator i = rowList.begin(); i != rowList.end(); ++i) { + TizenAppId tzAppid = i->Get_tizen_appid(); + idList.push_back(tzAppid); + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in getHandle") +} + +TizenPkgId getTizenPkgIdByHandle(const DbWidgetHandle handle) +{ + LogDebug("Getting TizenPkgId by DbWidgetHandle: " << handle); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(handle)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + if (rowList.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget by handle"); + } + TizenPkgId tzPkgid = rowList.front().Get_tizen_pkgid(); + + return tzPkgid; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in getHandle") +} + +TizenPkgId getTizenPkgIdByAppId(const TizenAppId tzAppid) +{ + LogDebug("Getting TizenPkgId by TizenAppId: " << tzAppid); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(tzAppid)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + if (rowList.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget by tizen appId"); + } + TizenPkgId tzPkgid = rowList.front().Get_tizen_pkgid(); + + return tzPkgid; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed get pkgId") +} +} // namespace + +IWidgetSecurity::~IWidgetSecurity() +{} + +WidgetDAOReadOnly::WidgetDAOReadOnly(DbWidgetHandle widgetHandle) : + m_widgetHandle(widgetHandle) +{} + +WidgetDAOReadOnly::WidgetDAOReadOnly(DPL::OptionalString widgetGUID) : + m_widgetHandle(WidgetDAOReadOnly::getHandle(widgetGUID)) +{} + +WidgetDAOReadOnly::WidgetDAOReadOnly(TizenAppId tzAppid) : + m_widgetHandle(WidgetDAOReadOnly::getHandle(tzAppid)) +{} + +WidgetDAOReadOnly::~WidgetDAOReadOnly() +{} + +DbWidgetHandle WidgetDAOReadOnly::getHandle() const +{ + return m_widgetHandle; +} + +DbWidgetHandle WidgetDAOReadOnly::getHandle(const WidgetGUID GUID) +{ + LogDebug("Getting WidgetHandle by GUID [" << GUID << "]"); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(GUID)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + if (rowList.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget by guid"); + } + return rowList.front().Get_app_id(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in getHandle") +} + +DbWidgetHandle WidgetDAOReadOnly::getHandle(const DPL::String tzAppId) +{ + LogDebug("Getting WidgetHandle by tizen app id [" << tzAppId << "]"); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(tzAppId)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + if (rowList.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget by package name"); + } + return rowList.front().Get_app_id(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in getHandle") +} + +DbWidgetHandle WidgetDAOReadOnly::getHandleByPkgId(const DPL::String pkgId) +{ + LogDebug("Getting WidgetHandle by tizen package id [" << pkgId << "]"); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(pkgId)); + WidgetInfo::Select::RowList rowList = select->GetRowList(); + + if (rowList.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Failed to get widget by package id"); + } + return rowList.front().Get_app_id(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed in getHandle") +} + + +TizenAppId WidgetDAOReadOnly::getTzAppId() const +{ + return getTizenAppIdByHandle(m_widgetHandle); +} + +TizenAppId WidgetDAOReadOnly::getTzAppId(const WidgetGUID GUID) +{ + return getTizenAppIdByHandle(getHandle(GUID)); +} + +TizenAppId WidgetDAOReadOnly::getTzAppId(const DbWidgetHandle handle) +{ + return getTizenAppIdByHandle(handle); +} + +TizenAppId WidgetDAOReadOnly::getTzAppId(const TizenPkgId tzPkgid) +{ + return getTizenAppIdByPkgId(tzPkgid); +} + +TizenAppId WidgetDAOReadOnly::getTizenAppId() const +{ + return getTizenAppIdByHandle(m_widgetHandle); +} + +TizenAppId WidgetDAOReadOnly::getTizenAppId(const WidgetGUID GUID) +{ + return getTizenAppIdByHandle(getHandle(GUID)); +} + +TizenAppId WidgetDAOReadOnly::getTizenAppId(const DbWidgetHandle handle) +{ + return getTizenAppIdByHandle(handle); +} + +TizenAppId WidgetDAOReadOnly::getTizenAppId(const TizenPkgId tzPkgid) +{ + return getTizenAppIdByPkgId(tzPkgid); +} + +TizenAppIdList WidgetDAOReadOnly::getTizenAppidList() +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + return select->GetValueList(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get TizenAppIdList") +} + +TizenAppIdList WidgetDAOReadOnly::getTizenAppIdList() +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + return select->GetValueList(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get TizenAppIdList") +} + +std::list WidgetDAOReadOnly::getTzAppIdList(const TizenPkgId tzPkgid){ + std::list result; + getTizenAppIdListByPkgId(tzPkgid, result); + return result; +} + +TizenPkgId WidgetDAOReadOnly::getTzPkgId() const +{ + return getTizenPkgIdByHandle(m_widgetHandle); +} + +TizenPkgId WidgetDAOReadOnly::getTzPkgId(const DbWidgetHandle handle) +{ + return getTizenPkgIdByHandle(handle); +} + +TizenPkgId WidgetDAOReadOnly::getTzPkgId(const TizenAppId tzAppid) +{ + return getTizenPkgIdByAppId(tzAppid); +} + +TizenPkgId WidgetDAOReadOnly::getTizenPkgId() const +{ + return getTizenPkgIdByHandle(m_widgetHandle); +} + +TizenPkgId WidgetDAOReadOnly::getTizenPkgId(const DbWidgetHandle handle) +{ + return getTizenPkgIdByHandle(handle); +} + +TizenPkgId WidgetDAOReadOnly::getTizenPkgId(const TizenAppId tzAppid) +{ + return getTizenPkgIdByAppId(tzAppid); +} + +TizenPkgIdList WidgetDAOReadOnly::getTizenPkgidList() +{ + LogDebug("Getting Pkgid List "); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + return select->GetValueList(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get Pkgid list") +} + +TizenPkgIdList WidgetDAOReadOnly::getTizenPkgIdList() +{ + LogDebug("Getting TizenPkgId List "); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + return select->GetValueList(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get Pkgid list") +} + +PropertyDAOReadOnly::WidgetPropertyKeyList +WidgetDAOReadOnly::getPropertyKeyList() const +{ + return PropertyDAOReadOnly::GetPropertyKeyList(getTizenAppId()); +} + +PropertyDAOReadOnly::WidgetPreferenceList +WidgetDAOReadOnly::getPropertyList() const +{ + return PropertyDAOReadOnly::GetPropertyList(getTizenAppId()); +} + +PropertyDAOReadOnly::WidgetPropertyValue WidgetDAOReadOnly::getPropertyValue( + const PropertyDAOReadOnly::WidgetPropertyKey &key) const +{ + return PropertyDAOReadOnly::GetPropertyValue(getTizenAppId(), key); +} + +DPL::OptionalInt WidgetDAOReadOnly::checkPropertyReadFlag( + const PropertyDAOReadOnly::WidgetPropertyKey &key) const +{ + return PropertyDAOReadOnly::CheckPropertyReadFlag(getTizenAppId(), key); +} + +DPL::String WidgetDAOReadOnly::getPath() const +{ + DPL::String path = *getWidgetInstalledPath(); + DPL::String srcPath = DPL::FromUTF8String(GlobalConfig::GetWidgetSrcPath()); + + path += srcPath + L"/"; + + return path; +} + +DPL::String WidgetDAOReadOnly::getFullPath() const +{ + return L"file://" + getPath(); +} + +WidgetLocalizedInfo +WidgetDAOReadOnly::getLocalizedInfo(const DPL::String& languageTag) +const +{ + LogDebug("Getting Localized Info. Handle: " << m_widgetHandle); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&WrtDatabase::interface()); + CHECK_WIDGET_EXISTENCE(transaction, m_widgetHandle) + + WRT_DB_SELECT(select, LocalizedWidgetInfo, &WrtDatabase::interface()) + select->Where( + And(Equals(m_widgetHandle), + Equals(languageTag))); + LocalizedWidgetInfo::Row info = select->GetSingleRow(); + WidgetLocalizedInfo result; + + result.name = info.Get_widget_name(); + result.shortName = info.Get_widget_shortname(); + result.description = info.Get_widget_description(); + result.license = info.Get_widget_license(); + result.licenseHref = info.Get_widget_license_href(); + + transaction.Commit(); + return result; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get localized info") +} + +DbWidgetFeatureSet WidgetDAOReadOnly::getFeaturesList() const +{ + LogDebug("Getting FeaturesList. Handle: " << m_widgetHandle); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&WrtDatabase::interface()); + CHECK_WIDGET_EXISTENCE(transaction, m_widgetHandle) + + WRT_DB_SELECT(select, WidgetFeature, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + DbWidgetFeatureSet resultSet; + typedef std::list RowList; + RowList list = select->GetRowList(); + + for (RowList::iterator i = list.begin(); i != list.end(); ++i) { + DbWidgetFeature feature; + feature.name = i->Get_name(); + feature.rejected = i->Get_rejected(); + FeatureDAOReadOnly featureDao(DPL::ToUTF8String(i->Get_name())); + feature.pluginId = featureDao.GetPluginHandle(); + resultSet.insert(feature); + } + transaction.Commit(); + return resultSet; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get features list") +} + +bool WidgetDAOReadOnly::hasFeature(const std::string& featureName) const +{ + LogDebug( + "Checking if widget has feature: " << featureName << ". Handle: " << + m_widgetHandle); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&WrtDatabase::interface()); + CHECK_WIDGET_EXISTENCE(transaction, m_widgetHandle) + + WRT_DB_SELECT(select, wrt::WidgetFeature, &WrtDatabase::interface()) + select->Where(And(Equals(m_widgetHandle), + Equals( + DPL::FromUTF8String(featureName)))); + + wrt::WidgetFeature::Select::RowList rows = select->GetRowList(); + transaction.Commit(); + return !rows.empty(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to check for feature") +} + +DbWidgetDAOReadOnlyList WidgetDAOReadOnly::getWidgetList() +{ + LogDebug("Getting DbWidget List"); + DbWidgetDAOReadOnlyList list; + FOREACH(iterator, getTizenAppIdList()) { + list.push_back(WidgetDAOReadOnlyPtr(new WidgetDAOReadOnly(*iterator))); + } + return list; +} + +bool WidgetDAOReadOnly::isWidgetInstalled(DbWidgetHandle handle) +{ + LogDebug("Checking if widget exist. Handle: " << handle); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(handle)); + + WidgetInfo::Select::RowList rows = select->GetRowList(); + + return !rows.empty(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to check if widget exist") +} + +bool WidgetDAOReadOnly::isWidgetInstalled(const TizenAppId &tzAppId) +{ + LogDebug("Checking if widget exist. tizen app id" << tzAppId); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(tzAppId)); + + WidgetInfo::Select::RowList rows = select->GetRowList(); + + return !rows.empty(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to check if widget exist") +} + +ExternalLocationList WidgetDAOReadOnly::getWidgetExternalLocations() const +{ + LogDebug("Getting WidgetExtranalFiles List"); + ExternalLocationList result; + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetExternalLocations, &WrtDatabase::interface()); + select->Where(Equals(m_widgetHandle)); + WidgetExternalLocations::Select::RowList rows = select->GetRowList(); + FOREACH(it, rows) + { + result.push_back(DPL::ToUTF8String(it->Get_path())); + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get handle list") + return result; +} + +CertificateChainList WidgetDAOReadOnly::getWidgetCertificate( + CertificateSource source) const +{ + WRT_DB_SELECT(select, WidgetCertificate, &WrtDatabase::interface()) + select->Where( + And( + Equals(m_widgetHandle), + Equals(source))); + + std::list chainList = select->GetRowList(); + + CertificateChainList result; + + FOREACH(iter, chainList) + result.push_back(DPL::ToUTF8String(iter->Get_encoded_chain())); + return result; +} + +DbWidgetSize WidgetDAOReadOnly::getPreferredSize() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + + DbWidgetSize size; + size.width = row.Get_widget_width(); + size.height = row.Get_widget_height(); + + LogDebug("Return size wxh = " << + (!!size.width ? *size.width : -1) << " x " << + (!!size.height ? *size.height : -1)); + + return size; +} + +WidgetType WidgetDAOReadOnly::getWidgetType() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + DPL::OptionalInt result = row.Get_widget_type(); + return WidgetType(static_cast(*result)); +} + +WidgetGUID WidgetDAOReadOnly::getGUID() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_widget_id(); +} + +DPL::OptionalString WidgetDAOReadOnly::getDefaultlocale() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_defaultlocale(); +} + +DPL::Optional WidgetDAOReadOnly::getVersion() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_widget_version(); +} + +DPL::Optional WidgetDAOReadOnly::getAuthorName() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_author_name(); +} + +DPL::Optional WidgetDAOReadOnly::getAuthorEmail() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_author_email(); +} + +DPL::Optional WidgetDAOReadOnly::getAuthorHref() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_author_href(); +} + +DPL::Optional WidgetDAOReadOnly::getMinimumWacVersion() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_min_version(); +} + +bool WidgetDAOReadOnly::getBackSupported() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_back_supported(); +} + +DPL::OptionalString WidgetDAOReadOnly::getCspPolicy() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_csp_policy(); +} + +DPL::OptionalString WidgetDAOReadOnly::getCspPolicyReportOnly() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + return row.Get_csp_policy_report_only(); +} + +bool WidgetDAOReadOnly::getWebkitPluginsRequired() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + DPL::OptionalInt ret = row.Get_webkit_plugins_required(); + + if (ret.IsNull() || *ret == 0) { + return false; + } else { return true; + } +} + +time_t WidgetDAOReadOnly::getInstallTime() const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetExtendedInfo, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + WidgetExtendedInfo::Select::RowList rows = select->GetRowList(); + if (rows.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Cannot find widget. Handle: " << m_widgetHandle); + } + + return static_cast(*rows.front().Get_install_time()); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get widdget install time") +} + +DPL::OptionalString WidgetDAOReadOnly::getSplashImgSrc() const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetExtendedInfo, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + WidgetExtendedInfo::Select::RowList rows = select->GetRowList(); + if (rows.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Cannot find widget. Handle: " << m_widgetHandle); + } + + DPL::OptionalString value = rows.front().Get_splash_img_src(); + if (value.IsNull()) { + return DPL::OptionalString::Null; + } + + return DPL::OptionalString(getPath() + *value); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get splash image path") +} + +WidgetDAOReadOnly::WidgetLocalizedIconList WidgetDAOReadOnly:: + getLocalizedIconList() const +{ + //TODO check widget existance?? + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetLocalizedIcon, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + std::list list = + select->GetRowList(); + WidgetLocalizedIconList ret; + FOREACH(it, list) + { + WidgetLocalizedIconRow icon = { it->Get_app_id(), + it->Get_icon_id(), + it->Get_widget_locale() }; + ret.push_back(icon); + } + return ret; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get icon data") +} + +WidgetDAOReadOnly::WidgetIconList WidgetDAOReadOnly::getIconList() const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, wrt::WidgetIcon, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + select->OrderBy(DPL::TypeListDecl >()); + + std::list list = + select->GetRowList(); + WidgetIconList ret; + FOREACH(it, list) + { + WidgetIconRow icon = { it->Get_icon_id(), + it->Get_app_id(), + it->Get_icon_src(), + it->Get_icon_width(), + it->Get_icon_height() }; + ret.push_back(icon); + } + return ret; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get icon data") +} + +WidgetDAOReadOnly::LocalizedStartFileList WidgetDAOReadOnly:: + getLocalizedStartFileList() const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetLocalizedStartFile, &WrtDatabase::interface()) + select->Where(Equals( + m_widgetHandle)); + select->OrderBy("start_file_id ASC"); + + std::list list = + select->GetRowList(); + LocalizedStartFileList ret; + FOREACH(it, list) + { + WidgetLocalizedStartFileRow file = { it->Get_start_file_id(), + it->Get_app_id(), + it->Get_widget_locale(), + it->Get_type(), + it->Get_encoding() }; + ret.push_back(file); + } + return ret; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get start file list data") +} + +WidgetDAOReadOnly::WidgetStartFileList WidgetDAOReadOnly::getStartFileList() +const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetStartFile, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + select->OrderBy("start_file_id ASC"); + + std::list list = + select->GetRowList(); + WidgetStartFileList ret; + FOREACH(it, list) + { + WidgetStartFileRow file = { it->Get_start_file_id(), + it->Get_app_id(), + it->Get_src() }; + ret.push_back(file); + } + return ret; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get start file list data") +} + +WindowModeList WidgetDAOReadOnly::getWindowModes() const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetWindowModes, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + return select->GetValueList(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get window modes") +} + +std::string WidgetDAOReadOnly::getBaseFolder() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + DPL::Optional ret = row.Get_base_folder(); + std::string baseFolder; + if (!ret.IsNull()) { + baseFolder = DPL::ToUTF8String(*ret); + } + + if (!baseFolder.empty()) { + baseFolder += "/"; + } + + return baseFolder; +} + +WidgetCertificateDataList WidgetDAOReadOnly::getCertificateDataList() const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, + WidgetCertificateFingerprint, + &WrtDatabase::interface()) + select->Where(Equals( + m_widgetHandle)); + select->OrderBy("chainid"); + WidgetCertificateFingerprint::Select::RowList rows = + select->GetRowList(); + + WidgetCertificateDataList outlCertificateData; + FOREACH(it, rows) + { + WidgetCertificateData data; + + data.owner = + static_cast (it->Get_owner()); + data.type = + static_cast (it->Get_type()); + data.chainId = it->Get_chainid(); + DPL::Optional md5 = it->Get_md5_fingerprint(); + data.strMD5Fingerprint = + md5.IsNull() ? "" : DPL::ToUTF8String(*md5); + DPL::Optional sha1 = it->Get_sha1_fingerprint(); + data.strSHA1Fingerprint = + sha1.IsNull() ? "" : DPL::ToUTF8String(*sha1); + DPL::Optional cname = it->Get_common_name(); + data.strCommonName = + cname.IsNull() ? DPL::FromUTF8String("") : *cname; + + outlCertificateData.push_back(data); + } + return outlCertificateData; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get fingerprint list") +} + +FingerPrintList WidgetDAOReadOnly::getKeyFingerprints( + WidgetCertificateData::Owner owner, + WidgetCertificateData::Type type) const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, + WidgetCertificateFingerprint, + &WrtDatabase::interface()) + select->Where(And(And( + Equals( + m_widgetHandle), + Equals(owner)), + Equals(type))); + + WidgetCertificateFingerprint::Select::RowList rows = + select->GetRowList(); + + FingerPrintList keys; + FOREACH(it, rows) + { + DPL::Optional sha1 = it->Get_sha1_fingerprint(); + if (!sha1.IsNull()) { + keys.push_back(DPL::ToUTF8String(*sha1)); + } + DPL::Optional md5 = it->Get_md5_fingerprint(); + if (!md5.IsNull()) { + keys.push_back(DPL::ToUTF8String(*md5)); + } + } + return keys; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get fingerprint list") +} + +WidgetCertificateCNList WidgetDAOReadOnly::getKeyCommonNameList( + WidgetCertificateData::Owner owner, + WidgetCertificateData::Type type) const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, + WidgetCertificateFingerprint, + &WrtDatabase::interface()) + select->Where(And(And( + Equals( + m_widgetHandle), + Equals(owner)), + Equals(type))); + + WidgetCertificateFingerprint::Select::RowList rows = + select->GetRowList(); + + WidgetCertificateCNList out; + FOREACH(it, rows) + { + DPL::Optional cname = it->Get_common_name(); + out.push_back(cname.IsNull() ? "" : DPL::ToUTF8String(*cname)); + } + return out; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get key common name") +} + +void WidgetDAOReadOnly::getWidgetAccessInfo( + WidgetAccessInfoList& outAccessInfoList) const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetWARPInfo, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + WidgetWARPInfo::Select::RowList rows = select->GetRowList(); + + FOREACH(it, rows) + { + WidgetAccessInfo info; + + info.strIRI = it->Get_iri(); + DPL::OptionalInt access = it->Get_subdomain_access(); + if (access.IsNull() || 0 == *access) { + info.bSubDomains = false; + } else if (1 == *access) { + info.bSubDomains = true; + } + + outAccessInfoList.push_back(info); + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get accessinfo list") +} + +void WidgetDAOReadOnly::getWidgetAllowNavigationInfo( + WidgetAllowNavigationInfoList& allowNavigationList) const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetAllowNavigation, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + WidgetAllowNavigation::Select::RowList rows = select->GetRowList(); + + FOREACH(it, rows) { + WidgetAllowNavigationInfo info; + info.scheme = it->Get_scheme(); + info.host = it->Get_host(); + allowNavigationList.push_back(info); + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get allow-navigation info list") +} + +LanguageTags WidgetDAOReadOnly::getLanguageTags() const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, LocalizedWidgetInfo, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + return select->GetValueList(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get language tags") +} + +LanguageTags WidgetDAOReadOnly::getIconLanguageTags() const +{ + //TODO check widget existance + WRT_DB_SELECT(select, WidgetLocalizedIcon, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + select->Distinct(); + return select->GetValueList(); +} + +void WidgetDAOReadOnly::getWidgetSettings( + WidgetSettings& outWidgetSettings) const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, SettingsList, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + SettingsList::Select::RowList rows = select->GetRowList(); + + FOREACH(it, rows) + { + WidgetSetting info; + + info.settingName = it->Get_settingName(); + info.settingValue = it->Get_settingValue(); + outWidgetSettings.push_back(info); + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get settings list") +} + +void WidgetDAOReadOnly::getAppControlList( + WidgetAppControlList& outAppControlList) const +{ + LogDebug("Getting getAppControlList. Handle: " << m_widgetHandle); + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction transaction(&WrtDatabase::interface()); + CHECK_WIDGET_EXISTENCE(transaction, m_widgetHandle) + + WRT_DB_SELECT(select, AppControlInfo, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + AppControlInfo::Select::RowList rows = select->GetRowList(); + + if (rows.empty()) { + LogDebug("AppControl list is empty. Handle: " << + m_widgetHandle); + } + + FOREACH(it, rows) { + WidgetAppControl ret; + ret.src = it->Get_src(); + ret.operation = it->Get_operation(); + ret.uri = it->Get_uri(); + ret.mime = it->Get_mime(); + ret.disposition = static_cast(it->Get_disposition()); + ret.index = it->Get_execute_index(); + outAppControlList.push_back(ret); + } + + transaction.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get AppControl list") +} + +PackagingType WidgetDAOReadOnly::getPackagingType() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + DPL::OptionalInt result = row.Get_pkg_type(); + return PackagingType(static_cast(*result)); +} + +void WidgetDAOReadOnly::getEncryptedFileList(EncryptedFileList& filesList) +const +{ + //TODO check widget existance + WRT_DB_SELECT(select, EncryptedResourceList, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + typedef std::list RowList; + RowList list = select->GetRowList(); + + FOREACH(it, list) { + EncryptedFileInfo info; + info.fileName = it->Get_resource(); + info.fileSize = it->Get_size(); + filesList.insert(info); + } +} + +DPL::OptionalString WidgetDAOReadOnly::getBackgroundPage() const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetExtendedInfo, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + WidgetExtendedInfo::Select::RowList rows = select->GetRowList(); + if (rows.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Cannot find widget. Handle: " << m_widgetHandle); + } + + return rows.front().Get_background_page(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get background page") +} + +TizenPkgId WidgetDAOReadOnly::generatePkgId() +{ + std::string allowed("0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"); + TizenPkgId pkgId; + pkgId.resize(MAX_TIZENID_LENGTH); + do { + for (int i = 0; i < MAX_TIZENID_LENGTH; ++i) { + pkgId[i] = allowed[rand_r(&seed) % allowed.length()]; + } + } while (isWidgetInstalled(pkgId)); + return pkgId; +} + +DPL::OptionalString WidgetDAOReadOnly::getWidgetInstalledPath() const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::wrt; + WRT_DB_SELECT(select, WidgetExtendedInfo, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + WidgetExtendedInfo::Select::RowList rows = select->GetRowList(); + if (rows.empty()) { + ThrowMsg(WidgetDAOReadOnly::Exception::WidgetNotExist, + "Cannot find widget. Handle: " << m_widgetHandle); + } + + return rows.front().Get_installed_path(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get widdget installed path") +} + +PrivilegeList WidgetDAOReadOnly::getWidgetPrivilege() const +{ + //TODO check widget existance + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WRT_DB_SELECT(select, WidgetPrivilege, &WrtDatabase::interface()) + select->Where(Equals(m_widgetHandle)); + + return select->GetValueList(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get PrivilegeList") +} + +WidgetSecurityModelVersion WidgetDAOReadOnly::getSecurityModelVersion() const +{ + WidgetInfoRow row = getWidgetInfoRow(m_widgetHandle); + DPL::OptionalInt result = row.Get_security_model_version(); + return static_cast(*result); +} + +#undef SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN +#undef SQL_CONNECTION_EXCEPTION_HANDLER_END +#undef CHECK_WIDGET_EXISTENCE +} // namespace WrtDB diff --git a/modules/widget_dao/dao/widget_dao_types.cpp b/modules/widget_dao/dao/widget_dao_types.cpp new file mode 100644 index 0000000..1296b28 --- /dev/null +++ b/modules/widget_dao/dao/widget_dao_types.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file widget_dao_types.cpp + * @author Leerang Song (leerang.song@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of + * common data types forwidget database. + */ + +#include +#include + +namespace WrtDB { + +const std::map g_W3CPrivilegeTextMap = { + {"http://tizen.org/privilege/location", FEATURE_GEOLOCATION}, + {"http://tizen.org/privilege/notification", FEATURE_WEB_NOTIFICATION}, + {"http://tizen.org/privilege/mediacapture", FEATURE_USER_MEDIA}, + {"http://tizen.org/privilege/fullscreen", FEATURE_FULLSCREEN_MODE}, + {"http://tizen.org/privilege/unlimitedstorage", FEATURE_WEB_DATABASE}, + {"http://tizen.org/privilege/camera", FEATURE_CAMERA}, + {"http://tizen.org/privilege/audiorecorder", FEATURE_AUDIO_RECORDER} +}; +} // namespace SecurityOriginDB diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/WrtDatabase.h b/modules/widget_dao/include/dpl/wrt-dao-ro/WrtDatabase.h new file mode 100644 index 0000000..8caa49f --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/WrtDatabase.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef WRT_SRC_CONFIGURATION_WRTDATABASE_H_ +#define WRT_SRC_CONFIGURATION_WRTDATABASE_H_ + +#include + +namespace WrtDB { +class WrtDatabase +{ + public: + static const char *Address(); + static DPL::DB::SqlConnection::Flag::Type Flags(); + static void attachToThreadRO(); + static void attachToThreadRW(); + static void detachFromThread(); + static DPL::DB::ThreadDatabaseSupport& interface(); + static bool CheckTableExist(const char *name); + + private: + static DPL::DB::ThreadDatabaseSupport m_interface; +}; +} + +#endif /* WRTDATABASE_H */ + diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/common_dao_types.h b/modules/widget_dao/include/dpl/wrt-dao-ro/common_dao_types.h new file mode 100755 index 0000000..d734efa --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/common_dao_types.h @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file common_dao_types.h + * @author Michal Ciepielski (m.ciepielski@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of common data types for wrtdb + */ + +#ifndef WRT_WIDGET_DAO_COMMON_DAO_TYPES_H_ +#define WRT_WIDGET_DAO_COMMON_DAO_TYPES_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +class PluginMetafileData +{ + public: + struct Feature + { + std::string m_name; + std::set m_deviceCapabilities; + + bool operator< (const Feature& obj) const + { + return m_name < obj.m_name; + } + }; + typedef std::set FeatureContainer; + + public: + + PluginMetafileData() + {} + + std::string m_libraryName; + FeatureContainer m_featureContainer; +}; + +class PluginObjectsDAO +{ + public: + typedef std::set Objects; + typedef std::shared_ptr ObjectsPtr; + + public: + explicit PluginObjectsDAO() {} + + protected: + ObjectsPtr m_implemented; + ObjectsPtr m_dependent; +}; + +/** + * @brief Widget id describes web-runtime global widget identifier. + * + * Notice that only up to one widget can exist at the same time. + * DbWidgetHandle can be translated into corresponding WidgetModel by invoking + * FindWidgetModel routine. + */ +typedef int DbWidgetHandle; +typedef DPL::String TizenPkgId; +typedef DPL::String TizenAppId; + +/** + * Value of invalid widget handle + */ +enum { + INVALID_WIDGET_HANDLE = -1 +}; + +/** + * @brief Structure to hold the information of widget's size + */ +struct DbWidgetSize +{ + DPL::OptionalInt width; + DPL::OptionalInt height; + + DbWidgetSize(DPL::OptionalInt w = DPL::OptionalInt::Null, + DPL::OptionalInt h = DPL::OptionalInt::Null) : + width(w), + height(h) + {} +}; + +inline bool operator ==(const DbWidgetSize &objA, const DbWidgetSize &objB) +{ + if (!objA.height || !objA.width || !objB.width || !objB.height) { + return false; + } else { + return *objA.height == *objB.height && *objA.width == *objB.width; + } +} + +/** + * Widget [G]lobal [U]nique [ID]entifier + * Orginated from appstore ID + */ +typedef DPL::OptionalString WidgetGUID; + +struct WidgetAccessInfo +{ + DPL::String strIRI; /* origin iri */ + bool bSubDomains; /* do we want access to subdomains ? */ + + bool operator ==(const WidgetAccessInfo& info) const + { + return info.strIRI == strIRI && + info.bSubDomains == bSubDomains; + } +}; +typedef std::list WidgetAccessInfoList; + +struct WidgetAllowNavigationInfo +{ + DPL::String scheme; + DPL::String host; +}; +typedef std::list WidgetAllowNavigationInfoList; + +struct EncryptedFileInfo +{ + DPL::String fileName; + int fileSize; + + bool operator==(const EncryptedFileInfo& info) const + { + return fileName == info.fileName; + } + + bool operator==(const DPL::String& file) const + { + return fileName == file; + } + + bool operator< (const EncryptedFileInfo& info) const + { + return fileName < info.fileName; + } +}; + +typedef std::list WindowModeList; + +typedef std::list PrivilegeList; + +typedef std::set EncryptedFileList; + +/** + * @brief Widget feature host information about possible javascript extensions + * that widget may use + * + * Widget features are declared in configuration file in widget installation + * package. Each declared special feature is contained in some wrt-plugin that + * declares to implement it. After widget launch wrt searches for proper plugin + * libraries and load needed features. + * + * Widget features can be required or optional. It is possible to start widget + * without missing feature. When required feature cannot be loaded widget will + * not start. + */ + +enum { + INVALID_PLUGIN_HANDLE = -1 +}; +typedef int DbPluginHandle; + +struct DbWidgetFeature +{ + DPL::String name; /// Feature name + bool rejected; /// Api feature was rejected by ace + DbPluginHandle pluginId; /// Plugin id that implement this feature + + DbWidgetFeature() : + pluginId(INVALID_PLUGIN_HANDLE) + {} +}; + +inline bool operator < (const DbWidgetFeature &objA, + const DbWidgetFeature &objB) +{ + return objA.name.compare(objB.name) < 0; +} + +inline bool operator==(const DbWidgetFeature &featureA, + const DbWidgetFeature &featureB) +{ + return featureA.name == featureB.name && + featureA.pluginId == featureB.pluginId; +} + +/** + * @brief Default container for features list + */ +typedef std::multiset DbWidgetFeatureSet; + +/** + * @brief Default container with DbWidgetHandle's + */ +typedef std::list DbWidgetHandleList; +typedef std::list TizenAppIdList; +typedef std::list TizenPkgIdList; + +class WidgetDAOReadOnly; //forward declaration +typedef std::shared_ptr WidgetDAOReadOnlyPtr; +/** + * @brief Default container with WidgetDAOReadOnly + */ +typedef std::list DbWidgetDAOReadOnlyList; + +/** + * @brief Widget specific type + * + * Widget type describes belowed in WAC, TIZEN WebApp + */ +enum AppType +{ + APP_TYPE_UNKNOWN = 0, // unknown + APP_TYPE_TIZENWEBAPP, // Tizen webapp + APP_TYPE_TIZENWEBSERVICE // Tizen web service +}; + +class WidgetType +{ + public: + WidgetType() : + appType(APP_TYPE_UNKNOWN) + {} + WidgetType(const AppType type) : + appType(type) + {} + bool operator== (const AppType& other) const + { + return appType == other; + } + bool operator!= (const AppType& other) const + { + return appType != other; + } + std::string getApptypeToString() + { + switch (appType) { +#define X(x) case x: return #x; + X(APP_TYPE_UNKNOWN) + X(APP_TYPE_TIZENWEBAPP) + X(APP_TYPE_TIZENWEBSERVICE) + +#undef X + default: + return "UNKNOWN"; + } + } + + AppType appType; +}; + +/** + * @brief Package specific type + * + * Package type describes belowed in Tizen webapp, C++ service App + */ +enum PkgType +{ + PKG_TYPE_UNKNOWN = 0, // unknown + PKG_TYPE_NOMAL_WEB_APP, + PKG_TYPE_DIRECTORY_WEB_APP, + PKG_TYPE_HOSTED_WEB_APP, // request from browser + PKG_TYPE_HYBRID_WEB_APP // Tizen webapp with C++ service app +}; + +class PackagingType +{ + public: + PackagingType() : + pkgType(PKG_TYPE_UNKNOWN) + {} + PackagingType(const PkgType type) : + pkgType(type) + {} + bool operator== (const PkgType& other) const + { + return pkgType == other; + } + bool operator!= (const PkgType& other) const + { + return pkgType != other; + } + std::string getPkgtypeToString() + { + switch (pkgType) { +#define X(x) case x: return #x; + X(PKG_TYPE_UNKNOWN) + X(PKG_TYPE_NOMAL_WEB_APP) + X(PKG_TYPE_DIRECTORY_WEB_APP) + X(PKG_TYPE_HOSTED_WEB_APP) + X(PKG_TYPE_HYBRID_WEB_APP) +#undef X + default: + return "UNKNOWN"; + } + } + + PkgType pkgType; +}; + +struct WidgetSetting +{ + DPL::String settingName; + DPL::String settingValue; + + bool operator ==(const WidgetSetting& info) const + { + return (info.settingName == settingName && + info.settingValue == settingValue); + } + bool operator !=(const WidgetSetting& info) const + { + return (info.settingName != settingName || + info.settingValue != settingValue); + } +}; + +typedef std::list WidgetSettings; + +/** + * @brief Widget AppControl + * + * Application control describes details of behaviour + * when widget receives aul bundle data. + */ +namespace AppControlPrefix { + const char* const PROCESS_PREFIX = "-__CONTROL_PROCESS__"; +} +struct WidgetAppControl +{ + enum class Disposition { + UNDEFINE = 0, + WINDOW = 1, + INLINE = 2 + }; + + DPL::String src; /* start uri */ + DPL::String operation; /* service name */ + DPL::String uri; /* scheme type*/ + DPL::String mime; /* mime type */ + Disposition disposition; + unsigned index; + + bool operator== (const WidgetAppControl& other) const + { + return src == other.src && + operation == other.operation && + uri == other.uri && + mime == other.mime && + disposition == other.disposition; + } +}; + +typedef std::list WidgetAppControlList; + +enum class WidgetSecurityModelVersion +{ + WIDGET_SECURITY_MODEL_V1 = 0, // WARP + WIDGET_SECURITY_MODEL_V2 // CSP, allow-navigation +}; +} // namespace WrtDB +#endif /* WRT_WIDGET_DAO_COMMON_DAO_TYPES_H_ */ diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/config_parser_data.h b/modules/widget_dao/include/dpl/wrt-dao-ro/config_parser_data.h new file mode 100755 index 0000000..84bacc3 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/config_parser_data.h @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file config_parser_data.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 0.1 + * @brief + */ +#ifndef CONFIG_PARSER_DATA_H_ +#define CONFIG_PARSER_DATA_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +void NormalizeString(DPL::OptionalString& txt, bool isTrimSpace = false); +void NormalizeString(DPL::String& str); +DPL::String GetSingleAttributeValue(const DPL::String value); +void NormalizeAndTrimSpaceString(DPL::OptionalString& txt); +#if ENABLE(ELEMENT_ATTR_MAX_LENGTH) +void NormalizeString(DPL::String& str, const unsigned int length, bool showEllipsis = false); +void NormalizeString(DPL::OptionalString& str, const unsigned int length, bool showEllipsis = false); +void NormalizeAndTrimSpaceString(DPL::OptionalString& str, const unsigned int length); +#endif // ELEMENT_ATTR_MAX_LENGTH +class WidgetConfigurationManager; + +class ConfigParserData +{ + public: + struct Feature + { + Feature(const DPL::String& _name) : name(_name) + {} + DPL::String name; + + bool operator==(const Feature&) const; + bool operator!=(const Feature&) const; + bool operator >(const Feature&) const; + bool operator>=(const Feature&) const; + bool operator <(const Feature&) const; + bool operator<=(const Feature&) const; + }; + typedef std::set FeaturesList; + + struct Privilege + { + Privilege(const DPL::String& _name) : name(_name) + {} + DPL::String name; + + bool operator==(const Privilege&) const; + bool operator!=(const Privilege&) const; + bool operator >(const Privilege&) const; + bool operator>=(const Privilege&) const; + bool operator <(const Privilege&) const; + bool operator<=(const Privilege&) const; + }; + typedef std::set PrivilegeList; + + struct Icon + { + Icon(const DPL::String& _src) : src(_src), isSmall(false) + {} + DPL::String src; + DPL::OptionalInt width; + DPL::OptionalInt height; + bool isSmall; + bool operator==(const Icon&) const; + bool operator!=(const Icon&) const; + bool operator >(const Icon&) const; + bool operator>=(const Icon&) const; + bool operator <(const Icon&) const; + bool operator<=(const Icon&) const; + }; + typedef std::list IconsList; + + struct LocalizedData + { + DPL::OptionalString name; + DPL::OptionalString shortName; + + DPL::OptionalString description; + + DPL::OptionalString license; + DPL::OptionalString licenseFile; + DPL::OptionalString licenseHref; + }; + typedef std::map LocalizedDataSet; + + struct Preference + { + Preference(const DPL::String& _name, + bool _readonly = false) : + name(_name), + value(), + readonly(_readonly) + {} + DPL::String name; + DPL::OptionalString value; + bool readonly; + bool operator==(const Preference&) const; + bool operator!=(const Preference&) const; + bool operator >(const Preference&) const; + bool operator>=(const Preference&) const; + bool operator <(const Preference&) const; + bool operator<=(const Preference&) const; + }; + typedef std::set PreferencesList; + typedef std::set StringsList; + + struct AccessInfo + { + AccessInfo(const DPL::String& strIRI, + bool bSubdomainAccess) : m_strIRI(strIRI), + m_bSubDomainAccess(bSubdomainAccess) + {} + + bool operator==(const AccessInfo&) const; + bool operator!=(const AccessInfo&) const; + bool operator <(const AccessInfo&) const; + + DPL::String m_strIRI; + bool m_bSubDomainAccess; + }; + typedef std::set AccessInfoSet; + + struct Setting + { + Setting(const DPL::String& name, + const DPL::String& value) : + m_name(name), + m_value(value) + {} + DPL::String m_name; + DPL::String m_value; + + bool operator==(const Setting&) const; + bool operator!=(const Setting&) const; + bool operator >(const Setting&) const; + bool operator>=(const Setting&) const; + bool operator <(const Setting&) const; + bool operator<=(const Setting&) const; + }; + + typedef std::set SettingsList; + + struct AppControlInfo + { + enum class Disposition { + UNDEFINE = 0, + WINDOW = 1, + INLINE = 2 + }; + AppControlInfo(const DPL::String& operation) : + m_operation(operation), + m_disposition(Disposition::UNDEFINE), + m_index(0) + {} + DPL::String m_src; + DPL::String m_operation; + std::set m_uriList; + std::set m_mimeList; + Disposition m_disposition; + unsigned m_index; + + bool operator==(const AppControlInfo&) const; + bool operator!=(const AppControlInfo&) const; + }; + + typedef std::list AppControlInfoList; + + struct LiveboxInfo + { + LiveboxInfo() { } + + struct BoxSize + { + DPL::String m_size; + DPL::String m_preview; + DPL::String m_useDecoration; + }; + typedef BoxSize BoxSizeInfo; + typedef std::list BoxSizeList; + + struct BoxContent + { + DPL::String m_boxSrc; + DPL::String m_boxMouseEvent; + DPL::String m_boxTouchEffect; + BoxSizeList m_boxSize; + DPL::String m_pdSrc; + DPL::String m_pdWidth; + DPL::String m_pdHeight; + DPL::String m_pdFastOpen; + }; + typedef BoxContent BoxContentInfo; + + typedef std::list > BoxLabelList; + + BoxLabelList m_label; + DPL::String m_icon; + DPL::String m_liveboxId; + DPL::String m_primary; + DPL::String m_type; + DPL::String m_autoLaunch; + DPL::String m_updatePeriod; + BoxContentInfo m_boxInfo; + + bool operator==(const LiveboxInfo&) const; + bool operator!=(const LiveboxInfo&) const; + bool operator >(const LiveboxInfo&) const; + bool operator>=(const LiveboxInfo&) const; + bool operator <(const LiveboxInfo&) const; + bool operator<=(const LiveboxInfo&) const; + }; + typedef DPL::Optional OptionalLiveboxInfo; + typedef std::list LiveboxList; + + enum IconSectionType + { + DefaultIcon =0, + SmallIcon + }; + + typedef std::set> IconSet; + typedef std::list CapabilityList; + typedef std::set> DisplayNameSet; + + struct AccountProvider + { + AccountProvider() : + m_multiAccountSupport(false) + { } + + bool m_multiAccountSupport; + IconSet m_iconSet; + DisplayNameSet m_displayNameSet; + CapabilityList m_capabilityList; + }; + + typedef std::list DependsPkgList; + typedef std::set CategoryList; + + struct AllowNavigationInfo + { + AllowNavigationInfo(DPL::String scheme, + DPL::String host) : + m_scheme(scheme), + m_host(host) + { } + DPL::String m_scheme; + DPL::String m_host; + }; + typedef std::list AllowNavigationInfoList; + + struct Metadata + { + Metadata(const DPL::OptionalString& _key, + const DPL::OptionalString& _value) : + key(_key), + value(_value) + {} + DPL::OptionalString key; + DPL::OptionalString value; + + bool operator==(const Metadata&) const; + bool operator!=(const Metadata&) const; + }; + typedef std::list MetadataList; + + struct ImeAppInfo + { + DPL::String uuid; + typedef std::set LanguageList; + LanguageList languageList; + }; + typedef std::list ImeAppInfoList; + + struct ServiceAppInfo + { + ServiceAppInfo() : onBoot(false), autoRestart(false) { } + + DPL::String serviceId; + bool onBoot; + bool autoRestart; + LocalizedDataSet m_localizedDataSet; + DPL::String serviceContent; + IconsList m_iconsList; + MetadataList m_metadataList; + CategoryList m_categoryList; + }; + typedef std::list ServiceAppInfoList; + + enum class SecurityModelVersion { + SECURITY_MODEL_V1 = 0, // WARP + SECURITY_MODEL_V2 // CSP, allow-navigation + }; + + LiveboxList m_livebox; + StringsList nameSpaces; + + LocalizedDataSet localizedDataSet; + + DPL::OptionalString authorName; + DPL::OptionalString authorHref; + DPL::OptionalString authorEmail; + + FeaturesList featuresList; + PrivilegeList privilegeList; + + SettingsList settingsList; + + DPL::OptionalInt width; + DPL::OptionalInt height; + + DPL::OptionalString widget_id; + DPL::OptionalString defaultlocale; + + PreferencesList preferencesList; + + DPL::OptionalString version; + StringsList windowModes; + + AccessInfoSet accessInfoSet; + + bool flashNeeded; + + DPL::OptionalString minVersionRequired; + + bool backSupported; + bool accessNetwork; + + // Unlocalized data, to be processed by WidgetConfigurationManager + bool startFileEncountered; + DPL::OptionalString startFile; + DPL::OptionalString startFileEncoding; + DPL::OptionalString startFileContentType; + DPL::OptionalString startFileNamespace; + IconsList iconsList; + + // tizen id / required platform min version for TIZEN webapp + DPL::OptionalString tizenMinVersionRequired; + DPL::OptionalString tizenPkgId; + DPL::OptionalString tizenAppId; + bool didFoundTizenApplicationElement; + + // Ambient Support(true, false) + DPL::OptionalString ambient; + + // allow-navigation + bool allowNavigationEncountered; + AllowNavigationInfoList allowNavigationInfoList; + + //csp polic for widget + bool cspPolicyEncountered; + DPL::OptionalString cspPolicy; + bool cspPolicyReportOnlyEncountered; + DPL::OptionalString cspPolicyReportOnly; + + //AppControl model list + AppControlInfoList appControlList; + + // For link shared directory + DependsPkgList dependsPkgList; + // Splash image path + DPL::OptionalString splashImgSrc; + // Background page filename + DPL::OptionalString backgroundPage; + // For category + CategoryList categoryList; + // For Account + AccountProvider accountProvider; + // security model version + SecurityModelVersion securityModelVersion; + // security model version + MetadataList metadataList; + //ime app + ImeAppInfoList imeAppInfoList; + //service app + ServiceAppInfoList serviceAppInfoList; + + ConfigParserData() : + flashNeeded(false), + minVersionRequired(), + backSupported(false), + accessNetwork(false), + startFileEncountered(false), + didFoundTizenApplicationElement(false), + allowNavigationEncountered(false), + cspPolicyEncountered(false), + cspPolicyReportOnlyEncountered(false), + securityModelVersion(SecurityModelVersion::SECURITY_MODEL_V1) + {} +}; +} // namespace WrtDB + +#endif //CONFIG_PARSER_DATA_H_ diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/feature_dao_read_only.h b/modules/widget_dao/include/dpl/wrt-dao-ro/feature_dao_read_only.h new file mode 100644 index 0000000..f366012 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/feature_dao_read_only.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file feature_dao_read_only.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of feature dao read only + */ + +#ifndef WRT_SRC_CONFIGURATION_FEATURE_DAO_READ_ONLY_H_ +#define WRT_SRC_CONFIGURATION_FEATURE_DAO_READ_ONLY_H_ + +#include +#include +#include +#include +#include "feature_model.h" +#include +#include + +namespace WrtDB { +// TODO: Move to feature_model.h +typedef std::set DeviceCapabilitySet; + +class FeatureDAOReadOnly +{ + public: + /** + * Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + DECLARE_EXCEPTION_TYPE(Base, FeatureNotExist) + }; + + // TODO: Move to feature_model.h + typedef std::set DeviceCapabilitiesList; + typedef std::multimap DeviceCapabilitiesMap; + typedef std::map NameMap; + typedef std::map FeatureMap; + + static bool isDeviceCapabilityInstalled(const std::string &deviceCapName); + + FeatureDAOReadOnly(FeatureHandle); + FeatureDAOReadOnly(const std::string &featureName); + + static FeatureHandleListPtr GetFeatureHandleListForPlugin( + DbPluginHandle pluginHandle); + + static bool isFeatureInstalled(const std::string &featureName); + static bool isFeatureInstalled(FeatureHandle handle); + static FeatureHandleList GetHandleList(); + + std::string GetName() const; + FeatureHandle GetFeatureHandle() const; + std::string GetLibraryPath() const; + std::string GetLibraryName() const; + DeviceCapabilitiesList GetDeviceCapabilities() const; + DbPluginHandle GetPluginHandle() const; + + static NameMap GetNames(); + static DeviceCapabilitiesMap GetDevCapWithFeatureHandle(); + static DeviceCapabilitySet GetDeviceCapability(const DPL::String &apifeature); + + static FeatureMap GetFeatures(const std::list& featureNames); + + protected: + FeatureHandle m_featureHandle; +}; +} // namespace WrtDB + +#endif /* WRT_SRC_CONFIGURATION_FEATURE_DAO_READ_ONLY_H_ */ diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/feature_model.h b/modules/widget_dao/include/dpl/wrt-dao-ro/feature_model.h new file mode 100644 index 0000000..8698d4a --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/feature_model.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file feature_model.h + * @author Pawel Sikorski (p.sikorski@samgsung.com) + * @version + * @brief This file contains FeatureModel, FeatureHandle definitions. + */ +#ifndef FEATURE_MODEL_H +#define FEATURE_MODEL_H + +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +typedef int FeatureHandle; +typedef std::list FeatureHandleList; +typedef std::shared_ptr FeatureHandleListPtr; + +typedef int FeatureSetHandle; +typedef std::list FeatureSetHandleList; + +typedef struct { + std::string featureName; + DbPluginHandle pluginHandle; +} FeatureData; + +class FeatureModel : public DPL::Event::Model +{ + public: + DPL::Event::Property FHandle; + DPL::Event::Property Name; + + DPL::Event::Property > DeviceCapabilities; + DPL::Event::Property PHandle; + + FeatureModel(FeatureHandle handle) : + FHandle(this, handle), + Name(this), + DeviceCapabilities(this), + PHandle(this, -1) + {} + + void SetData(const std::string& name, + const std::set& deviceCapabilities, + const DbPluginHandle& pluginHandle) + { + Name.SetWithoutLock(name); + DeviceCapabilities.SetWithoutLock(deviceCapabilities); + PHandle.SetWithoutLock(pluginHandle); + } +}; + +typedef std::shared_ptr FeatureModelPtr; +} // namespace WrtDB + +#endif // FEATURE_MODEL_H diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h b/modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h new file mode 100644 index 0000000..c8bd592 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/global_config.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file global_config.h + * @author Yang Jie (jie2.yang@samsung.com) + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file contains global WRT config + */ +#ifndef GLOBAL_CONFIG_H +#define GLOBAL_CONFIG_H + +#include +#include + +namespace WrtDB { +namespace GlobalConfig { +/** + * WRT database path + */ +inline const char* GetWrtDatabaseFilePath() +{ + return "/opt/dbspace/.wrt.db"; +} + +/** + * WRT device plugin path + */ +inline const char* GetDevicePluginPath() +{ + return "/usr/lib/wrt-plugins"; +} + +/** + * WRT widgets that are downloaded and installed by user + */ +inline const char* GetUserInstalledWidgetPath() +{ + return "/opt/usr/apps"; +} + +/** + * WRT widgets that are preloaded + */ +inline const char* GetUserPreloadedWidgetPath() +{ + return "/usr/apps"; +} + +/** + * WRT widgets that are downloaded and installed by user + */ +inline const char* GetWidgetUserDataPath() +{ + return "/opt/usr/apps"; +} + +/** + * WRT widgets that are downloaded and installed by user + */ +inline const char* GetWidgetSrcPath() +{ + return "/res/wgt"; +} + +/** + * Directory for WebKit local storage files + */ +inline const char* GetPublicVirtualRootPath() +{ + return "/opt/share/widget/data/Public"; +} + +/** + * Directory for WebKit local storage files + */ +inline const char* GetWidgetLocalStoragePath() +{ + return "data/localStorage"; +} + +/** + * Directory for tests data (such as test widgets wgt) + */ +inline const char* GetTestsDataPath() +{ + return "/opt/share/widget/tests"; +} + +/** + * widgets exec path + */ +inline const char* GetUserWidgetExecPath() +{ + return "/bin"; +} + +/** + * widgets private data path + */ +inline const char* GetWidgetPrivateStoragePath() +{ + return "data"; +} + +/** + * widgets private temp data path + */ +inline const char* GetWidgetPrivateTempStoragePath() +{ + return "tmp"; +} + +/** + * widgets desktop files path + */ +inline const char* GetUserWidgetDesktopPath() +{ + return "/opt/share/applications"; +} + +/** + * wrt-client exec path + */ +inline const char* GetWrtClientExec() +{ + return "/usr/bin/wrt-client"; +} + +/** + * wrt-service exec path + */ +inline const char* GetWrtServiceExec() +{ + return "/usr/bin/wrt-service"; +} + +/** + * widgets desktop icon path + */ +inline const char* GetUserWidgetDesktopIconPath() +{ + return "/opt/share/icons/default/small"; +} + +/** + * widgets default icon file + */ +inline const char* GetUserWidgetDefaultIconFile() +{ + return "/usr/share/wrt-engine/wrt_widget_default_icon.png"; +} + +inline const char* GetSignatureXmlSchema() +{ + //TODO please rename, this filename is not descriptive enough + return "/usr/share/wrt-engine/schema.xsd"; +} + +/** + * Name of the w3c geolocation feature + */ +inline const char* GetW3CGeolocationFeatureName() +{ + return "http://www.w3.org/TR/geolocation-API/"; +} + +/** + * Prefix of package name for widgets + */ +inline const char* GetPkgnamePrefix() +{ + return "org.tizen."; +} + +/** + * Plugin Configuration Metafile name + */ +inline const char* GetPluginMetafileName() +{ + return "config.xml"; +} + +/** + * Plugin .so prefix + */ +inline const char* GetPluginPrefix() +{ + return "libwrt-plugins-"; +} + +/** + * Plugin .so suffix + */ +inline const char* GetPluginSuffix() +{ + return ".so"; +} + +/** + * WRT device plugins installation required + * File which indicate that new plugins + * are available and should be installed + */ +inline const char* GetPluginInstallInitializerName() +{ + return "/opt/share/widget/plugin-installation-required"; +} + +/** + * File with certificate fingerprints list. + */ + +inline const char* GetFingerprintListFile() +{ + return "/usr/share/wrt-engine/fingerprint_list.xml"; +} + +inline const char* GetFingerprintListSchema() +{ + return "/usr/share/wrt-engine/fingerprint_list.xsd"; +} + +inline const char* GetVCoreDatabaseFilePath() +{ + return "/opt/dbspace/.cert_svc_vcore.db"; +} + +/** + * widgets cookie database file name + */ +inline const char* GetCookieDatabaseFile() +{ + return ".cookie.db"; +} + +inline const char* GetTmpDirPath() +{ + return "/tmp"; +} + +inline const char* GetTizenVersion() +{ + return "2.3.1"; +} + +inline const char* GetShareDirectoryPath() +{ + return "/opt/share"; +} + +inline const char* GetTempInstallInfoPath() +{ + return "/opt/share/widget/temp_info"; +} + +inline const char* GetWidgetSharedPath() +{ + return "/shared"; +} + +inline const char* GetWidgetDataPath() +{ + return "/data"; +} + +inline const char* GetWidgetTrustedPath() +{ + return "/trusted"; +} + +inline const char* GetWidgetResPath() +{ + return "/res"; +} + +inline const char* GetNPRuntimePluginsPath() +{ +#ifdef __arm__ + return "plugins/arm"; +#else + return "plugins/x86"; +#endif +} + +inline const char* GetBackupDatabaseSuffix() +{ + return ".backup"; +} + +inline const char* GetManifestPath() +{ + return "/opt/share/packages"; +} + +inline const char* GetPreloadManifestPath() +{ + return "/usr/share/packages"; +} + +inline const char* GetRecoveryStatusPath() +{ + return "/usr/share/packages/.recovery/wgt"; +} +} // namespace GlobalConfig +} // namespace WrtDB + +#endif // GLOBAL_CONFIG_H diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/path_builder.h b/modules/widget_dao/include/dpl/wrt-dao-ro/path_builder.h new file mode 100644 index 0000000..4ea6a4f --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/path_builder.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file PathBuilder.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief Header file for PathBuilder class. + */ +#ifndef WRT_UTILS_PATHBUILDER_H +#define WRT_UTILS_PATHBUILDER_H + +#include +#include + +namespace WrtDB { +class PathBuilderImpl; + +class PathBuilder : private DPL::Noncopyable +{ + public: + PathBuilder(); + explicit PathBuilder(const std::string& path); + + ~PathBuilder(); + + PathBuilder& Append(const std::string& path); + + PathBuilder& Concat(const std::string& arg); + PathBuilder& Concat(int arg); + + PathBuilder& Reset(); + + bool Empty() const; + + std::string GetFullPath() const; + + private: + PathBuilderImpl* m_impl; +}; +} // namespace WrtDB + +#endif diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/plugin_dao_read_only.h b/modules/widget_dao/include/dpl/wrt-dao-ro/plugin_dao_read_only.h new file mode 100644 index 0000000..3be2441 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/plugin_dao_read_only.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file plugin_dao_read_only.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of plugin dao read only + */ + +#ifndef WRT_SRC_CONFIGURATION_PLUGIN_DAO_READ_ONLY_H_ +#define WRT_SRC_CONFIGURATION_PLUGIN_DAO_READ_ONLY_H_ + +#include +#include +#include +#include +#include + +namespace WrtDB { +typedef std::list PluginHandleList; +typedef std::set PluginHandleSet; +typedef std::list ImplementedObjectsList; +typedef std::shared_ptr PluginHandleSetPtr; + +//TODO make it friend to FeatureDAO or inherit +class PluginDAOReadOnly +{ + public: + enum PluginInstallationState + { + INSTALLATION_DEFAULT, + //when plugin data are up to date and plugin model may be created + INSTALLATION_COMPLETED, + //installation is in progress, some data may not be valid + INSTALLATION_IN_PROGRESS, + //installation not completed due to missing dependency + INSTALLATION_WAITING, + + UNKNOWN_ERROR + }; + + static int ToInt(PluginInstallationState state) + { + return static_cast(state); + } + + static PluginInstallationState ToState(int state) + { + return static_cast(state); + } + + /** + * PluginDAO Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + DECLARE_EXCEPTION_TYPE(Base, PluginNotExist) + DECLARE_EXCEPTION_TYPE(Base, PluginInstallationNotCompleted) + }; + + public: + PluginDAOReadOnly(DbPluginHandle pluginHandle); + PluginDAOReadOnly(const std::string &libraryName); + + static PluginHandleList getPluginHandleList(); + static PluginHandleList getRootPluginHandleList(); + + static bool isPluginInstalled(const std::string &libraryName); + static bool isPluginInstalled(DbPluginHandle pluginHandle); + + static PluginHandleSetPtr getPluginHandleByStatus( + PluginInstallationState state); + + static DbPluginHandle getPluginHandleForImplementedObject( + const std::string& objectName); + + static ImplementedObjectsList getImplementedObjects(); + static ImplementedObjectsList getImplementedObjectsForPluginHandle( + DbPluginHandle handle); + + static PluginObjectsDAO::ObjectsPtr getRequiredObjectsForPluginHandle( + DbPluginHandle handle); + + static PluginInstallationState getInstallationStateForHandle( + DbPluginHandle handle); + + DbPluginHandle getPluginHandle() const; + PluginInstallationState getInstallationStatus() const; + std::string getLibraryPath() const; + std::string getLibraryName() const; + PluginHandleSetPtr getLibraryDependencies() const; + + private: + DbPluginHandle m_pluginHandle; + + void checkInstallationCompleted(); +}; +} // namespace WrtDB + +#endif /* WRT_SRC_CONFIGURATION_PLUGIN_DAO_READ_ONLY_H_ */ diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/property_dao_read_only.h b/modules/widget_dao/include/dpl/wrt-dao-ro/property_dao_read_only.h new file mode 100644 index 0000000..88e308a --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/property_dao_read_only.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * property_dao_read_only.h + * + * Created on: Nov 16, 2011 + * Author: Krzysztof Jackiewicz(k.jackiewicz@samsung.com) + */ + +#ifndef PROPERTY_DAO_READ_ONLY_H_ +#define PROPERTY_DAO_READ_ONLY_H_ + +#include +#include +#include +#include +#include + +namespace WrtDB { +namespace PropertyDAOReadOnly { +typedef DPL::String WidgetPropertyKey; +typedef DPL::OptionalString WidgetPropertyValue; + +typedef std::list WidgetPropertyKeyList; + +struct WidgetPreferenceRow { + int appId; + TizenAppId tizen_appid; + WidgetPropertyKey key_name; + WidgetPropertyValue key_value; + DPL::OptionalInt readonly; +}; + +typedef std::list WidgetPreferenceList; + +/** + * PropertyDAO Exception classes + */ +class Exception +{ + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + DECLARE_EXCEPTION_TYPE(Base, ReadOnlyProperty) +}; + +//deprecated +/* This method checks read only flag for given property + */ +DPL::OptionalInt CheckPropertyReadFlag(DbWidgetHandle widgetHandle, + const WidgetPropertyKey &key) +__attribute__((deprecated)); + +/* This method checks read only flag for given property + */ +DPL::OptionalInt CheckPropertyReadFlag(TizenAppId tzAppid, + const WidgetPropertyKey &key); + +/* This method gets widget property key list + */ +WidgetPropertyKeyList GetPropertyKeyList(TizenAppId tzAppid); + +//deprecated +/* This method gets widget property list + */ +WidgetPreferenceList GetPropertyList(DbWidgetHandle widgetHandle) +__attribute__((deprecated)); + +/* This method gets widget property list + */ +WidgetPreferenceList GetPropertyList(TizenAppId tzAppid); + +/* This method get widget property value + */ +WidgetPropertyValue GetPropertyValue(TizenAppId tzAppid, + const WidgetPropertyKey &key); +} // PropertyDAOReadOnly +} // namespace WrtDB + +#endif /* PROPERTY_DAO_READ_ONLY_H_ */ diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/webruntime_database.h b/modules/widget_dao/include/dpl/wrt-dao-ro/webruntime_database.h new file mode 100644 index 0000000..67c88a9 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/webruntime_database.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file webruntime_database.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of webruntime database + */ +#ifndef WRT_ENGINE_SRC_CONFIGURATION_WEBRUNTIME_DATABASE_H +#define WRT_ENGINE_SRC_CONFIGURATION_WEBRUNTIME_DATABASE_H + +#include +#include + +extern DPL::Mutex g_wrtDbQueriesMutex; + +#define WRT_DB_INTERNAL(tlsCommand, InternalType, interface) \ + static DPL::ThreadLocalVariable *tlsCommand##Ptr = NULL; \ + { \ + DPL::Mutex::ScopedLock lock(&g_wrtDbQueriesMutex); \ + if (!tlsCommand##Ptr) { \ + static DPL::ThreadLocalVariable tmp; \ + tlsCommand##Ptr = &tmp; \ + } \ + } \ + DPL::ThreadLocalVariable &tlsCommand = *tlsCommand##Ptr; \ + if (tlsCommand.IsNull()) { tlsCommand = InternalType(interface); } + +#define WRT_DB_SELECT(name, type, interface) WRT_DB_INTERNAL(name, \ + type::Select, \ + interface) + +#define WRT_DB_INSERT(name, type, interface) WRT_DB_INTERNAL(name, \ + type::Insert, \ + interface) + +#define WRT_DB_UPDATE(name, type, interface) WRT_DB_INTERNAL(name, \ + type::Update, \ + interface) + +#define WRT_DB_DELETE(name, type, interface) WRT_DB_INTERNAL(name, \ + type::Delete, \ + interface) + +#endif // WRT_ENGINE_SRC_CONFIGURATION_WEBRUNTIME_DATABASE_H diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/widget_config.h b/modules/widget_dao/include/dpl/wrt-dao-ro/widget_config.h new file mode 100644 index 0000000..c452814 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/widget_config.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file widget_config.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief Implementation file for widget config. + */ +#ifndef SRC_DOMAIN_WIDGET_CONFIG_H +#define SRC_DOMAIN_WIDGET_CONFIG_H + +#include +#include + +#include +#include +#include + +namespace WrtDB { +namespace WidgetConfig { +inline std::string GetWidgetBasePath(DPL::String tzPkgId) +{ + return PathBuilder() + .Append(GlobalConfig::GetWidgetUserDataPath()) + .Append(DPL::ToUTF8String(tzPkgId)) + .GetFullPath(); +} + +inline std::string GetWidgetWebLocalStoragePath(DPL::String tzPkgId) +{ + return PathBuilder(GetWidgetBasePath(tzPkgId)) + .Append(GlobalConfig::GetWidgetLocalStoragePath()) + .GetFullPath(); +} + +inline std::string GetWidgetPersistentStoragePath(DPL::String tzPkgId) +{ + return PathBuilder(GetWidgetBasePath(tzPkgId)) + .Append(GlobalConfig::GetWidgetPrivateStoragePath()) + .GetFullPath(); +} + +inline std::string GetWidgetTemporaryStoragePath(DPL::String tzPkgId) +{ + return PathBuilder(GetWidgetBasePath(tzPkgId)) + .Append(GlobalConfig::GetWidgetPrivateTempStoragePath()) + .GetFullPath(); +} + +inline std::string GetWidgetDesktopFilePath(DPL::String tzPkgId) +{ + return PathBuilder() + .Append(GlobalConfig::GetUserWidgetDesktopPath()) + .Append(DPL::ToUTF8String(tzPkgId)) + .Concat(".desktop") + .GetFullPath(); +} + +inline std::string GetWidgetSharedStoragePath(DPL::String tzPkgId) +{ + return PathBuilder() + .Append(GlobalConfig::GetWidgetUserDataPath()) + .Append(DPL::ToUTF8String(tzPkgId)) + .Concat(GlobalConfig::GetWidgetSharedPath()) + .GetFullPath(); +} + +inline std::string GetWidgetSharedDataStoragePath(DPL::String tzPkgId) +{ + return PathBuilder(GetWidgetSharedStoragePath(tzPkgId)) + .Concat(GlobalConfig::GetWidgetDataPath()) + .GetFullPath(); +} + +inline std::string GetWidgetSharedTrustedStoragePath(DPL::String tzPkgId) +{ + return PathBuilder(GetWidgetSharedStoragePath(tzPkgId)) + .Concat(GlobalConfig::GetWidgetTrustedPath()) + .GetFullPath(); +} + +inline std::string GetWidgetSharedResStoragePath(DPL::String tzPkgId) +{ + return PathBuilder(GetWidgetSharedStoragePath(tzPkgId)) + .Concat(GlobalConfig::GetWidgetResPath()) + .GetFullPath(); +} + +inline std::string GetWidgetNPRuntimePluginsPath(const DPL::String& tzPkgId) +{ + return PathBuilder(GetWidgetBasePath(tzPkgId)) + .Concat(GlobalConfig::GetWidgetSrcPath()) + .Append(GlobalConfig::GetNPRuntimePluginsPath()) + .GetFullPath(); +} +} // namespace WidgetConfig +} // namespace WrtDB + +#endif diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_read_only.h b/modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_read_only.h new file mode 100755 index 0000000..c82995d --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_read_only.h @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of widget dao class. + * + * @file widget_dao_read_only.h + * @author Yang Jie (jie2.yang@samsung.com) + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of widget dao + */ + +#ifndef _WRT_SRC_CONFIGURATION_WIDGET_DAO_READ_ONLY_H_ +#define _WRT_SRC_CONFIGURATION_WIDGET_DAO_READ_ONLY_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +enum CertificateSource { + SIGNATURE_AUTHOR = 0, + SIGNATURE_DISTRIBUTOR = 1, + SIGNATURE_DISTRIBUTOR2 = 2, + SIGNATURE_UNKNOWN = 3 +}; + +struct WidgetLocalizedInfo +{ + DPL::OptionalString name; + DPL::OptionalString shortName; + DPL::OptionalString description; + DPL::OptionalString license; + DPL::OptionalString licenseHref; +}; + +/** + * CertificateData + * A structure to hold certificate fingerprints. + */ +struct WidgetCertificateData +{ + enum Owner { AUTHOR, DISTRIBUTOR, DISTRIBUTOR2, UNKNOWN }; + enum Type { ROOT, ENDENTITY }; + + // type of signature: author/distributor + Owner owner; + // indicates whether this is ca certificate + Type type; + + // chain id number: relative BASE, where BASE is signatureBASE.xml + int chainId; + // certificate fingerprint digested by md5 + std::string strMD5Fingerprint; + // certificate fingerprint digestef by sha1 + std::string strSHA1Fingerprint; + // Common name field in certificate + DPL::String strCommonName; + + bool operator== (const WidgetCertificateData& certData) const + { + return certData.chainId == chainId && + certData.owner == owner && + certData.strCommonName == strCommonName && + certData.strMD5Fingerprint == strMD5Fingerprint && + certData.strSHA1Fingerprint == strSHA1Fingerprint; + } +}; + +typedef std::list WidgetCertificateDataList; + +typedef DPL::String Locale; +typedef std::set LocaleSet; +typedef std::list ExternalLocationList; + +/** + * WidgetRegisterInfo + * A structure to hold widget's information needed to be registered. + * @see WidgetConfigurationInfo + */ +struct WidgetRegisterInfo +{ + struct LocalizedIcon : public ConfigParserData::Icon + { + LocalizedIcon(const ConfigParserData::Icon& icon, + const LocaleSet& _availableLocales) : + ConfigParserData::Icon(icon), + availableLocales(_availableLocales) + {} + + LocaleSet availableLocales; + }; + + struct StartFileProperties + { + DPL::String encoding; + DPL::String type; + }; + + typedef std::map StartFilePropertiesForLocalesMap; + struct LocalizedStartFile + { + DPL::String path; + StartFilePropertiesForLocalesMap propertiesForLocales; + }; + + typedef std::list LocalizedIconList; + typedef std::list LocalizedStartFileList; + struct LocalizationData + { + LocalizedIconList icons; + LocalizedStartFileList startFiles; + }; + + //Constructor + WidgetRegisterInfo() : + webAppType(APP_TYPE_UNKNOWN), + configInfo(), + packagingType(PKG_TYPE_UNKNOWN) + {} + + WidgetType webAppType; + DPL::OptionalString guid; + DPL::OptionalString version; + DPL::OptionalString minVersion; + std::string baseFolder; + ConfigParserData configInfo; + LocalizationData localizationData; + + TizenPkgId tzPkgid; + TizenAppId tzAppid; + TizenAppId tzBackupAppid; + + time_t installedTime; + PackagingType packagingType; + EncryptedFileList encryptedFiles; + ExternalLocationList externalLocations; + DPL::OptionalString widgetInstalledPath; +}; + +typedef std::list CertificateChainList; +class IWidgetSecurity +{ + public: + virtual ~IWidgetSecurity(); + + virtual const WidgetCertificateDataList& getCertificateList() const = 0; + + virtual bool isRecognized() const = 0; + + virtual bool isDistributorSigned() const = 0; + + virtual void getCertificateChainList(CertificateChainList& list, + CertificateSource source) const = 0; +}; + +/** + * WidgetAuthorInfo. + * Structure to hold the information of widget's author. + */ +struct WidgetAuthorInfo +{ + DPL::OptionalString name; + DPL::OptionalString email; + DPL::OptionalString href; +}; + +typedef std::list WidgetCertificateCNList; +typedef std::list LanguageTagList; +typedef std::list HostList; +typedef std::list FingerPrintList; + +class WidgetDAOReadOnly +{ + public: + /** + * WidgetDAO Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + DECLARE_EXCEPTION_TYPE(Base, ReadOnlyProperty) + DECLARE_EXCEPTION_TYPE(Base, GUIDisNull) + DECLARE_EXCEPTION_TYPE(Base, UnexpectedEmptyResult) + DECLARE_EXCEPTION_TYPE(Base, WidgetNotExist) + DECLARE_EXCEPTION_TYPE(Base, AlreadyRegistered) + }; + + protected: + DbWidgetHandle m_widgetHandle; + + public: + struct WidgetLocalizedIconRow + { + int appId; + int iconId; + DPL::String widgetLocale; + }; + typedef std::list WidgetLocalizedIconList; + + struct WidgetIconRow + { + int iconId; + int appId; + DPL::String iconSrc; + DPL::OptionalInt iconWidth; + DPL::OptionalInt iconHeight; + }; + typedef std::list WidgetIconList; + + struct WidgetStartFileRow + { + int startFileId; + int appId; + DPL::String src; + }; + typedef std::list WidgetStartFileList; + + struct WidgetLocalizedStartFileRow + { + int startFileId; + int appId; + DPL::String widgetLocale; + DPL::String type; + DPL::String encoding; + }; + typedef std::list LocalizedStartFileList; + + /** + * This is a constructor. + * + * @param[in] widgetHandle application id of widget. + */ + WidgetDAOReadOnly(DbWidgetHandle widgetHandle); + WidgetDAOReadOnly(DPL::OptionalString widgetGUID); + WidgetDAOReadOnly(WrtDB::TizenAppId tzAppid); + + /** + * Destructor + */ + virtual ~WidgetDAOReadOnly(); + + /** + * This method returns widget handle(m_widgetHandle). + * + * @return widget handle(m_widgetHandle). + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DbWidgetHandle getHandle() const; + static DbWidgetHandle getHandle(const WidgetGUID GUID); + static DbWidgetHandle getHandle(const DPL::String tzAppId); + static DbWidgetHandle getHandleByPkgId(const DPL::String pkgId); + + /** + * This method Returns tizen application id for the specified web application + * @return TizenAppId + */ + TizenAppId getTzAppId() const DPL_DEPRECATED_WITH_MESSAGE("Use getTizenAppId"); + static TizenAppId getTzAppId(const WidgetGUID GUID) DPL_DEPRECATED_WITH_MESSAGE("Use getTizenAppId"); + static TizenAppId getTzAppId(const DbWidgetHandle handle) DPL_DEPRECATED_WITH_MESSAGE("Use getTizenAppId"); + static TizenAppId getTzAppId(const TizenPkgId tizenPkgId) DPL_DEPRECATED_WITH_MESSAGE("Use getTizenAppId"); + TizenAppId getTizenAppId() const; + static TizenAppId getTizenAppId(const WidgetGUID GUID); + static TizenAppId getTizenAppId(const DbWidgetHandle handle); + static TizenAppId getTizenAppId(const TizenPkgId tizenPkgId); + + /** + * This method returns list of installed tizen application id + * @return TizenAppIdList + */ + static TizenAppIdList getTizenAppidList() DPL_DEPRECATED_WITH_MESSAGE("Use getTizenAppIdList"); + static TizenAppIdList getTizenAppIdList(); + static std::list getTzAppIdList(const TizenPkgId tzPkgid); + + /** + * Returns TizenPkgId for the specified widget + * + * @return TizenPkgId; + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + + TizenPkgId getTzPkgId() const DPL_DEPRECATED_WITH_MESSAGE("Use getTizenPkgId"); + static TizenPkgId getTzPkgId(const DbWidgetHandle handle) DPL_DEPRECATED_WITH_MESSAGE("Use getTizenPkgId"); + static TizenPkgId getTzPkgId(const TizenAppId tzAppid) DPL_DEPRECATED_WITH_MESSAGE("Use getTizenPkgId"); + TizenPkgId getTizenPkgId() const; + static TizenPkgId getTizenPkgId(const DbWidgetHandle handle); + static TizenPkgId getTizenPkgId(const TizenAppId tzAppid); + + /** + * This method returns list of tizen package list of installed packages + * @return list of TizenPkgIdList of installed packages + */ + static TizenPkgIdList getTizenPkgidList() DPL_DEPRECATED_WITH_MESSAGE("Use getTizenPkgIdList"); + static TizenPkgIdList getTizenPkgIdList(); + + /** + * This method returns the root directory of widget resource. + * + * @return path name of root directory. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + virtual DPL::String getPath() const; + + DPL::String getFullPath() const; + + /** + * This method returns the preferred size of the widget, + * including width and height. + * + * @see DbWidgetSize + * @return An structure type variable to hold widget's size. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching + * DB table. + */ + DbWidgetSize getPreferredSize() const; + + /** + * This method returns the type of the widget. + * + * @return WidgetType + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching + * records in DB table. + */ + WidgetType getWidgetType() const; + + /** + * This method returns the id of the widget. + * + * @return widget id + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + WidgetGUID getGUID() const; + + /** + * This method returns the defaultlocale for the widget. + * + * @return defaultlocale + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DPL::OptionalString getDefaultlocale() const; + + /** + * This method returns list of localized icons files; + * + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + WidgetLocalizedIconList getLocalizedIconList() const; + + /** + * This method returns list of icons files; + * + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + WidgetIconList getIconList() const; + + /** + * This method returns list of localized start files; + * + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + LocalizedStartFileList getLocalizedStartFileList() const; + + /** + * This method returns list of start files; + * + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + WidgetStartFileList getStartFileList() const; + + /** + * @param[out] outAccessInfoList list filled with access info structures + */ + void getWidgetAccessInfo(WidgetAccessInfoList& outAccessInfoList) const; + void getWidgetAllowNavigationInfo( + WidgetAllowNavigationInfoList& allowNavigationInfoList) const; + + /** + * This method returns window mode of widget. + * + * @return window modes of widget + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + WindowModeList getWindowModes() const; + + /** + * This method returns the version of the widget. + * + * @return version of widget + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DPL::OptionalString getVersion() const; + + /** + * This method is used as a getter for csp policy of widget. It should be + * provided in configuration file. + * @return global csp policy for widget + */ + DPL::OptionalString getCspPolicy() const; + + /** + * This method is used as a getter for report only csp policy of widget. + * It may be provided in configuration file. + * @return global csp report only policy for widget + */ + DPL::OptionalString getCspPolicyReportOnly() const; + + /** + * This method returns list filed with Common Name entries from certificate. + * + * @return Common Name of Distribuotor End Entity certificate. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + WidgetCertificateCNList getKeyCommonNameList( + WidgetCertificateData::Owner owner, + WidgetCertificateData::Type type) const; + + /** + * given a certificate owner (author / distributor) and type of certificate + * (end entity / ca) + * function returns list of matching fingerprints + */ + FingerPrintList getKeyFingerprints( + WidgetCertificateData::Owner owner, + WidgetCertificateData::Type type) const; + + /* + * This method gets certificate data list for a widget from database. + */ + WidgetCertificateDataList getCertificateDataList() const; + + /** + * This method returns a list of widget features. + * + * @see WidgetFeature + * @see FreeFeatureList() + * @return list of widget features, type of list element is structure + * WidgetFeature + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DbWidgetFeatureSet getFeaturesList() const; + + /** + * This method checks whether widget has specified feature. + * + * @return true if has, false if has not + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + */ + bool hasFeature(const std::string& featureName) const; + + /** + * This method gets if widget needs webkit plugins enabled + * + * @return true: widget needs webkit plugins enabled + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + bool getWebkitPluginsRequired() const; + + /** + * This method returns a list of all the installed widgets. + * + * @return list of installed widgets. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + static DbWidgetDAOReadOnlyList getWidgetList(); + + /** + * This method gets author's infomation of a widget which is parsed from + * configiration document. + * + * @see WidgetAuthorInfo + * @param[out] pAuthorInfo + * @return true if succeed, false if fail. + */ + WidgetAuthorInfo getAuthorInfo() const; + + /** + * This method gets author's name of a widget which is parsed from + * configiration document. + * + * @param[out] pAuthorInfo + * @return author's name. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DPL::OptionalString getAuthorName() const; + + /** + * This method gets author's email of a widget which is parsed from + * configiration document. + * + * @param[out] pAuthorInfo + * @return author's email. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DPL::OptionalString getAuthorEmail() const; + + /** + * This method gets author's email of a widget which is parsed from + * configiration document. + * + * @param[out] pAuthorInfo + * @return author's email. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DPL::OptionalString getAuthorHref() const; + + /** + * This method returns minimum version of WAC that WRT has to be compliant + * to to run this widget + * + * @return Minimum version + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + DPL::OptionalString getMinimumWacVersion() const; + + /** + * This method get widget installed time + * + * @return time_t : return widget's install time + */ + time_t getInstallTime() const; + + /** + * This method gets widget base folder. + * + * @return widget base folder. + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching records in + * DB table. + */ + std::string getBaseFolder() const; + + /* This method checks read only flag for given property + */ + DPL::OptionalInt checkPropertyReadFlag( + const PropertyDAOReadOnly::WidgetPropertyKey &key) const; + + /* This method gets widget property key list + */ + PropertyDAOReadOnly::WidgetPropertyKeyList getPropertyKeyList() const; + + /* This method gets widget property list + */ + PropertyDAOReadOnly::WidgetPreferenceList getPropertyList() const; + + /* This method get widget property value + */ + PropertyDAOReadOnly::WidgetPropertyValue getPropertyValue( + const PropertyDAOReadOnly::WidgetPropertyKey &key) const; + + LanguageTagList getLanguageTags() const; + LanguageTagList getIconLanguageTags() const; + + WidgetLocalizedInfo getLocalizedInfo(const DPL::String& languageTag) const; + + bool getBackSupported() const; + + static bool isWidgetInstalled(DbWidgetHandle handle); + static bool isWidgetInstalled(const TizenAppId & tzAppId); + + /* This method get path of the splash image. + * + * @return path of the widget's splash image + */ + DPL::OptionalString getSplashImgSrc() const; + + ExternalLocationList getWidgetExternalLocations() const; + + /* + * Default value is required to keep compatibility with + * wrt-installer and wrt. + */ + CertificateChainList getWidgetCertificate( + CertificateSource source = SIGNATURE_DISTRIBUTOR) const; + + void getWidgetSettings(WidgetSettings& outWidgetSettings) const; + + /** + * This method gets application control list that define AUL value + * + * @return See above comment + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + */ + void getAppControlList( + WidgetAppControlList& outAppControlList) const; + + /** + * This method returns the type of the package. + * + * @return PackagingType + * @exception WRT_CONF_ERR_EMDB_FAILURE - Fail to query DB table. + * @exception WRT_CONF_ERR_EMDB_NO_RECORD - Can not find matching + * records in DB table. + */ + PackagingType getPackagingType() const; + + void getEncryptedFileList(EncryptedFileList& filesList) const; + + /** + * This method returns widget's background page filename. + * + * @return Name of file containing background page + */ + DPL::OptionalString getBackgroundPage() const; + + /** + * @brief generateTizenId generates new package id + * + * If widget do not supplies it's own tizen package id, this method can be + * used, + * although it should be removed in future. + * + * @return new tizen package id + */ + static TizenPkgId generatePkgId(); + static TizenPkgId generateTizenId() + { + return generatePkgId(); + } + + /** + * This method returns widget's installed path + * + * @return path of widget installed + */ + DPL::OptionalString getWidgetInstalledPath() const; + PrivilegeList getWidgetPrivilege() const; + WidgetSecurityModelVersion getSecurityModelVersion() const; + +}; +} // namespace WrtDB + +#endif // _WRT_SRC_CONFIGURATION_WIDGET_DAO_READ_ONLY_H_ + diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_types.h b/modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_types.h new file mode 100644 index 0000000..6d6e171 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/widget_dao_types.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file widget_dao_types.h + * @author Leerang Song (leerang.song@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of + * common data types forwidget database. + */ +#ifndef _WIDGET_DAO_TYPES_H_ +#define _WIDGET_DAO_TYPES_H_ + +#include +#include +#include +#include + +namespace WrtDB { + +enum Feature +{ + FEATURE_START = 0, + FEATURE_GEOLOCATION = 0, + FEATURE_WEB_NOTIFICATION, + FEATURE_USER_MEDIA, + FEATURE_FULLSCREEN_MODE, + FEATURE_WEB_DATABASE, + FEATURE_CAMERA, + FEATURE_AUDIO_RECORDER, + FEATURE_END +}; +extern const std::map g_W3CPrivilegeTextMap; +} // namespace WrtDB + +#endif // _WIDGET_DAO_TYPES_H_ diff --git a/modules/widget_dao/include/dpl/wrt-dao-ro/wrt_db_types.h b/modules/widget_dao/include/dpl/wrt-dao-ro/wrt_db_types.h new file mode 100644 index 0000000..1702433 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-ro/wrt_db_types.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * + * @file wrt_db_types.h + * @author Krzysztof Jackiewicz + * @version 1.0 + * @brief This file contains the declaration of common data types for wrtdb + */ +#ifndef _WRT_DB_TYPES_H_ +#define _WRT_DB_TYPES_H_ + +#include + +typedef WrtDB::DbWidgetHandle WidgetHandle; +typedef WrtDB::DbWidgetHandleList WidgetHandleList; +typedef WrtDB::DbWidgetDAOReadOnlyList WidgetDAOReadOnlyList; + +typedef WrtDB::DbWidgetFeature WidgetFeature; +typedef WrtDB::DbWidgetFeatureSet WidgetFeatureSet; + +typedef WrtDB::DbWidgetSize WidgetSize; +typedef WrtDB::DbPluginHandle PluginHandle; + +#endif diff --git a/modules/widget_dao/include/dpl/wrt-dao-rw/feature_dao.h b/modules/widget_dao/include/dpl/wrt-dao-rw/feature_dao.h new file mode 100644 index 0000000..6ee312a --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-rw/feature_dao.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of feature dao class. + * + * @file feature_dao.h + * @author Jaroslaw Osmanski (j.osmanski@samsung.com) + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of feature dao + */ +#ifndef _FEATURE_DAO_H +#define _FEATURE_DAO_H + +#include + +namespace WrtDB { +namespace FeatureDAO { +FeatureHandle RegisterFeature(const PluginMetafileData::Feature &feature, + const DbPluginHandle pluginHandle); +void UnregisterFeature(FeatureHandle featureHandle); +} // namespace FeatureDB +} // namespace WrtDB + +#endif /* _FEATURE_DAO_H */ + diff --git a/modules/widget_dao/include/dpl/wrt-dao-rw/plugin_dao.h b/modules/widget_dao/include/dpl/wrt-dao-rw/plugin_dao.h new file mode 100644 index 0000000..0b53eef --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-rw/plugin_dao.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of plugin dao class. + * + * @file plugin_dao.h + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of plugin dao + */ + +#ifndef WRT_SRC_CONFIGURATION_PLUGIN_DAO_H_ +#define WRT_SRC_CONFIGURATION_PLUGIN_DAO_H_ + +#include + +namespace WrtDB { +class PluginDAO : public PluginDAOReadOnly +{ + public: + PluginDAO(DbPluginHandle pluginHandle); + PluginDAO(const std::string &libraryName); + + static DbPluginHandle registerPlugin( + const PluginMetafileData& metafile, + const std::string& pluginPath); + + static void registerPluginImplementedObject( + const std::string& objectName, + DbPluginHandle pluginHandle); + + static void registerPluginRequiredObject( + const std::string& objectName, + DbPluginHandle pluginHandle); + + static void registerPluginLibrariesDependencies( + DbPluginHandle plugin, + const PluginHandleSetPtr& dependencies); + + static void setPluginInstallationStatus( + DbPluginHandle, + PluginInstallationState); + + static void unregisterPlugin(DbPluginHandle pluginHandle); +}; +} // namespace WrtDB + +#endif /* WRT_SRC_CONFIGURATION_PLUGIN_DAO_H_ */ diff --git a/modules/widget_dao/include/dpl/wrt-dao-rw/property_dao.h b/modules/widget_dao/include/dpl/wrt-dao-rw/property_dao.h new file mode 100644 index 0000000..7e3f215 --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-rw/property_dao.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file property_dao.h + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of property dao + */ + +#ifndef WRT_SRC_CONFIGURATION_PROPERTY_DAO_H_ +#define WRT_SRC_CONFIGURATION_PROPERTY_DAO_H_ + +#include + +namespace WrtDB { +struct WidgetRegisterInfo; //forward declaration + +namespace PropertyDAO { +void RemoveProperty(TizenAppId tzAppid, + const PropertyDAOReadOnly::WidgetPropertyKey &key); + +//deprecated +/* This method sets widget property + */ +void SetProperty(DbWidgetHandle widgetHandle, + const PropertyDAOReadOnly::WidgetPropertyKey &key, + const PropertyDAOReadOnly::WidgetPropertyValue &value, + bool readOnly = false) +__attribute__((deprecated)); + +/* This method sets widget property + */ +void SetProperty(TizenAppId tzAppid, + const PropertyDAOReadOnly::WidgetPropertyKey &key, + const PropertyDAOReadOnly::WidgetPropertyValue &value, + bool readOnly = false); + +/* This method registers properties for widget. + * Properties unregistering is done via "delete cascade" mechanism in SQL + */ +void RegisterProperties(DbWidgetHandle widgetHandle, TizenAppId tzAppid, + const WidgetRegisterInfo ®Info); +} // namespace PropertyDAO +} // namespace WrtDB + +#endif /* WRT_SRC_CONFIGURATION_PROPERTY_DAO_H_ */ diff --git a/modules/widget_dao/include/dpl/wrt-dao-rw/widget_dao.h b/modules/widget_dao/include/dpl/wrt-dao-rw/widget_dao.h new file mode 100755 index 0000000..d205ccf --- /dev/null +++ b/modules/widget_dao/include/dpl/wrt-dao-rw/widget_dao.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of widget dao class. + * + * @file widget_dao.h + * @author Yang Jie (jie2.yang@samsung.com) + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains the declaration of widget dao + */ +#ifndef WIDGET_DAO_H +#define WIDGET_DAO_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WrtDB { +class WidgetDAO : public WidgetDAOReadOnly +{ + public: + typedef std::list LanguageTagsList; + + WidgetDAO(DPL::OptionalString widgetGUID); + WidgetDAO(DPL::String tzAppId); + + /** + * Destructor + */ + virtual ~WidgetDAO(); + + /** + * This method registers the widget information in the DB when it is + * installed. + * + * @see WidgetRegisterInfo + * @see UnRegisterWidget() + * @param[in] TizenAppId Widget app id that will be registered. + * @param[in] pWidgetRegisterInfo Specified the widget's information + * needed to be registered. + * @param[in] widgetSecurity Widget's security certificates. + */ + static void registerWidget( + const TizenAppId& tzAppId, + const WidgetRegisterInfo &widgetRegInfo, + const IWidgetSecurity &widgetSecurity); + + static void registerService( + const ConfigParserData::ServiceAppInfo &serviceAppInfo, + const WidgetRegisterInfo &widgetRegInfo, + const IWidgetSecurity &widgetSecurity); + + /** + * @brief registerWidgetGenerateTizenId Registers widget with auto-generated + * tizen id + * + * This function is disadviced and should be used only in tests. + * Function is not thread-safe. + * + * @param pWidgetRegisterInfo registeration information + * @param widgetSecurity Widget's security certificates. + * @return tzAppId generated + */ + static TizenAppId registerWidgetGeneratePkgId( + const WidgetRegisterInfo &pWidgetRegisterInfo, + const IWidgetSecurity &widgetSecurity); + + static void updateTizenAppId(const TizenAppId & fromAppId, + const TizenAppId & toAppId); + /** + * This method removes a widget's information from EmDB. + * + * @see RegisterWidget() + * @param[in] tzAppId widgets name to be unregistered + */ + static void unregisterWidget(const TizenAppId & tzAppId); + + /* This method removes widget property + */ + void removeProperty(const PropertyDAOReadOnly::WidgetPropertyKey &key); + + /** + * @brief registerExternalLocations Removes rows from + * WidgetExternalLocations + */ + void unregisterAllExternalLocations(); + + /* This method sets widget property + */ + void setProperty(const PropertyDAOReadOnly::WidgetPropertyKey &key, + const PropertyDAOReadOnly::WidgetPropertyValue &value, + bool readOnly = false); + + /* set tzAppId + */ + void setTizenAppId(const DPL::OptionalString& tzAppId); + + /* This function will update of api-feature status. + * If status is true (feature rejected) plugin connected with this + * api feature mustn't be loaded durign widget launch. + */ + void updateFeatureRejectStatus(const DbWidgetFeature &widgetFeature); + + private: + //Methods used during widget registering + static DbWidgetHandle registerWidgetInfo( + const TizenAppId & tzAppId, + const TizenPkgId & tzPkgId, + const std::string & baseFolder, + AppType appType, + PkgType pkgType, + const ConfigParserData &widgetConfigurationInfo, + const IWidgetSecurity &widgetSecurity, + const DPL::Optional handle = + DPL::Optional()); + static void registerWidgetExtendedInfo(DbWidgetHandle widgetHandle, + time_t installedTime, + const DPL::OptionalString & splashImgSrc, const DPL::OptionalString & backgroundPage, + const DPL::OptionalString & widgetInstalledPath); + static void registerWidgetLocalizedInfo( + DbWidgetHandle widgetHandle, + const ConfigParserData::LocalizedDataSet &localizedDataSet); + static void registerWidgetIcons( + DbWidgetHandle widgetHandle, + const WidgetRegisterInfo::LocalizedIconList &icons); + static void registerWidgetStartFile( + DbWidgetHandle widgetHandle, + const WidgetRegisterInfo::LocalizedStartFileList &startFiles); + static void registerWidgetFeatures( + DbWidgetHandle widgetHandle, + const ConfigParserData::FeaturesList &featuresList); + static void registerWidgetPrivilege( + DbWidgetHandle widgetHandle, + const ConfigParserData::PrivilegeList &privilegeList); + static void registerWidgetWindowModes( + DbWidgetHandle widgetHandle, + const ConfigParserData::StringsList &windowModes); + static void registerWidgetWarpInfo( + DbWidgetHandle widgetHandle, + const ConfigParserData::AccessInfoSet &accessInfoSet); + static void registerWidgetAllowNavigationInfo( + DbWidgetHandle widgetHandle, + const ConfigParserData::AllowNavigationInfoList &allowNavigationInfoList); + static void registerWidgetCertificates( + DbWidgetHandle widgetHandle, + const IWidgetSecurity &widgetSecurity); + static void registerCertificatesChains( + DbWidgetHandle widgetHandle, + CertificateSource certificateSource, + const CertificateChainList &list); + static void registerWidgetSettings( + DbWidgetHandle widgetHandle, + const ConfigParserData::SettingsList &settingsList); + static void registerAppControl( + DbWidgetHandle widgetHandle, + const ConfigParserData::AppControlInfoList &appControlList); + static void registerEncryptedResouceInfo( + DbWidgetHandle widgetHandle, + const EncryptedFileList &encryptedFiles); + + /** + * @brief registerExternalLocations Inserts new rows to + * WidgetExternalLocations + * @param externals list of files + */ + static void registerExternalLocations( + DbWidgetHandle widgetHandle, + const ExternalLocationList & + externals); + + static void registerServiceInternal(const ConfigParserData::ServiceAppInfo &serviceAppInfo, + const WidgetRegisterInfo &widgetRegInfo, const IWidgetSecurity &widgetSecurity); + + static void registerWidgetInternal( + const TizenAppId & tzAppId, + const WidgetRegisterInfo &widgetRegInfo, + const IWidgetSecurity &widgetSecurity, + const DPL::Optional handle = + DPL::Optional()); + static void unregisterWidgetInternal(const TizenAppId & tzAppId); + static void insertAppControlInfo(DbWidgetHandle handle, + DPL::String src, + DPL::String operation, + DPL::String uri, + DPL::String mime, + unsigned index, + unsigned disposition); +}; +} // namespace WrtDB + +#endif // WIDGET_DAO_H diff --git a/modules/widget_dao/orm/gen_db_md5.sh b/modules/widget_dao/orm/gen_db_md5.sh new file mode 100755 index 0000000..38587b7 --- /dev/null +++ b/modules/widget_dao/orm/gen_db_md5.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +CHECKSUM=`cat ${2} ${3} 2>/dev/null | md5sum 2>/dev/null | cut -d\ -f1 2>/dev/null` +echo "#define DB_CHECKSUM DB_VERSION_${CHECKSUM}" > ${1} +echo "#define DB_CHECKSUM_STR \"DB_VERSION_${CHECKSUM}\"" >> ${1} + diff --git a/modules/widget_dao/orm/orm_generator_wrt.h b/modules/widget_dao/orm/orm_generator_wrt.h new file mode 100644 index 0000000..09ac57e --- /dev/null +++ b/modules/widget_dao/orm/orm_generator_wrt.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ORM_GENERATOR_WRT_H +#define ORM_GENERATOR_WRT_H + +#define ORM_GENERATOR_DATABASE_NAME wrt_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif diff --git a/modules/widget_dao/orm/version_db b/modules/widget_dao/orm/version_db new file mode 100644 index 0000000..7e20d8d --- /dev/null +++ b/modules/widget_dao/orm/version_db @@ -0,0 +1,5 @@ +SQL( + BEGIN TRANSACTION; + CREATE TABLE DB_CHECKSUM (version INT); + COMMIT; +) diff --git a/modules/widget_dao/orm/wrt_db b/modules/widget_dao/orm/wrt_db new file mode 100644 index 0000000..4d31747 --- /dev/null +++ b/modules/widget_dao/orm/wrt_db @@ -0,0 +1,314 @@ +SQL( + PRAGMA foreign_keys = ON; + BEGIN TRANSACTION; +) + +CREATE_TABLE(WidgetInfo) + COLUMN_NOT_NULL(app_id, INTEGER, PRIMARY KEY AUTOINCREMENT) + COLUMN(widget_type, INT, DEFAULT 1) + COLUMN(widget_id, TEXT, DEFAULT '') + COLUMN(widget_version, TEXT, DEFAULT '') + COLUMN(widget_width, INT, DEFAULT 0) + COLUMN(widget_height, INT, DEFAULT 0) + COLUMN(author_name, TEXT, DEFAULT '') + COLUMN(author_email, TEXT, DEFAULT '') + COLUMN(author_href, TEXT, DEFAULT '') + COLUMN(base_folder, TEXT, DEFAULT '') + COLUMN(webkit_plugins_required, TINYINT, DEFAULT 0) + COLUMN(csp_policy, TEXT, DEFAULT '') + COLUMN(csp_policy_report_only, TEXT, DEFAULT '') + COLUMN(wac_signed, INT, DEFAULT 0) + COLUMN(min_version, TEXT, DEFAULT '1.0') + COLUMN_NOT_NULL(back_supported, TINYINT, DEFAULT 0) + COLUMN(access_network, TINYINT, DEFAULT 0) + COLUMN(defaultlocale, TEXT, DEFAULT 0) + COLUMN_NOT_NULL(tizen_pkgid, TEXT, DEFAULT '') + COLUMN_NOT_NULL(tizen_appid, TEXT, DEFAULT 0 UNIQUE) + COLUMN(pkg_type, INT, DEFAULT 0) + COLUMN(security_model_version, INT, DEFAULT 0) +CREATE_TABLE_END() + +SQL( + CREATE INDEX IF NOT EXISTS WidgetInfo_AppidIndex ON WidgetInfo(tizen_appid); +) + +CREATE_TABLE(WidgetCertificate) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(cert_source, INT, CHECK(cert_source between 0 and 2)) + COLUMN_NOT_NULL(encoded_chain, VARCHAR(16000),) + TABLE_CONSTRAINTS( + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetWindowModes) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(window_mode, VARCHAR(256),) + TABLE_CONSTRAINTS( + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(LocalizedWidgetInfo) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(widget_locale, TEXT,) + COLUMN(widget_name, TEXT,) + COLUMN(widget_shortname, TEXT,) + COLUMN(widget_description, TEXT,) + COLUMN(widget_license, TEXT,) + COLUMN(widget_license_file, TEXT,) + COLUMN(widget_license_href, TEXT,) + + TABLE_CONSTRAINTS( + PRIMARY KEY (app_id, widget_locale), + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetExtendedInfo) + COLUMN_NOT_NULL(app_id, INTEGER, PRIMARY KEY) + COLUMN(last_update_time, BIGINT, DEFAULT 0) + COLUMN(install_time, BIGINT, DEFAULT 0) + COLUMN(option_state, INT, DEFAULT 0) + COLUMN(updated, INT, DEFAULT 0) + COLUMN(update_policy, INT, DEFAULT 0) + COLUMN_NOT_NULL(test_widget, INT, CHECK(test_widget between 0 and 1) DEFAULT 0) + COLUMN(splash_img_src, TEXT, DEFAULT '') + COLUMN(background_page, TEXT, DEFAULT '') + COLUMN(installed_path, TEXT, DEFAULT '') + TABLE_CONSTRAINTS( + FOREIGN KEY(app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetPreference) + COLUMN_NOT_NULL(app_id, INTEGER,) + COLUMN_NOT_NULL(tizen_appid, TEXT, DEFAULT 0) + COLUMN_NOT_NULL(key_name, TEXT,) + COLUMN(key_value, TEXT, DEFAULT '') + COLUMN(readonly, INT, DEFAULT 0) + + TABLE_CONSTRAINTS( + PRIMARY KEY(app_id, key_name), + FOREIGN KEY(app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetFeature) + COLUMN_NOT_NULL(widget_feature_id, INTEGER, primary key autoincrement) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(name, TEXT,) + COLUMN_NOT_NULL(rejected, INT,) + TABLE_CONSTRAINTS( + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetPrivilege) + COLUMN_NOT_NULL(widget_privilege_id, INTEGER, primary key autoincrement) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(name, TEXT,) + TABLE_CONSTRAINTS( + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetIcon) + COLUMN_NOT_NULL(icon_id, INTEGER, primary key autoincrement) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(icon_src, TEXT,) + COLUMN(icon_width, INT, DEFAULT 0) + COLUMN(icon_height, INT, DEFAULT 0) + TABLE_CONSTRAINTS( + FOREIGN KEY(app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetLocalizedIcon) + COLUMN_NOT_NULL(app_id, INT,) /* TODO key duplicated for efficiency - ORM doesn't support JOIN */ + COLUMN_NOT_NULL(icon_id, INTEGER,) + COLUMN_NOT_NULL(widget_locale, TEXT,) + TABLE_CONSTRAINTS( + FOREIGN KEY(icon_id) REFERENCES WidgetIcon (icon_id) ON DELETE CASCADE, + PRIMARY KEY(icon_id, widget_locale) + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetStartFile) + COLUMN_NOT_NULL(start_file_id, INTEGER, primary key autoincrement) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(src, TEXT,) + TABLE_CONSTRAINTS( + FOREIGN KEY(app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetLocalizedStartFile) + COLUMN_NOT_NULL(app_id, INT,) /* TODO key duplicated for efficiency - ORM doesn't support JOIN */ + COLUMN_NOT_NULL(start_file_id, INTEGER,) + COLUMN_NOT_NULL(widget_locale, TEXT,) + COLUMN_NOT_NULL(type, TEXT,) + COLUMN_NOT_NULL(encoding, TEXT,) + TABLE_CONSTRAINTS( + FOREIGN KEY(start_file_id) REFERENCES WidgetStartFile (start_file_id) ON DELETE CASCADE, + PRIMARY KEY(start_file_id, widget_locale) + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetExternalLocations) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(path, TEXT,) + TABLE_CONSTRAINTS( + FOREIGN KEY(app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE, + PRIMARY KEY(app_id, path) + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetCertificateFingerprint) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(owner, INT,) + COLUMN_NOT_NULL(chainid, INT,) + COLUMN_NOT_NULL(type, INT,) + COLUMN(md5_fingerprint, TEXT,) + COLUMN(sha1_fingerprint, TEXT,) + COLUMN(common_name, VARCHAR(64),) + + TABLE_CONSTRAINTS( + PRIMARY KEY(app_id, chainid, owner, type) + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetWARPInfo) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(iri, TEXT,) + COLUMN(subdomain_access, INT, CHECK(subdomain_access between 0 and 1)) + + TABLE_CONSTRAINTS( + PRIMARY KEY(app_id, iri) + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(WidgetAllowNavigation) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(scheme, TEXT,) + COLUMN_NOT_NULL(host, TEXT,) + + TABLE_CONSTRAINTS( + PRIMARY KEY(app_id, scheme, host) + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(FeaturesList) + COLUMN_NOT_NULL(FeatureUUID, INTEGER, primary key autoincrement) + COLUMN_NOT_NULL(FeatureName, TEXT, unique) + COLUMN_NOT_NULL(PluginPropertiesId, INT,) + + TABLE_CONSTRAINTS( + FOREIGN KEY (PluginPropertiesId) REFERENCES PluginProperties (PluginPropertiesId) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(PluginProperties) + COLUMN_NOT_NULL(PluginPropertiesId, INTEGER, primary key autoincrement) + COLUMN_NOT_NULL(InstallationState, INTEGER, DEFAULT 0) + COLUMN_NOT_NULL(PluginLibraryName, TEXT, unique) + COLUMN(PluginLibraryPath, TEXT,) +CREATE_TABLE_END() + +CREATE_TABLE(PluginDependencies) + COLUMN_NOT_NULL(PluginPropertiesId, INTEGER, not null) + COLUMN_NOT_NULL(RequiredPluginPropertiesId, INTEGER, not null) + + TABLE_CONSTRAINTS( + FOREIGN KEY (PluginPropertiesId) REFERENCES PluginProperties (PluginPropertiesId) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(PluginImplementedObjects) + COLUMN_NOT_NULL(PluginObject, TEXT, unique) + COLUMN_NOT_NULL(PluginPropertiesId, INTEGER, not null) + + TABLE_CONSTRAINTS( + FOREIGN KEY (PluginPropertiesId) REFERENCES PluginProperties (PluginPropertiesId) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(PluginRequiredObjects) + COLUMN_NOT_NULL(PluginPropertiesId, INTEGER, not null) + COLUMN_NOT_NULL(PluginObject, TEXT, not null) + + TABLE_CONSTRAINTS( + FOREIGN KEY (PluginPropertiesId) REFERENCES PluginProperties (PluginPropertiesId) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(DeviceCapabilities) + COLUMN_NOT_NULL(DeviceCapID, INTEGER, primary key autoincrement) + COLUMN_NOT_NULL(DeviceCapName, TEXT, unique) + COLUMN(DeviceCapDefaultValue, INT,) +CREATE_TABLE_END() + +CREATE_TABLE(FeatureDeviceCapProxy) + COLUMN_NOT_NULL(FeatureUUID, INT, not null) + COLUMN_NOT_NULL(DeviceCapID, INT, not null) + + TABLE_CONSTRAINTS( + FOREIGN KEY (FeatureUUID) REFERENCES FeaturesList (FeatureUUID) ON DELETE CASCADE + FOREIGN KEY (DeviceCapID) REFERENCES DeviceCapabilities (DeviceCapID) ON DELETE CASCADE + PRIMARY KEY(FeatureUUID,DeviceCapID) + ) +CREATE_TABLE_END() + +CREATE_TABLE(OCSPResponseStorage) + COLUMN_NOT_NULL(cert_chain, TEXT, primary key) + COLUMN(end_entity_check, INT,) + COLUMN(ocsp_status, INT,) + COLUMN(next_update_time, BIGINT,) +CREATE_TABLE_END() + +CREATE_TABLE(CRLResponseStorage) + COLUMN_NOT_NULL(distribution_point,TEXT, primary key) + COLUMN_NOT_NULL(crl_body, TEXT,) + COLUMN(next_update_time, BIGINT,) +CREATE_TABLE_END() + +CREATE_TABLE(SettingsList) + COLUMN_NOT_NULL(appId, INT,) + COLUMN_NOT_NULL(settingName, TEXT,) + COLUMN_NOT_NULL(settingValue, TEXT,) + TABLE_CONSTRAINTS( + FOREIGN KEY (appId) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(AppControlInfo) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(execute_index, INT,) + COLUMN_NOT_NULL(src, TEXT,) + COLUMN_NOT_NULL(operation, TEXT,) + COLUMN_NOT_NULL(uri, TEXT,) + COLUMN_NOT_NULL(mime, TEXT,) + COLUMN_NOT_NULL(disposition, TINYINT, DEFAULT 0) + + TABLE_CONSTRAINTS( + PRIMARY KEY(app_id, operation, uri, mime) + FOREIGN KEY(app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +CREATE_TABLE(EncryptedResourceList) + COLUMN_NOT_NULL(app_id, INT,) + COLUMN_NOT_NULL(resource, TEXT,) + COLUMN_NOT_NULL(size, INT,) + + TABLE_CONSTRAINTS( + FOREIGN KEY (app_id) REFERENCES WidgetInfo (app_id) ON DELETE CASCADE + ) +CREATE_TABLE_END() + +SQL( + COMMIT; +) diff --git a/modules/widget_dao/orm/wrt_db_definitions b/modules/widget_dao/orm/wrt_db_definitions new file mode 100644 index 0000000..f2a4a2e --- /dev/null +++ b/modules/widget_dao/orm/wrt_db_definitions @@ -0,0 +1,6 @@ +DATABASE_START(wrt) + +#include "wrt_db" +#include "version_db" + +DATABASE_END() diff --git a/modules/widget_dao/orm/wrt_db_sql_generator.h b/modules/widget_dao/orm/wrt_db_sql_generator.h new file mode 100644 index 0000000..1b69679 --- /dev/null +++ b/modules/widget_dao/orm/wrt_db_sql_generator.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file wrt_db_sql_generator.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL input file from + * database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. + +#include + +#include "wrt_db_definitions" diff --git a/modules/widget_interface_dao/CMakeLists.txt b/modules/widget_interface_dao/CMakeLists.txt new file mode 100644 index 0000000..6e4c409 --- /dev/null +++ b/modules/widget_interface_dao/CMakeLists.txt @@ -0,0 +1,46 @@ +SET(TARGET_WIDGET_INTERFACE_DAO_DB "Sqlite3DbWidgetInterface") + +ADD_CUSTOM_COMMAND( OUTPUT .widget_interface.db + COMMAND rm -f ${CMAKE_CURRENT_BINARY_DIR}/.widget_interface.db + COMMAND gcc -Wall -I${PROJECT_SOURCE_DIR}/modules/db/include -I${PROJECT_SOURCE_DIR}/modules/widget_interface_dao/orm -E ${PROJECT_SOURCE_DIR}/modules/widget_interface_dao/orm/widget_interface_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_BINARY_DIR}/widget_interface_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_BINARY_DIR}/.widget_interface.db ".read ${CMAKE_CURRENT_BINARY_DIR}/widget_interface_db.sql" || rm -f ${CMAKE_CURRENT_BINARY_DIR}/.widget_interface.db + DEPENDS ${PROJECT_SOURCE_DIR}/modules/widget_interface_dao/orm/widget_interface_db_sql_generator.h ${PROJECT_SOURCE_DIR}/modules/widget_interface_dao/orm/widget_interface_db + ) + +ADD_CUSTOM_TARGET(${TARGET_WIDGET_INTERFACE_DAO_DB} ALL DEPENDS .widget_interface.db) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/widget_interface_db.sql DESTINATION share/wrt-engine/) + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(WIDGET_INTERFACE_DAO_DEPS + glib-2.0 + dlog + REQUIRED) + +SET(WIDGET_INTERFACE_DAO_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/modules/widget_interface_dao/include + ${PROJECT_SOURCE_DIR}/modules/widget_interface_dao/orm + ${PROJECT_SOURCE_DIR}/modules/core/include + ${PROJECT_SOURCE_DIR}/modules/db/include + ${PROJECT_SOURCE_DIR}/modules/log/include + ${PROJECT_SOURCE_DIR}/modules/widget_dao/include +) + +SET(WIDGET_INTERFACE_DAO_SOURCES + dao/widget_interface_dao.cpp +) + +INCLUDE_DIRECTORIES(SYSTEM ${WIDGET_INTERFACE_DAO_DEPS_INCLUDE_DIRS} ) +INCLUDE_DIRECTORIES(${WIDGET_INTERFACE_DAO_INCLUDE_DIRS}) + +ADD_LIBRARY(${TARGET_WIDGET_INTERFACE_DAO_LIB} SHARED ${WIDGET_INTERFACE_DAO_SOURCES}) +SET_TARGET_PROPERTIES(${TARGET_WIDGET_INTERFACE_DAO_LIB} PROPERTIES SOVERSION ${API_VERSION} VERSION ${VERSION}) +TARGET_LINK_LIBRARIES(${TARGET_WIDGET_INTERFACE_DAO_LIB} ${TARGET_DPL_EFL} ${TARGET_DPL_DB_EFL} ${TARGET_WRT_DAO_RO_LIB} ${WIDGET_INTERFACE_DAO_DEPS_LIBRARIES}) +ADD_DEPENDENCIES(${TARGET_WIDGET_INTERFACE_DAO_LIB} ${TARGET_WIDGET_INTERFACE_DAO_DB}) + +INSTALL(TARGETS ${TARGET_WIDGET_INTERFACE_DAO_LIB} DESTINATION lib) + +INSTALL(FILES + include/wrt-commons/widget-interface-dao/widget_interface_dao.h + DESTINATION include/dpl-efl/wrt-commons/widget-interface-dao +) diff --git a/modules/widget_interface_dao/dao/widget_interface_dao.cpp b/modules/widget_interface_dao/dao/widget_interface_dao.cpp new file mode 100644 index 0000000..1d66ed8 --- /dev/null +++ b/modules/widget_interface_dao/dao/widget_interface_dao.cpp @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Lukasz Marek (l.marek@samsung.com) + * @version 0.1 + * @brief + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "orm_generator_widget_interface.h" + +namespace WidgetInterfaceDB { +using namespace DPL::DB::ORM; +using namespace DPL::DB::ORM::widget_interface; + +#define SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN Try +#define SQL_CONNECTION_EXCEPTION_HANDLER_END(message) \ + Catch(DPL::DB::SqlConnection::Exception::Base) { \ + LogError(message); \ + ReThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError, \ + message); \ + } + +namespace { +DPL::DB::SqlConnection::Flag::Type DATABASE_FLAG = + DPL::DB::SqlConnection::Flag::UseLucene; +DPL::DB::SqlConnection::Flag::Option DATABASE_OPTION = + DPL::DB::SqlConnection::Flag::RW; +const char *KEY_WIDGET_ARG = "widget_arg"; + +const char* const DATABASE_NAME = ".widget_interface.db"; +const char* const DATABASE_FILE_PATH = + "/usr/share/wrt-engine/widget_interface_db.sql"; +const char* const DATABASE_JOURNAL_FILENAME = "-journal"; + +const int APP_UID = 5000; +const int APP_GUID = 5000; +} // anonymous namespace + +WidgetInterfaceDAO::WidgetInterfaceDAO(int widgetHandle) : + m_widgetHandle(widgetHandle), + m_databaseInterface(databaseFileName(widgetHandle), DATABASE_FLAG) +{ + checkDatabase(); + m_databaseInterface.AttachToThread(DATABASE_OPTION); +} + +WidgetInterfaceDAO::~WidgetInterfaceDAO() +{ + m_databaseInterface.DetachFromThread(); +} + +void WidgetInterfaceDAO::checkDatabase() +{ + std::string databaseFile = databaseFileName(m_widgetHandle); + struct stat buffer; + if (stat(databaseFile.c_str(), &buffer) != 0) { + //Create fresh database + LogDebug("Creating database " << databaseFile); + + std::fstream file; + file.open(DATABASE_FILE_PATH, std::ios_base::in); + if (!file) { + ThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError, + "Cannot create database. SQL file is missing."); + } + + std::stringstream stream; + stream << file.rdbuf(); + + file.close(); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + DPL::DB::SqlConnection con(databaseFile, + DATABASE_FLAG, + DATABASE_OPTION); + con.ExecCommand(stream.str().c_str()); + copyPropertiesFromWrtDatabase(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot create database") + + if(chown(databaseFile.c_str(), APP_UID, APP_GUID) != 0) { + ThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError, + "Fail to change uid/guid"); + } + std::string databaseJournal = + databaseFile + DATABASE_JOURNAL_FILENAME; + if(chown(databaseJournal.c_str(), APP_UID, APP_GUID) != 0) { + ThrowMsg(WidgetInterfaceDAO::Exception::DatabaseError, + "Fail to change uid/guid"); + } + } +} + +void WidgetInterfaceDAO::copyPropertiesFromWrtDatabase() +{ + WrtDB::WrtDatabase::attachToThreadRO(); + m_databaseInterface.AttachToThread(DPL::DB::SqlConnection::Flag::RW); + + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WrtDB::PropertyDAOReadOnly::WidgetPreferenceList existing = + WrtDB::PropertyDAOReadOnly::GetPropertyList( + WrtDB::WidgetDAOReadOnly::getTizenAppId(m_widgetHandle) + ); + + //save all properties read from config.xml + FOREACH(prop, existing) { + std::string key = DPL::ToUTF8String(prop->key_name); + if (key != KEY_WIDGET_ARG) { + std::string value; + if (!prop->key_value.IsNull()) { + value = DPL::ToUTF8String(*(prop->key_value)); + } + bool readonly = !prop->readonly.IsNull() && (*prop->readonly); + setItem(key, value, readonly, true); + } + } + } + SQL_CONNECTION_EXCEPTION_HANDLER_END( + "Cannot copy properties read from config.xml"); + + WrtDB::WrtDatabase::detachFromThread(); + m_databaseInterface.DetachFromThread(); +} + +void WidgetInterfaceDAO::setItem(const std::string& key, + const std::string& value, + bool readOnly) +{ + setItem(key, value, readOnly, false); +} + +void WidgetInterfaceDAO::setItem(const std::string& key, + const std::string& value, + bool readOnly, + bool fromConfigXml) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + ScopedTransaction tran(&m_databaseInterface); + //check if key exists + Properties::Select select(&m_databaseInterface); + select.Where(Equals(DPL::FromUTF8String(key))); + std::list rows = select.GetRowList(); + + if (rows.empty()) { + Properties::Insert insert(&m_databaseInterface); + Properties::Row row; + row.Set_key(DPL::FromUTF8String(key)); + row.Set_value(DPL::FromUTF8String(value)); + row.Set_readonly(readOnly ? 1 : 0); + row.Set_configxml(fromConfigXml ? 1 : 0); + insert.Values(row); + insert.Execute(); + } else { + Assert(rows.size() == 1); + Properties::Row row = rows.front(); + if (row.Get_readonly() != 0) { + Throw(Exception::LocalStorageValueNoModifableException); + } + row.Set_value(DPL::FromUTF8String(value)); + row.Set_readonly(readOnly ? 1 : 0); + Properties::Update update(&m_databaseInterface); + update.Where(Equals(DPL::FromUTF8String(key))); + update.Values(row); + update.Execute(); + } + tran.Commit(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot set item"); +} + +void WidgetInterfaceDAO::removeItem(const std::string& key) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + Properties::Select select(&m_databaseInterface); + select.Where(Equals(DPL::FromUTF8String(key))); + bool readonly = select.GetSingleValue(); + if (readonly) { + ThrowMsg(Exception::LocalStorageValueNoModifableException, + "Cannot delete item. Item is readonly"); + } + Properties::Delete deleteItem(&m_databaseInterface); + deleteItem.Where(Equals(DPL::FromUTF8String(key))); + deleteItem.Execute(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot delete item"); +} + +DPL::Optional WidgetInterfaceDAO::getValue( + const std::string& key) const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + Properties::Select select(&m_databaseInterface); + select.Where(Equals(DPL::FromUTF8String(key))); + std::list value = + select.GetValueList(); + if (value.empty()) { + return DPL::Optional(); + } + return DPL::Optional(DPL::ToUTF8String(value.front())); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Not found item"); +} + +void WidgetInterfaceDAO::clear(bool removeReadOnly) +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + Properties::Delete deleteItem(&m_databaseInterface); + if (!removeReadOnly) { + deleteItem.Where(Equals(0)); + } + deleteItem.Execute(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot delete all items"); +} + +size_t WidgetInterfaceDAO::getStorageSize() const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + Properties::Select select(&m_databaseInterface); + std::list list = + select.GetValueList(); + return list.size(); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count"); +} + +std::string WidgetInterfaceDAO::getKeyByIndex(size_t index) const +{ + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + Properties::Select select(&m_databaseInterface); + select.OrderBy("key"); + std::list list = select.GetValueList(); + if (index >= list.size()) { + Throw(Exception::InvalidArgumentException); + } + for (size_t i = 0; i < index; ++i) { + list.pop_front(); + } + return DPL::ToUTF8String(list.front()); + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count"); +} + +std::string WidgetInterfaceDAO::databaseFileName(int widgetHandle) +{ + using namespace DPL::DB::ORM; + using namespace WrtDB::WidgetConfig; + + WrtDB::WrtDatabase::attachToThreadRO(); + std::stringstream filename; + SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN + { + WrtDB::WidgetDAOReadOnly widgetDAO(widgetHandle); + WrtDB::TizenPkgId pkgid = widgetDAO.getTizenPkgId(); + + filename << GetWidgetPersistentStoragePath(pkgid) + << "/" + << DATABASE_NAME; + } + SQL_CONNECTION_EXCEPTION_HANDLER_END("Cannot get item count"); + WrtDB::WrtDatabase::detachFromThread(); + return filename.str(); +} +} // namespace WidgetInterfaceDB diff --git a/modules/widget_interface_dao/include/wrt-commons/widget-interface-dao/widget_interface_dao.h b/modules/widget_interface_dao/include/wrt-commons/widget-interface-dao/widget_interface_dao.h new file mode 100644 index 0000000..8b35344 --- /dev/null +++ b/modules/widget_interface_dao/include/wrt-commons/widget-interface-dao/widget_interface_dao.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Lukasz Marek (l.marek@samsung.com) + * @version 0.1 + * @brief + */ + +#ifndef _WIDGET_INTERFACE_DAO_H_ +#define _WIDGET_INTERFACE_DAO_H_ + +#include +#include +#include + +namespace WidgetInterfaceDB { +class WidgetInterfaceDAO +{ + public: + + /** + * WidgetInterfaceDAO Exception classes + */ + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, DatabaseError) + DECLARE_EXCEPTION_TYPE(Base, LocalStorageValueNoModifableException) + DECLARE_EXCEPTION_TYPE(Base, InvalidArgumentException) + }; + WidgetInterfaceDAO(int widgetHandle); + virtual ~WidgetInterfaceDAO(); + + static std::string databaseFileName(int widgetHandle); + void setItem(const std::string& key, + const std::string& value, + bool readOnly, + bool fromConfigXml); + void setItem(const std::string& key, + const std::string& value, + bool readOnly); + void removeItem(const std::string& key); + DPL::Optional getValue(const std::string& key) const; + void clear(bool removeReadOnly); + size_t getStorageSize() const; + std::string getKeyByIndex(size_t index) const; + + protected: + int m_widgetHandle; + mutable DPL::DB::ThreadDatabaseSupport m_databaseInterface; + + private: + void checkDatabase(); + void copyPropertiesFromWrtDatabase(); +}; +typedef std::unique_ptr WidgetInterfaceDAOPtr; +} +#endif //_WIDGET_INTERFACE_DAO_H_ diff --git a/modules/widget_interface_dao/orm/orm_generator_widget_interface.h b/modules/widget_interface_dao/orm/orm_generator_widget_interface.h new file mode 100644 index 0000000..87a3e05 --- /dev/null +++ b/modules/widget_interface_dao/orm/orm_generator_widget_interface.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ORM_GENERATOR_WIDGET_INTERFACE_H_ +#define ORM_GENERATOR_WIDGET_INTERFACE_H_ + +#define ORM_GENERATOR_DATABASE_NAME widget_interface_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif diff --git a/modules/widget_interface_dao/orm/widget_interface_db b/modules/widget_interface_dao/orm/widget_interface_db new file mode 100644 index 0000000..d33ec48 --- /dev/null +++ b/modules/widget_interface_dao/orm/widget_interface_db @@ -0,0 +1,17 @@ +SQL( + PRAGMA foreign_keys = ON; + BEGIN TRANSACTION; +) + +CREATE_TABLE(Properties) + COLUMN_NOT_NULL(key, TEXT,) + COLUMN_NOT_NULL(value, TEXT,) + COLUMN_NOT_NULL(readonly, INTEGER, check(readonly between 0 and 1)) + COLUMN_NOT_NULL(configxml, INTEGER, check(readonly between 0 and 1) DEFAULT 0) + + TABLE_CONSTRAINTS(unique(key)) +CREATE_TABLE_END() + +SQL( + COMMIT; +) diff --git a/modules/widget_interface_dao/orm/widget_interface_db_definitions b/modules/widget_interface_dao/orm/widget_interface_db_definitions new file mode 100644 index 0000000..85f627d --- /dev/null +++ b/modules/widget_interface_dao/orm/widget_interface_db_definitions @@ -0,0 +1,5 @@ +DATABASE_START(widget_interface) + +#include "widget_interface_db" + +DATABASE_END() diff --git a/modules/widget_interface_dao/orm/widget_interface_db_sql_generator.h b/modules/widget_interface_dao/orm/widget_interface_db_sql_generator.h new file mode 100644 index 0000000..b4ce0b6 --- /dev/null +++ b/modules/widget_interface_dao/orm/widget_interface_db_sql_generator.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file wrt_db_sql_generator.h + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL input file from + * database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. + +#include + +#include "widget_interface_db_definitions" diff --git a/packaging/wrt-commons.spec b/packaging/wrt-commons.spec new file mode 100644 index 0000000..f97ef63 --- /dev/null +++ b/packaging/wrt-commons.spec @@ -0,0 +1,146 @@ +#git:framework/web/wrt-commons +Name: wrt-commons +Summary: Wrt common library +Version: 0.2.196_w8 +Release: 1 +Group: Development/Libraries +License: Apache-2.0 +URL: N/A +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(libssl) +BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gio-2.0) +BuildRequires: pkgconfig(db-util) +BuildRequires: pkgconfig(zlib) +BuildRequires: pkgconfig(libpcrecpp) +BuildRequires: pkgconfig(icu-i18n) +BuildRequires: pkgconfig(libxml-2.0) +BuildRequires: pkgconfig(openssl) +BuildRequires: pkgconfig(libiri) +BuildRequires: pkgconfig(libidn) +BuildRequires: pkgconfig(minizip) +BuildRequires: boost-devel + +%description +Wrt common library + +%package devel +Summary: Wrt common library development headers +Group: Development/Libraries +Requires: %{name} = %{version} +Requires: boost-devel + +%description devel +Wrt common library development headers + +%prep +%setup -q + +%define with_tests 0 +%if "%{WITH_TESTS}" == "ON" || "%{WITH_TESTS}" == "Y" || "%{WITH_TESTS}" == "YES" || "%{WITH_TESTS}" == "TRUE" || "%{WITH_TESTS}" == "1" + %define with_tests 1 +%endif + +%define with_child 0 +%if "%{WITH_CHILD}" == "ON" || "%{WITH_CHILD}" == "Y" || "%{WITH_CHILD}" == "YES" || "%{WITH_CHILD}" == "TRUE" || "%{WITH_CHILD}" == "1" + %define with_child 1 +%endif + +%build +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" + +export LDFLAGS+="-Wl,--rpath=%{_libdir} -Wl,--hash-style=both -Wl,--as-needed" + +cmake . -DVERSION=%{version} \ + -DDPL_LOG="OFF" \ + -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -DCMAKE_BUILD_TYPE=%{?build_type:%build_type} \ + %{?WITH_TESTS:-DWITH_TESTS=%WITH_TESTS} \ + %{?WITH_CHILD:-DWITH_CHILD=%WITH_CHILD} +make %{?jobs:-j%jobs} + +%install +mkdir -p %{buildroot}/usr/share/license +cp LICENSE %{buildroot}/usr/share/license/%{name} +%make_install + +%clean +rm -rf %{buildroot} + +%post +mkdir -p /opt/share/widget/system +mkdir -p /opt/share/widget/user +mkdir -p /opt/share/widget/exec +mkdir -p /opt/share/widget/data/Public +mkdir -p /usr/lib/wrt-plugins + +#Don't reset DB when install on QEMU (during other packages building witch GBS) +if [ -z "$EMULATOR_ARCHS" ]; then + if [ -z ${2} ]; then + echo "This is new install of wrt-commons" + echo "Calling /usr/bin/wrt_commons_reset_db.sh" + /usr/bin/wrt_commons_reset_db.sh + else + # Find out old and new version of databases + WRT_OLD_DB_VERSION=`sqlite3 /opt/dbspace/.wrt.db ".tables" | grep "DB_VERSION_"` + WRT_NEW_DB_VERSION=`cat /usr/share/wrt-engine/wrt_db.sql | tr '[:blank:]' '\n' | grep DB_VERSION_` + echo "OLD wrt database version ${WRT_OLD_DB_VERSION}" + echo "NEW wrt database version ${WRT_NEW_DB_VERSION}" + + if [ ${WRT_OLD_DB_VERSION} -a ${WRT_NEW_DB_VERSION} ] + then + if [ ${WRT_NEW_DB_VERSION} = ${WRT_OLD_DB_VERSION} ] + then + echo "Equal database detected so db installation ignored" + else + echo "Calling /usr/bin/wrt_commons_reset_db.sh" + /usr/bin/wrt_commons_reset_db.sh + fi + else + echo "Calling /usr/bin/wrt_commons_reset_db.sh" + /usr/bin/wrt_commons_reset_db.sh + fi + fi +fi + +mkdir -p /usr/etc/ace +mkdir -p /usr/apps/org.tizen.policy + +# Set Smack label for db files +chsmack -a 'wrt-commons::db_wrt' /opt/dbspace/.wrt.db +chsmack -a 'wrt-commons::db_wrt' /opt/dbspace/.wrt.db-journal +chsmack -a 'wrt-commons::db_wrt' /opt/usr/dbspace/.wrt_custom_handler.db +chsmack -a 'wrt-commons::db_wrt' /opt/usr/dbspace/.wrt_custom_handler.db-journal +chsmack -a '*' /opt/usr/dbspace/.wrt_i18n.db +chsmack -a '*' /opt/usr/dbspace/.wrt_i18n.db-journal + +echo "[WRT] wrt-commons postinst done ..." + +%files +%manifest wrt-commons.manifest +%{_libdir}/*.so +%{_libdir}/*.so.* +%{_datadir}/wrt-engine/* +%{_datadir}/license/%{name} +%attr(755,root,root) %{_bindir}/wrt_commons_create_clean_db.sh +%attr(755,root,root) %{_bindir}/wrt_commons_reset_db.sh +%if %{with_tests} + %attr(755,root,root) %{_bindir}/wrt-commons-tests-* + %attr(755,root,root) %{_bindir}/wrt_dao_tests_prepare_db.sh + %attr(755,root,root) %{_bindir}/wrt_db_localization_prepare.sh + %{_datadir}/dbus-1/services/org.tizen.DBusTestService.service + /opt/share/wrt/wrt-commons/tests/* + /opt/share/widget/tests/localization/* +%endif + +%files devel +%{_includedir}/dpl-efl/* +%{_libdir}/pkgconfig/*.pc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..50227c7 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,30 @@ +# Suppress all warnings; TODO: inhibit only specific warnings per target (TURNED OFF) +#SET(CMAKE_CXX_FLAGS_BACKUP ${CMAKE_CXX_FLAGS}) +#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") + +INCLUDE(CMakeUtils.txt) + +SET(TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +SET(TESTS_COMMON_DIR "${TESTS_DIR}/common") + +WRT_ADD_INTERNAL_DEPENDENCIES( + ${TARGET_DPL_TEST_ENGINE_EFL} +) + +ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(dao) +ADD_SUBDIRECTORY(db) +ADD_SUBDIRECTORY(dbus) +ADD_SUBDIRECTORY(event) +ADD_SUBDIRECTORY(files_localization) +ADD_SUBDIRECTORY(localizationTagsProvider) +ADD_SUBDIRECTORY(utils) +ADD_SUBDIRECTORY(i18n) + +IF(WITH_CHILD) + MESSAGE(STATUS "Additional test subdirectory is being added") + ADD_SUBDIRECTORY(test) +ENDIF(WITH_CHILD) + +# Rollback CXX flags +#SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_BACKUP}) diff --git a/tests/CMakeUtils.txt b/tests/CMakeUtils.txt new file mode 100644 index 0000000..ea9cfb3 --- /dev/null +++ b/tests/CMakeUtils.txt @@ -0,0 +1,178 @@ +# @file CMakeUtils.txt +# @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) +# @author Pawel Sikorski (p.sikorski@samsung.com) +# @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) +# @version 1.0 +# @brief +# + +# +# Discovers target's INCLUDE_DIRECTORIES and LINK_DIRECTORIES. +# This is done by retrieving the directory target was built in and +# fetching appropriate properties of that directory. +FUNCTION(WRT_INTROSPECT_TARGET PREFIX TARGET_NAME) + GET_TARGET_PROPERTY(LOCATION ${TARGET_NAME} LOCATION) + IF(${LOCATION} STREQUAL "LOCATION-NOTFOUND") + MESSAGE(FATAL_ERROR "Target '${TARGET_NAME}' introspection failed") + ELSE(${LOCATION} STREQUAL "LOCATION-NOTFOUND") + STRING(FIND ${LOCATION} "/" LAST_SLASH_POSITION REVERSE) + STRING(SUBSTRING ${LOCATION} 0 ${LAST_SLASH_POSITION} LOCATION) + + GET_DIRECTORY_PROPERTY(INCLUDE_DIRS DIRECTORY ${LOCATION} INCLUDE_DIRECTORIES) + SET("${PREFIX}_INCLUDE_DIRS" ${INCLUDE_DIRS} PARENT_SCOPE) + + GET_DIRECTORY_PROPERTY(LIBRARY_DIRS DIRECTORY ${LOCATION} LINK_DIRECTORIES) + SET("${PREFIX}_LIBRARY_DIRS" ${LIBRARY_DIRS} PARENT_SCOPE) + ENDIF(${LOCATION} STREQUAL "LOCATION-NOTFOUND") +ENDFUNCTION(WRT_INTROSPECT_TARGET) + +# +# Replacement functions for standard (w/o "WRT_" prefix) CMake functions. +# They store supplied arguments in global properties to assign them to tests. +# Anything added with this functions is used by all targets that are built with +# WRT_TEST_BUILD function. + +# +# Appends directories to global property TESTS_INCLUDE_DIRS which is +# then read by WRT_TEST_BUILD and its content is forwarded to +# command INCLUDE_DIRECTORIES() (for all targets). +FUNCTION(WRT_INCLUDE_DIRECTORIES) + SET_PROPERTY(GLOBAL APPEND PROPERTY TESTS_INCLUDE_DIRS ${ARGV}) +ENDFUNCTION(WRT_INCLUDE_DIRECTORIES) + +# +# Appends directories to global property TESTS_LIBRARY_DIRS which is +# then read by WRT_TEST_BUILD and its content is forwarded to +# command LINK_DIRECTORIES() (for all targets). +FUNCTION(WRT_LINK_DIRECTORIES) + SET_PROPERTY(GLOBAL APPEND PROPERTY TESTS_LIBRARY_DIRS ${ARGV}) +ENDFUNCTION(WRT_LINK_DIRECTORIES) + +# +# Appends directories to global property TESTS_LIBRARIES which is +# then read by WRT_TEST_BUILD and its content is forwarded to +# command TARGET_LINK_LIBRARIES() (for all targets). +FUNCTION(WRT_TARGET_LINK_LIBRARIES) + SET_PROPERTY(GLOBAL APPEND PROPERTY TESTS_LIBRARIES ${ARGV}) +ENDFUNCTION(WRT_TARGET_LINK_LIBRARIES) + +# +# Convenience method that fills TESTS_INCLUDE_DIRS, TESTS_LIBRARY_DIRS +# and TESTS_LIBRARIES with values discovered from introspecting supplied +# targets. +# Function takes arbitrary number of targets. +FUNCTION(WRT_ADD_INTERNAL_DEPENDENCIES) + FOREACH(DEPENDENCY ${ARGV}) + WRT_INTROSPECT_TARGET(prefix ${DEPENDENCY}) + WRT_INCLUDE_DIRECTORIES(${prefix_INCLUDE_DIRS}) + WRT_LINK_DIRECTORIES(${prefix_LIBRARY_DIRS}) + WRT_TARGET_LINK_LIBRARIES(${DEPENDENCY}) + ENDFOREACH(DEPENDENCY) +ENDFUNCTION(WRT_ADD_INTERNAL_DEPENDENCIES) + + +# +# Replacement functions for standard (w/o "WRT_" prefix) CMake functions. +# They store supplied arguments in global properties to assign them to specific +# tests. Properties names are based on the test target name. +# Anything added with this functions is used only by the specified target that +# is built with WRT_TEST_BUILD function. + +# +# Appends directories to global property ${TARGET_NAME}_INCLUDE_DIRS +# which is then read by WRT_TEST_BUILD and its content is forwarded to +# command INCLUDE_DIRECTORIES() (for specified target). +FUNCTION(WRT_TEST_INCLUDE_DIRECTORIES TARGET_NAME) + SET_PROPERTY(GLOBAL APPEND PROPERTY ${TARGET_NAME}_INCLUDE_DIRS ${ARGN}) +ENDFUNCTION(WRT_TEST_INCLUDE_DIRECTORIES) + +# +# Appends directories to global property ${TARGET_NAME}_LIBRARY_DIRS +# which is then read by WRT_TEST_BUILD and its content is forwarded to +# command LINK_DIRECTORIES() (for specified target). +FUNCTION(WRT_TEST_LINK_DIRECTORIES TARGET_NAME) + SET_PROPERTY(GLOBAL APPEND PROPERTY ${TARGET_NAME}_LIBRARY_DIRS ${ARGN}) +ENDFUNCTION(WRT_TEST_LINK_DIRECTORIES) + +# +# Appends directories to global property ${TARGET_NAME}_LIBRARIES +# which is then read by WRT_TEST_BUILD and its content is forwarded to +# command TARGET_LINK_LIBRARIES() (for specified target). +FUNCTION(WRT_TEST_TARGET_LINK_LIBRARIES TARGET_NAME) + SET_PROPERTY(GLOBAL APPEND PROPERTY ${TARGET_NAME}_LIBRARIES ${ARGN}) +ENDFUNCTION(WRT_TEST_TARGET_LINK_LIBRARIES) + +# +# Convenience method that fills ${TARGET_NAME}_INCLUDE_DIRS, +# ${TARGET_NAME}_LIBRARY_DIRS and ${TARGET_NAME}_LIBRARIES with +# values discovered from introspecting supplied targets. +# Function takes arbitrary number of targets. +FUNCTION(WRT_TEST_ADD_INTERNAL_DEPENDENCIES TARGET_NAME) + FOREACH(DEPENDENCY ${ARGN}) + WRT_INTROSPECT_TARGET(prefix ${DEPENDENCY}) + WRT_TEST_INCLUDE_DIRECTORIES(${TARGET_NAME} ${prefix_INCLUDE_DIRS}) + WRT_TEST_LINK_DIRECTORIES(${TARGET_NAME} ${prefix_LIBRARY_DIRS}) + WRT_TEST_TARGET_LINK_LIBRARIES(${TARGET_NAME} ${DEPENDENCY}) + ENDFOREACH(DEPENDENCY) +ENDFUNCTION(WRT_TEST_ADD_INTERNAL_DEPENDENCIES) + +# Functions used to build test targets (proper sources, includes, libs are +# added automatically) +FUNCTION(WRT_TEST_BUILD TARGET_NAME) + SET(SOURCES "${ARGN}") + ADD_EXECUTABLE("${TARGET_NAME}" ${SOURCES}) + + # get include dirs global property + GET_PROPERTY(INCLUDE_DIRS GLOBAL PROPERTY TESTS_INCLUDE_DIRS) + GET_PROPERTY(TEST_INCLUDE_DIRS GLOBAL PROPERTY ${TARGET_NAME}_INCLUDE_DIRS) + INCLUDE_DIRECTORIES( + ${INCLUDE_DIRS} + ${TEST_INCLUDE_DIRS} + ) + + # get library dirs global property + GET_PROPERTY(LIBRARY_DIRS GLOBAL PROPERTY TESTS_LIBRARY_DIRS) + GET_PROPERTY(TEST_LIBRARY_DIRS GLOBAL PROPERTY ${TARGET_NAME}_LIBRARY_DIRS) + LINK_DIRECTORIES( + ${LIBRARY_DIRS} + ${TEST_LIBRARY_DIRS} + ) + + # get link libraries global property + GET_PROPERTY(LINK_LIBRARIES GLOBAL PROPERTY TESTS_LIBRARIES) + GET_PROPERTY(TEST_LIBRARIES GLOBAL PROPERTY ${TARGET_NAME}_LIBRARIES) + TARGET_LINK_LIBRARIES("${TARGET_NAME}" + ${LINK_LIBRARIES} + ${TEST_LIBRARIES} + ) +ENDFUNCTION(WRT_TEST_BUILD) + +FUNCTION(WRT_TEST_INSTALL) + SET_TARGET_PROPERTIES(${ARGV} PROPERTIES + BUILD_WITH_INSTALL_RPATH ON + INSTALL_RPATH_USE_LINK_PATH ON + ) + INSTALL(TARGETS ${ARGV} + DESTINATION bin + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE + ) +ENDFUNCTION(WRT_TEST_INSTALL) + +# Takes arbitrary number of arguments and concatenates them using ':' character. +# Rationale: +# CMake list when converted to a string is joined with ';' character. However, +# GCC takes strings with multiple elements separated with ':' (e.g. list of +# paths). Used typically when generating DB schemas with ORM mechanism. +FUNCTION(WRT_CONVERT_TO_GCC_LIST OUTPUT_VARIABLE) + FOREACH(ITEM ${ARGN}) + LIST(APPEND ITEMS ${ITEM}) + ENDFOREACH(ITEM) + STRING(REPLACE ";" ":" OUTPUT "${ITEMS}") + SET("${OUTPUT_VARIABLE}" "${OUTPUT}" PARENT_SCOPE) +ENDFUNCTION(WRT_CONVERT_TO_GCC_LIST) diff --git a/tests/common/include/glib_interface.h b/tests/common/include/glib_interface.h new file mode 100644 index 0000000..5629f99 --- /dev/null +++ b/tests/common/include/glib_interface.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file glib_interface.h + * @author Iwanek Tomasz (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the definitions of loop controlling utilities + */ + +#ifndef GLIB_INTERFACE_H +#define GLIB_INTERFACE_H + +//this header wraps glib headers which generates warnings + +#pragma GCC system_header +#include +#include + +#endif // GLIB_INTERFACE_H diff --git a/tests/common/include/loop_control.h b/tests/common/include/loop_control.h new file mode 100644 index 0000000..b58fb5c --- /dev/null +++ b/tests/common/include/loop_control.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file loop_control.cpp + * @author Jaroslaw Osmanski (j.osmanski@samsung.com) + * @version 1.0 + * @brief This file is the definitions of loop controlling utilities + */ + +#ifndef LOOP_CONTROL_H_ +#define LOOP_CONTROL_H_ + +namespace LoopControl { +void init_loop(int argc, char *argv[]); +void wait_for_wrt_init(); +void finish_wait_for_wrt_init(); +void quit_loop(); + +void wrt_start_loop(); +void wrt_end_loop(); + +void *abstract_window(); +} + +#endif /* LOOP_CONTROL_H_ */ diff --git a/tests/common/src/loop_control.cpp b/tests/common/src/loop_control.cpp new file mode 100644 index 0000000..5c690c2 --- /dev/null +++ b/tests/common/src/loop_control.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file loop_control.cpp + * @author Jaroslaw Osmanski (j.osmanski@samsung.com) + * @version 1.0 + * @brief This is implementation of EFL version of loop control + */ + +#include +#include +#include + +#include + +namespace LoopControl { +void init_loop(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + g_type_init(); + g_thread_init(NULL); + + LogDebug("Starting"); + elm_init(argc, argv); +} + +void wait_for_wrt_init() +{ + ecore_main_loop_begin(); +} + +void finish_wait_for_wrt_init() +{ + ecore_main_loop_quit(); +} + +void quit_loop() +{ + elm_shutdown(); +} + +void wrt_start_loop() +{ + ecore_main_loop_begin(); +} + +void wrt_end_loop() +{ + ecore_main_loop_quit(); +} + +void *abstract_window() +{ + return elm_win_add(NULL, "hello", ELM_WIN_BASIC); +} +} //end of LoopControl namespace diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt new file mode 100644 index 0000000..44d2321 --- /dev/null +++ b/tests/core/CMakeLists.txt @@ -0,0 +1,66 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) +# @version 1.0 +# @brief +# + +# +# Test files +# +# Define all DPL tests sources. +# Runner is responsible for runnint it all and +# generating proper output files +# + +SET(TARGET_NAME "wrt-commons-tests-core") + +# Set DPL tests sources +SET(DPL_TESTS_CORE_SOURCES + ${TESTS_DIR}/core/main.cpp + ${TESTS_DIR}/core/test_address.cpp + ${TESTS_DIR}/core/test_bind.cpp + ${TESTS_DIR}/core/test_binary_queue.cpp + ${TESTS_DIR}/core/test_foreach.cpp + ${TESTS_DIR}/core/test_log_unhandled_exception.cpp + ${TESTS_DIR}/core/test_once.cpp + ${TESTS_DIR}/core/test_serialization.cpp + ${TESTS_DIR}/core/test_scoped_array.cpp + ${TESTS_DIR}/core/test_scoped_close.cpp + ${TESTS_DIR}/core/test_scoped_dir.cpp + ${TESTS_DIR}/core/test_scoped_fclose.cpp + ${TESTS_DIR}/core/test_scoped_free.cpp + ${TESTS_DIR}/core/test_scoped_ptr.cpp + ${TESTS_DIR}/core/test_semaphore.cpp + ${TESTS_DIR}/core/test_shared_ptr.cpp + ${TESTS_DIR}/core/test_static_block.cpp + ${TESTS_DIR}/core/test_string.cpp + ${TESTS_DIR}/core/test_thread.cpp + ${TESTS_DIR}/core/test_type_list.cpp + ${TESTS_DIR}/core/test_zip_input.cpp + ${TESTS_DIR}/core/test_scope_guard.cpp + ${TESTS_DIR}/core/test_waitable_handle_watch.cpp + ${TESTS_DIR}/core/test_single_instance.cpp +) + +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_DPL_EFL}) +WRT_TEST_BUILD(${TARGET_NAME} ${DPL_TESTS_CORE_SOURCES}) +WRT_TEST_INSTALL(${TARGET_NAME}) + +INSTALL(FILES + ${TESTS_DIR}/core/data/sample.zip + DESTINATION /opt/share/wrt/wrt-commons/tests/core + ) diff --git a/tests/core/DESCRIPTION b/tests/core/DESCRIPTION new file mode 100644 index 0000000..48e5394 --- /dev/null +++ b/tests/core/DESCRIPTION @@ -0,0 +1,2 @@ +!!!options!!! stop +Test code diff --git a/tests/core/data/sample.zip b/tests/core/data/sample.zip new file mode 100644 index 0000000000000000000000000000000000000000..02417d89316a2de5eb658decfa83dc60e366c8c7 GIT binary patch literal 174 zcmWIWW@h1H0D-h9e>XlTKgobc3Fe?N{`GRn11vdjD z%L`_pLJ(1sT3iy~&B!FjjLRemkOd5kK)j?8#6mWg6=E)$nE~FcY#^14Ko|g|JwO}= E0Bw;T(f|Me literal 0 HcmV?d00001 diff --git a/tests/core/main.cpp b/tests/core/main.cpp new file mode 100644 index 0000000..42ffe3a --- /dev/null +++ b/tests/core/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main + */ +#include + +int main(int argc, char *argv[]) +{ + return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); +} + diff --git a/tests/core/test_address.cpp b/tests/core/test_address.cpp new file mode 100644 index 0000000..d887ca0 --- /dev/null +++ b/tests/core/test_address.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_address.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test address + */ +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: Address_InitialEmpty +Description: tests empty constructor of DPL::Address +Expected: string version of empy address equals ":0" +*/ +RUNNER_TEST(Address_InitialEmpty) +{ + DPL::Address address; + RUNNER_ASSERT(address.ToString() == ":0"); +} + +/* +Name: Address_InitialAddress +Description: tests constructor of DPL::Address with name only +Expected: string version of address equals given name and appended ":0" +*/ +RUNNER_TEST(Address_InitialAddress) +{ + DPL::Address address("www.sample.com"); + RUNNER_ASSERT(address.ToString() == "www.sample.com:0"); +} + +/* +Name: Address_InitialAddress +Description: tests constructor of DPL::Address with name and port +Expected: string version of address should look lik "adress name:port" +*/ +RUNNER_TEST(Address_InitialAddressPort) +{ + DPL::Address address("www.somewhere.com", 8080); + RUNNER_ASSERT(address.ToString() == "www.somewhere.com:8080"); +} + +/* +Name: Address_InitialAddress +Description: tests getter of address +Expected: address name and port should matches those passed in constructor +*/ +RUNNER_TEST(Address_Getters) +{ + DPL::Address address("www.somewhere.com", 8080); + RUNNER_ASSERT(address.GetAddress() == "www.somewhere.com"); + RUNNER_ASSERT(address.GetPort() == 8080); +} diff --git a/tests/core/test_binary_queue.cpp b/tests/core/test_binary_queue.cpp new file mode 100644 index 0000000..cd8931d --- /dev/null +++ b/tests/core/test_binary_queue.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_binary_queue.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test binary queue + */ +#include +#include +RUNNER_TEST_GROUP_INIT(DPL) + +inline std::string BinaryQueueToString(const DPL::BinaryQueue &queue) +{ + char *buffer = new char[queue.Size()]; + queue.Flatten(buffer, queue.Size()); + std::string result = std::string(buffer, buffer + queue.Size()); + delete[] buffer; + return result; +} + +/* +Name: BinaryQueue_InitialEmpty +Description: tests emptiness of new constructed queue +Expected: new queue should be empty +*/ +RUNNER_TEST(BinaryQueue_InitialEmpty) +{ + DPL::BinaryQueue queue; + RUNNER_ASSERT(queue.Empty() == true); +} + +/* +Name: BinaryQueue_InitialSize +Description: tests emptiness of new constructed queue +Expected: new queue size should be equal 0 +*/ +RUNNER_TEST(BinaryQueue_InitialSize) +{ + DPL::BinaryQueue queue; + RUNNER_ASSERT(queue.Size() == 0); +} + +/* +Name: BinaryQueue_InitialCopy +Description: tests emptiness of new copy-constructed empty queue +Expected: queue constructed on base on empty queue should be empty +*/ +RUNNER_TEST(BinaryQueue_InitialCopy) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy = queue; + + RUNNER_ASSERT(copy.Size() == 0); +} + +/* +Name: BinaryQueue_InitialConsumeZero +Description: tests consume method accepts 0 bytes +Expected: it should be avaliable to discard 0 bytes from empty queue +*/ +RUNNER_TEST(BinaryQueue_InitialConsumeZero) +{ + DPL::BinaryQueue queue; + queue.Consume(0); +} + +/* +Name: BinaryQueue_InitialFlattenConsumeZero +Description: tests returning data from queue and discarding +Expected: it should be able to call flattenconsume with empty buffer if 0 bytes are read +*/ +RUNNER_TEST(BinaryQueue_InitialFlattenConsumeZero) +{ + DPL::BinaryQueue queue; + queue.FlattenConsume(NULL, 0); +} + +/* +Name: BinaryQueue_InitialFlattenZero +Description: tests returning data from queue +Expected: it should be able to call flatten with empty buffer if 0 bytes are read +*/ +RUNNER_TEST(BinaryQueue_InitialFlattenZero) +{ + DPL::BinaryQueue queue; + queue.Flatten(NULL, 0); +} + +/* +Name: BinaryQueue_InitialConsumeOne +Description: tests discarding more bytes than it is avaliable +Expected: exception throw +*/ +RUNNER_TEST(BinaryQueue_InitialConsumeOne) +{ + DPL::BinaryQueue queue; + + Try + { + queue.Consume(1); + } + Catch(DPL::BinaryQueue::Exception::OutOfData) + { + return; + } + + RUNNER_FAIL; +} + +/* +Name: BinaryQueue_InitialFlattenConsumeOne +Description: tests reading and discarding more bytes than it is avaliable +Expected: exception throw +*/ +RUNNER_TEST(BinaryQueue_InitialFlattenConsumeOne) +{ + DPL::BinaryQueue queue; + + Try + { + char data; + queue.FlattenConsume(&data, 1); + } + Catch(DPL::BinaryQueue::Exception::OutOfData) + { + return; + } + + RUNNER_FAIL; +} + +/* +Name: BinaryQueue_InitialFlattenOne +Description: tests reading more bytes than it is avaliable +Expected: exception throw +*/ +RUNNER_TEST(BinaryQueue_InitialFlattenOne) +{ + DPL::BinaryQueue queue; + + Try + { + char data; + queue.Flatten(&data, 1); + } + Catch(DPL::BinaryQueue::Exception::OutOfData) + { + return; + } + + RUNNER_FAIL; +} + +/* +Name: BinaryQueue_ZeroCopyFrom +Description: tests coping content of empty queue to another (AppendCopyFrom) +Expected: source queue should be empty +*/ +RUNNER_TEST(BinaryQueue_ZeroCopyFrom) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy; + + copy.AppendCopyFrom(queue); + RUNNER_ASSERT(queue.Empty()); +} + +/* +Name: BinaryQueue_ZeroMoveFrom +Description: tests moving content of empty queue to another +Expected: source queue should be empty +*/ +RUNNER_TEST(BinaryQueue_ZeroMoveFrom) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy; + + copy.AppendMoveFrom(queue); + RUNNER_ASSERT(queue.Empty()); +} + +/* +Name: BinaryQueue_ZeroCopyTo +Description: tests moving content of empty queue to another (AppendCopyTo) +Expected: source queue should be empty +*/ +RUNNER_TEST(BinaryQueue_ZeroCopyTo) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy; + + queue.AppendCopyTo(copy); + RUNNER_ASSERT(queue.Empty()); +} + +/* +Name: BinaryQueue_InsertSingleCharacters +Description: tests inserting single bytes to queue +Expected: stringified content and size shoudl match expected +*/ +RUNNER_TEST(BinaryQueue_InsertSingleCharacters) +{ + DPL::BinaryQueue queue; + + queue.AppendCopy("a", 1); + queue.AppendCopy("b", 1); + queue.AppendCopy("c", 1); + queue.AppendCopy("d", 1); + + RUNNER_ASSERT(queue.Size() == 4); + RUNNER_ASSERT(BinaryQueueToString(queue) == "abcd"); +} + +/* +Name: BinaryQueue_Consume +Description: tests comsuming portions of 1 or 2 bytes +Expected: stringified content and size should match expected + Bytes should be pope from begin. +*/ +RUNNER_TEST(BinaryQueue_Consume) +{ + DPL::BinaryQueue queue; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + + RUNNER_ASSERT(queue.Size() == 6); + + queue.Consume(1); + RUNNER_ASSERT(queue.Size() == 5); + RUNNER_ASSERT(BinaryQueueToString(queue) == "bcdef"); + + queue.Consume(2); + RUNNER_ASSERT(queue.Size() == 3); + RUNNER_ASSERT(BinaryQueueToString(queue) == "def"); + + queue.Consume(1); + RUNNER_ASSERT(queue.Size() == 2); + RUNNER_ASSERT(BinaryQueueToString(queue) == "ef"); + + queue.Consume(2); + RUNNER_ASSERT(queue.Size() == 0); + RUNNER_ASSERT(BinaryQueueToString(queue) == ""); +} + +/* +Name: BinaryQueue_Flatten +Description: tests comsuming portions of 1 and more bytes +Expected: stringified content and size should match expected +*/ +RUNNER_TEST(BinaryQueue_Flatten) +{ + DPL::BinaryQueue queue; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + queue.AppendCopy("g", 1); + + RUNNER_ASSERT(queue.Size() == 7); + + RUNNER_ASSERT(BinaryQueueToString(queue) == "abcdefg"); +} + +/* +Name: BinaryQueue_FlattenConsume +Description: tests comsuming portions of 1 and more bytes +Expected: stringified content and size should match expected + reading and discarding bytes should affect queue's size and content +*/ +RUNNER_TEST(BinaryQueue_FlattenConsume) +{ + DPL::BinaryQueue queue; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + + RUNNER_ASSERT(queue.Size() == 6); + + char buffer[7] = { '\0' }; + queue.FlattenConsume(buffer, 3); + + RUNNER_ASSERT(queue.Size() == 3); + RUNNER_ASSERT(BinaryQueueToString(queue) == "def"); +} + +/* +Name: BinaryQueue_AppendCopyFrom +Description: tests creating copy of not empty queue (use of: AppendCopyFrom) +Expected: stringified content and size should match expected + from original queue and it's copy +*/ +RUNNER_TEST(BinaryQueue_AppendCopyFrom) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + + copy.AppendCopyFrom(queue); + + RUNNER_ASSERT(queue.Size() == 6); + RUNNER_ASSERT(copy.Size() == 6); + RUNNER_ASSERT(BinaryQueueToString(queue) == "abcdef"); + RUNNER_ASSERT(BinaryQueueToString(copy) == "abcdef"); +} + +/* +Name: BinaryQueue_AppendCopyTo +Description: tests creating copy of not empty queue (use of: AppendCopyTo) +Expected: stringified content and size should match expected + from original queue and it's copy +*/ +RUNNER_TEST(BinaryQueue_AppendCopyTo) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + + queue.AppendCopyTo(copy); + + RUNNER_ASSERT(queue.Size() == 6); + RUNNER_ASSERT(copy.Size() == 6); + RUNNER_ASSERT(BinaryQueueToString(queue) == "abcdef"); + RUNNER_ASSERT(BinaryQueueToString(copy) == "abcdef"); +} + +/* +Name: BinaryQueue_AppendMoveFrom +Description: tests moving content of not empty queue (use of: AppendMoveFrom) +Expected: stringified content and size should match expected + for new queue. Old queue should be empty after operation +*/ +RUNNER_TEST(BinaryQueue_AppendMoveFrom) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + + copy.AppendMoveFrom(queue); + + RUNNER_ASSERT(queue.Size() == 0); + RUNNER_ASSERT(copy.Size() == 6); + RUNNER_ASSERT(BinaryQueueToString(queue) == ""); + RUNNER_ASSERT(BinaryQueueToString(copy) == "abcdef"); +} + +/* +Name: BinaryQueue_AppendMoveFrom +Description: tests moving content of not empty queue (use of: AppendMoveTo) +Expected: stringified content and size should match expected + for new queue. Old queue should be empty after operation +*/ +RUNNER_TEST(BinaryQueue_AppendMoveTo) +{ + DPL::BinaryQueue queue; + DPL::BinaryQueue copy; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + + queue.AppendMoveTo(copy); + + RUNNER_ASSERT(queue.Size() == 0); + RUNNER_ASSERT(copy.Size() == 6); + RUNNER_ASSERT(BinaryQueueToString(queue) == ""); + RUNNER_ASSERT(BinaryQueueToString(copy) == "abcdef"); +} + +class Visitor : + public DPL::BinaryQueue::BucketVisitor +{ + private: + int m_index; + + public: + Visitor() : + m_index(0) + {} + + virtual void OnVisitBucket(const void *buffer, size_t bufferSize) + { + const char *str = static_cast(buffer); + + if (m_index == 0) { + RUNNER_ASSERT(bufferSize == 4); + RUNNER_ASSERT(str[0] == 'a'); + RUNNER_ASSERT(str[1] == 'b'); + RUNNER_ASSERT(str[2] == 'c'); + RUNNER_ASSERT(str[3] == 'd'); + } else if (m_index == 1) { + RUNNER_ASSERT(bufferSize == 2); + RUNNER_ASSERT(str[0] == 'e'); + RUNNER_ASSERT(str[1] == 'f'); + } else { + RUNNER_FAIL; + } + + ++m_index; + } +}; + +/* +Name: BinaryQueue_Visitor +Description: tests byte by byte content of queue by use of visitor +Expected: stringified content and size should match expected + Each byte should be at right position +*/ +RUNNER_TEST(BinaryQueue_Visitor) +{ + DPL::BinaryQueue queue; + + queue.AppendCopy("abcd", 4); + queue.AppendCopy("ef", 2); + + Visitor visitor; + queue.VisitBuckets(&visitor); +} + +RUNNER_TEST(BinaryQueue_AbstracInputRead) +{ + DPL::BinaryQueue queue; + + queue.AppendCopy("abcd", 4); + + queue.Read(0); + + RUNNER_ASSERT(BinaryQueueToString(*queue.Read(1).get()) == "a"); + RUNNER_ASSERT(BinaryQueueToString(*queue.Read(2).get()) == "bc"); + RUNNER_ASSERT(BinaryQueueToString(*queue.Read(1).get()) == "d"); + + RUNNER_ASSERT(queue.Size() == 0); +} + +/* +Name: BinaryQueue_AbstracOutputWrite +Description: tests appending one queue to another +Expected: written bytes shoudl affect content and size of queue +*/ +RUNNER_TEST(BinaryQueue_AbstracOutputWrite) +{ + DPL::BinaryQueue queue; + queue.AppendCopy("abcd", 4); + + DPL::BinaryQueue stream; + + stream.Write(queue, 4); + + RUNNER_ASSERT(BinaryQueueToString(*queue.Read(4).get()) == "abcd"); +} diff --git a/tests/core/test_bind.cpp b/tests/core/test_bind.cpp new file mode 100644 index 0000000..f71d418 --- /dev/null +++ b/tests/core/test_bind.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_bind.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test bind + */ +#include + +#include +#include + +namespace { +const int MAGIC_INT = 42; +const double MAGIC_DOUBLE = 42.42; + +struct BindTestBase { + BindTestBase() : called{false} {} + + bool called; +}; + +struct BindNoArguments : BindTestBase { + void foo() { called = true; } +}; + +struct BindWithArguments : BindTestBase { + void foo(int, double) { called = true; } +}; + +struct BindWithArgumentsAndResult : BindTestBase { + int foo(int, double) { called = true; return MAGIC_INT; } +}; +} + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: Bind_NoArguments +Description: tests binding method without arguments +Expected: bound method called +*/ +RUNNER_TEST(Bind_NoArguments) +{ + BindNoArguments test; + + std::function delegate = DPL::Bind(&BindNoArguments::foo, &test); + delegate(); + + RUNNER_ASSERT(test.called); +} + +/* +Name: Bind_WithArguments +Description: tests binding method with arguments +Expected: bound method called +*/ +RUNNER_TEST(Bind_WithArguments) +{ + BindWithArguments test; + + std::function delegate = + DPL::Bind(&BindWithArguments::foo, &test); + delegate(MAGIC_INT, MAGIC_DOUBLE); + + RUNNER_ASSERT(test.called); +} + +/* +Name: Bind_WithArgumentsAndResult +Description: tests binding method with arguments and result +Expected: bound method called +*/ +RUNNER_TEST(Bind_WithArgumentsAndResult) +{ + BindWithArgumentsAndResult test; + + std::function delegate = + DPL::Bind(&BindWithArgumentsAndResult::foo, &test); + int result = delegate(MAGIC_INT, MAGIC_DOUBLE); + + RUNNER_ASSERT(test.called); + RUNNER_ASSERT(MAGIC_INT == result); +} diff --git a/tests/core/test_foreach.cpp b/tests/core/test_foreach.cpp new file mode 100644 index 0000000..08d66df --- /dev/null +++ b/tests/core/test_foreach.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_foreach.cpp + * @author Bartosz Janiak (b.janiak@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of foreach tests. + */ + +#include +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +static const size_t testContainerSize = 1024; + +template +void VerifyForeach(Container& container) +{ + size_t i = 0; + FOREACH(it, container) + { + RUNNER_ASSERT(*it == i); + i++; + } + RUNNER_ASSERT(i == container.size()); +} + +#define VERIFY_FOREACH(container) \ + { \ + size_t i = 0; \ + FOREACH(it, container) \ + { \ + RUNNER_ASSERT(*it == i); \ + i++; \ + } \ + } + +static size_t numberOfCallsToTemporaryList = 0; +std::list temporaryList(); +std::list temporaryList() +{ + ++numberOfCallsToTemporaryList; + std::list list; + for (size_t i = 0; i < testContainerSize; i++) { + list.push_back(i); + } + return list; +} + +static size_t numberOfCallsToTemporaryVector = 0; +std::vector temporaryVector(); +std::vector temporaryVector() +{ + ++numberOfCallsToTemporaryVector; + std::vector vector; + for (size_t i = 0; i < testContainerSize; i++) { + vector.push_back(i); + } + return vector; +} + +static size_t numberOfCallsToTemporarySet = 0; +std::set temporarySet(); +std::set temporarySet() +{ + ++numberOfCallsToTemporarySet; + std::set set; + for (size_t i = 0; i < testContainerSize; i++) { + set.insert(i); + } + return set; +} + +/* +Name: Foreach_std_containers +Description: tests iterating contianers set, list, vector using foreach +Expected: value supplied by foreach matches sequence of integers +*/ +RUNNER_TEST(Foreach_std_containers) +{ + std::vector vector; + std::list list; + std::set set; + + for (size_t i = 0; i < testContainerSize; i++) { + vector.push_back(i); + list.push_back(i); + set.insert(i); + } + + VerifyForeach(vector); + VerifyForeach(list); + VerifyForeach(set); + + VERIFY_FOREACH(temporaryList()); + VERIFY_FOREACH(temporaryVector()); + VERIFY_FOREACH(temporarySet()); + + RUNNER_ASSERT(numberOfCallsToTemporaryList == 1); + RUNNER_ASSERT(numberOfCallsToTemporaryVector == 1); + RUNNER_ASSERT(numberOfCallsToTemporarySet == 1); +} diff --git a/tests/core/test_log_unhandled_exception.cpp b/tests/core/test_log_unhandled_exception.cpp new file mode 100644 index 0000000..3299357 --- /dev/null +++ b/tests/core/test_log_unhandled_exception.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_log_unhandled_exception.cpp + * @author Pawel Sikorski (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief + */ +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +class MyException +{}; + +class MyDPLException +{ + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, MyException) +}; + +class MySTDException : + public std::exception +{ + public: + virtual const char* what() const throw() + { + return "my std exception occurred"; + } +}; + +/* +Name: Log_Unknown_Exception +Description: tests exceptions catching macros +Expected: unknown exception should be catched + +TODO: workaround abort call +*/ +RUNNER_TEST(Log_Unknown_Exception) +{ + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + // throw MyException(); + } + UNHANDLED_EXCEPTION_HANDLER_END + RUNNER_ASSERT(true); +} + +/* +Name: Log_DPL_Exception +Description: tests exceptions catching macros +Expected: DPL exception should be catched + +TODO: workaround abort call +*/ +RUNNER_TEST(Log_DPL_Exception) +{ + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + // Throw(MyDPLException::MyException); + } + UNHANDLED_EXCEPTION_HANDLER_END + RUNNER_ASSERT(true); +} + +/* +Name: Log_STD_Exception +Description: tests exceptions catching macros +Expected: STD exception should be catched + +TODO: workaround abort call +*/ +RUNNER_TEST(Log_STD_Exception) +{ + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + // throw MySTDException(); + } + UNHANDLED_EXCEPTION_HANDLER_END + RUNNER_ASSERT(true); +} diff --git a/tests/core/test_once.cpp b/tests/core/test_once.cpp new file mode 100644 index 0000000..34e32fd --- /dev/null +++ b/tests/core/test_once.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_once.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of once tests + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +namespace // anonymous +{ +int g_counter; + +void Delegate() +{ + ++g_counter; +} +} // namespace anonymous + +RUNNER_TEST(Once_DoubleCall) +{ + g_counter = 0; + + DPL::Once once; + + once.Call(&Delegate); + once.Call(&Delegate); + + RUNNER_ASSERT_MSG(g_counter == 1, "Counter value is: " << g_counter); +} + +class MyThread : + public DPL::Thread +{ + protected: + virtual int ThreadEntry() + { + DPL::WaitForSingleHandle(m_event->GetHandle()); + m_once->Call(std::bind(&MyThread::Call, this)); + return 0; + } + + void Call() + { + ++*m_atom; + } + + public: + MyThread(DPL::WaitableEvent *event, DPL::Once *once, DPL::Atomic *atom) : + m_event(event), m_once(once), m_atom(atom) + {} + + private: + DPL::WaitableEvent *m_event; + DPL::Once *m_once; + DPL::Atomic *m_atom; +}; + +/* +Name: Once_MultiThreadCall +Description: tests once call wrapper for use by multiple threads +Expected: function should be called just once from one of running threads +*/ +RUNNER_TEST(Once_MultiThreadCall) +{ + const size_t NUM_THREADS = 20; + typedef std::shared_ptr ThreadPtr; + + ThreadPtr threads[NUM_THREADS]; + DPL::WaitableEvent event; + DPL::Once once; + DPL::Atomic atom; + + for (size_t i = 0; i < NUM_THREADS; ++i) { + (threads[i] = ThreadPtr(new MyThread(&event, &once, &atom)))->Run(); + } + + event.Signal(); + + for (size_t i = 0; i < NUM_THREADS; ++i) { + threads[i]->Quit(); + } + + RUNNER_ASSERT_MSG(atom == 1, "Atom value is: " << atom); +} diff --git a/tests/core/test_scope_guard.cpp b/tests/core/test_scope_guard.cpp new file mode 100644 index 0000000..7c09645 --- /dev/null +++ b/tests/core/test_scope_guard.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_scope_guard.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test scope guard + */ +#include +#include + +namespace { +bool g_guardCalled = false; + +void regularFunction() +{ + g_guardCalled = true; +} + +struct Functor +{ + explicit Functor(bool& guardCalled) + : m_guardCalled(guardCalled) + {} + + void operator()() + { + m_guardCalled = true; + } + + bool& m_guardCalled; +}; +} + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ScopeGuard_MakeScopeGuard_RegularFunction +Description: tests scope guard, created explicitly, with regular function +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_MakeScopeGuard_RegularFunction) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard(regularFunction); + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_MakeScopeGuard_Functor +Description: tests scope guard, created explicitly, with a functor +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_MakeScopeGuard_Functor) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard(Functor(g_guardCalled)); + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_MakeScopeGuard_Lambda +Description: tests scope guard, created explicitly, with a lambda +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_MakeScopeGuard_Lambda) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard( + [&g_guardCalled](){ g_guardCalled = true; }); + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_Macro +Description: tests scope guard, created implicitly, with a lambda +Expected: guard should be called +*/ +RUNNER_TEST(ScopeGuard_Macro) +{ + g_guardCalled = false; + { + DPL_SCOPE_EXIT(&g_guardCalled) + { + g_guardCalled = true; + }; + } + RUNNER_ASSERT(g_guardCalled); +} + +/* +Name: ScopeGuard_Release +Description: tests scope guard releasing API +Expected: guard should not be called +*/ +RUNNER_TEST(ScopeGuard_Release) +{ + g_guardCalled = false; + { + auto guard = DPL::MakeScopeGuard( + [&g_guardCalled](){ g_guardCalled = true; }); + guard.Release(); + } + RUNNER_ASSERT(!g_guardCalled); +} diff --git a/tests/core/test_scoped_array.cpp b/tests/core/test_scoped_array.cpp new file mode 100644 index 0000000..f2a3b4b --- /dev/null +++ b/tests/core/test_scoped_array.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_scoped_array.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test scoped array + */ +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ScopedArray_Zero +Description: tests emptiness of empty scoped array +Expected: array should be empty +*/ +RUNNER_TEST(ScopedArray_Zero) +{ + DPL::ScopedArray array; + + RUNNER_ASSERT(!array); + RUNNER_ASSERT(!!!array); +} + +/* +Name: ScopedArray_NonZero +Description: tests emptiness of not empty scoped array +Expected: array should be not empty +*/ +RUNNER_TEST(ScopedArray_NonZero) +{ + DPL::ScopedArray array(new char[7]); + + RUNNER_ASSERT(array); + RUNNER_ASSERT(!!array); +} + +/* +Name: ScopedArray_Reset +Description: tests reseting content of array +Expected: array should be empty after reset +*/ +RUNNER_TEST(ScopedArray_Reset) +{ + DPL::ScopedArray array(new char[7]); + array.Reset(); + + RUNNER_ASSERT(!array); + + array.Reset(new char); + RUNNER_ASSERT(array); +} + +/* +Name: ScopedArray_ArrayOperator +Description: tests accessing elements of array +Expected: returned values should be equal to those which were set +*/ +RUNNER_TEST(ScopedArray_ArrayOperator) +{ + DPL::ScopedArray array(new char[7]); + + array[1] = array[2] = 3; + + RUNNER_ASSERT(array[1] == 3); + RUNNER_ASSERT(array[2] == 3); +} diff --git a/tests/core/test_scoped_close.cpp b/tests/core/test_scoped_close.cpp new file mode 100644 index 0000000..3549fed --- /dev/null +++ b/tests/core/test_scoped_close.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_scoped_close.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test scoped close + */ +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +// DUNNO diff --git a/tests/core/test_scoped_dir.cpp b/tests/core/test_scoped_dir.cpp new file mode 100644 index 0000000..8cf0c3c --- /dev/null +++ b/tests/core/test_scoped_dir.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_scoped_dir.cpp + * @author Iwanek Tomasz (t.iwanek@smasung.com) + * @version 1.0 + * @brief Scoped directory test + */ +#include +#include + +#include +#include +#include + +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ScopedDir_Basic +Description: tests if scoped directory is working +Expected: directory created and removed +*/ +RUNNER_TEST(ScopedDir_Basic) +{ + const char * path = "/tmp/wrttest123456"; + if(access(path, F_OK) == 0) + { + RUNNER_ASSERT_MSG(!remove(path), "Cannot remove test directory"); + } + + { + DPL::ScopedDir dir(path, S_IRUSR | S_IWUSR); + std::ostringstream command; + command << "touch " << path << "/" << "file.txt"; + (void)system(command.str().c_str()); + RUNNER_ASSERT_MSG(access(path, R_OK) == 0, "Directory should be accessible"); + RUNNER_ASSERT_MSG(access(path, W_OK) == 0, "Directory should be writable"); + } + RUNNER_ASSERT_MSG(access(path, F_OK) != 0, "Directory should not exists"); +} diff --git a/tests/core/test_scoped_fclose.cpp b/tests/core/test_scoped_fclose.cpp new file mode 100644 index 0000000..7667a9e --- /dev/null +++ b/tests/core/test_scoped_fclose.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file test_scoped_fclose.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test scoped fclose + */ + +#include +#include + +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +namespace { +FILE* MakeTmp() +{ + FILE* result = NULL; + do { + result = tmpfile(); + } while (NULL != result && EINTR == errno); + return result; +} +} //anonymous namespace + +/* +Name: ScopedFClose_Zero +Description: tests if operator ! works correct for closed file +Expected: file should be closed +*/ +RUNNER_TEST(ScopedFClose_Zero) +{ + DPL::ScopedFClose file; + + RUNNER_ASSERT(!file); + RUNNER_ASSERT(!!!file); +} + +/* +Name: ScopedArray_NonZero +Description: tests if operator ! works correct for open file +Expected: file should be open +*/ +RUNNER_TEST(ScopedFClose_NonZero) +{ + DPL::ScopedFClose file(MakeTmp()); + + RUNNER_ASSERT(file); + RUNNER_ASSERT(!!file); +} + +/* +Name: ScopedFClose_Reset +Description: tests reseting of scoped file +Expected: file should be closed after reset +*/ +RUNNER_TEST(ScopedFClose_Reset) +{ + DPL::ScopedFClose file(MakeTmp()); + file.Reset(); + + RUNNER_ASSERT(!file); + + file.Reset(MakeTmp()); + RUNNER_ASSERT(file); +} + diff --git a/tests/core/test_scoped_free.cpp b/tests/core/test_scoped_free.cpp new file mode 100644 index 0000000..25bd6d6 --- /dev/null +++ b/tests/core/test_scoped_free.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_scoped_free.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test scoped free + */ +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ScopedFree_Zero +Description: Checks emptiness of not set scoped free +Expected: resource should be freed +*/ +RUNNER_TEST(ScopedFree_Zero) +{ + DPL::ScopedFree free; + + RUNNER_ASSERT(!free); + RUNNER_ASSERT(!!!free); +} + +/* +Name: ScopedFree_NonZero +Description: Checks emptiness of set scoped free +Expected: resource should not be reported as freed +*/ +RUNNER_TEST(ScopedFree_NonZero) +{ + DPL::ScopedFree free(malloc(7)); + + RUNNER_ASSERT(free); + RUNNER_ASSERT(!!free); +} + +/* +Name: ScopedFree_Reset +Description: Checks reseting scoped free +Expected: resource should be freed after reset +*/ +RUNNER_TEST(ScopedFree_Reset) +{ + DPL::ScopedFree free(malloc(7)); + free.Reset(); + + RUNNER_ASSERT(!free); + + free.Reset(malloc(8)); + RUNNER_ASSERT(free); +} diff --git a/tests/core/test_scoped_ptr.cpp b/tests/core/test_scoped_ptr.cpp new file mode 100644 index 0000000..af17bac --- /dev/null +++ b/tests/core/test_scoped_ptr.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_scoped_ptr.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test scoped ptr + */ +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ScopedPtr_Zero +Description: Checks if operator! works +Expected: resource should be not set +*/ +RUNNER_TEST(ScopedPtr_Zero) +{ + DPL::ScopedPtr ptr; + + RUNNER_ASSERT(!ptr); + RUNNER_ASSERT(!!!ptr); +} + +/* +Name: ScopedPtr_NonZero +Description: Checks if operator! works +Expected: resource should be set +*/ +RUNNER_TEST(ScopedPtr_NonZero) +{ + DPL::ScopedPtr ptr(new char(7)); + + RUNNER_ASSERT(ptr); + RUNNER_ASSERT(!!ptr); +} + +/* +Name: ScopedPtr_Reset +Description: Checks reseting scoped ptr +Expected: resource should be not set after reset +*/ +RUNNER_TEST(ScopedPtr_Reset) +{ + DPL::ScopedPtr ptr(new char(7)); + ptr.Reset(); + + RUNNER_ASSERT(!ptr); + + ptr.Reset(new char); + RUNNER_ASSERT(ptr); +} + +/* +Name: ScopedPtr_Operators +Description: Checks access operator +Expected: address of resource should be same as this, received from Get() method +*/ +RUNNER_TEST(ScopedPtr_Operators) +{ + DPL::ScopedPtr ptr(new char(7)); + + RUNNER_ASSERT(*ptr == *ptr.Get()); +} diff --git a/tests/core/test_semaphore.cpp b/tests/core/test_semaphore.cpp new file mode 100644 index 0000000..c93b365 --- /dev/null +++ b/tests/core/test_semaphore.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_semaphore.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of semaphore tests + */ +#include +#include +#include +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +class SemaphoreThread : + public DPL::Thread +{ + int m_delta; + int m_times; + int *m_value; + std::string m_semaphoreName; + + public: + SemaphoreThread(int delta, + int times, + int *value, + const std::string &semaphoreName) : + m_delta(delta), + m_times(times), + m_value(value), + m_semaphoreName(semaphoreName) + {} + + protected: + virtual int ThreadEntry() + { + DPL::Semaphore semaphore(m_semaphoreName); + + for (int i = 0; i < m_times; ++i) { + // Take scoped semaphore lock + DPL::Semaphore::ScopedLock lock(&semaphore); + *m_value += m_delta; + } + + return 0; + } +}; + +/* +Name: Semaphore_NamedIncrementDecrement +Description: Checks if semaphore are working +Expected: value should not change after all +*/ +RUNNER_TEST(Semaphore_NamedIncrementDecrement) +{ + std::string semaphoreName = + "dpl_test_semaphore_" + + DPL::lexical_cast(std::time(NULL)); + + int value = 0; + SemaphoreThread threadA(-1, 10000, &value, semaphoreName); + SemaphoreThread threadB(+1, 10000, &value, semaphoreName); + + threadA.Run(); + threadB.Run(); + + threadA.Quit(); + threadB.Quit(); + + RUNNER_ASSERT_MSG(value == 0, "Final value is: " << value); +} diff --git a/tests/core/test_serialization.cpp b/tests/core/test_serialization.cpp new file mode 100644 index 0000000..7bbf8de --- /dev/null +++ b/tests/core/test_serialization.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_address.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of serialization tests + */ + +#include +#include +#include +#include + +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +// test stream class +class BinaryStream : public DPL::IStream +{ + public: + virtual void Read(size_t num, void * bytes) + { + for (unsigned i = 0; i < num; ++i) { + ((unsigned char*)bytes)[i] = data[i + readPosition]; + } + readPosition += num; + } + virtual void Write(size_t num, const void * bytes) + { + for (unsigned i = 0; i < num; ++i) { + data.push_back(((unsigned char*)bytes)[i]); + } + } + BinaryStream() + { + readPosition = 0; + } + virtual ~BinaryStream(){} + + private: + std::vector data; + unsigned readPosition; +}; + +//test ISerializable class +class TestClass : public DPL::ISerializable +{ + public: + TestClass(int val, std::string str1, std::string str2) + { + a = val; + b = str1; + c.push_back(str1); + c.push_back(str2); + c.push_back(str1 + str2); + } + TestClass(DPL::IStream& stream) : + a(0) //TODO: consider the need (g.rynkowski) + { + DPL::Deserialization::Deserialize(stream, a); + DPL::Deserialization::Deserialize(stream, b); + DPL::Deserialization::Deserialize(stream, c); + } + virtual void Serialize(DPL::IStream& stream) const + { + DPL::Serialization::Serialize(stream, a); + DPL::Serialization::Serialize(stream, b); + DPL::Serialization::Serialize(stream, c); + } + virtual ~TestClass(){} + virtual bool operator==(const TestClass& other) + { + return (a == other.a && + b == other.b && + c.size() == other.c.size() && + c[0] == other.c[0] && + c[1] == other.c[1] && + c[2] == other.c[2]); + } + + private: + int a; + std::string b; + std::vector c; +}; + +/* +Name: Serialize_primitives +Description: Tests serialization of primitives types +Expected: serialized value after deserialization + should be equal to deserialied value +*/ +RUNNER_TEST(Serialize_primitives) +{ + int a = 1; + bool b = true; + unsigned c = 23; + BinaryStream stream; + DPL::Serialization::Serialize(stream, a); + DPL::Serialization::Serialize(stream, b); + DPL::Serialization::Serialize(stream, c); + int test_int; + DPL::Deserialization::Deserialize(stream, test_int); + RUNNER_ASSERT(test_int == a); + bool test_bool; + DPL::Deserialization::Deserialize(stream, test_bool); + RUNNER_ASSERT(test_bool == b); + unsigned test_unsigned; + DPL::Deserialization::Deserialize(stream, test_unsigned); + RUNNER_ASSERT(test_unsigned == c); +} + +/* +Name: Serialize_primitive_pointers +Description: Tests serialization of primitives pointer types +Expected: serialized value after deserialization + should be equal to deserialied value +*/ +RUNNER_TEST(Serialize_primitive_pointers) +{ + int a = 1; + bool b = true; + unsigned c = 23; + BinaryStream stream; + DPL::Serialization::Serialize(stream, &a); + DPL::Serialization::Serialize(stream, &b); + DPL::Serialization::Serialize(stream, &c); + int* test_int; + DPL::Deserialization::Deserialize(stream, test_int); + RUNNER_ASSERT(test_int != NULL && *test_int == a); + bool* test_bool; + DPL::Deserialization::Deserialize(stream, test_bool); + RUNNER_ASSERT(test_bool != NULL && *test_bool == b); + unsigned* test_unsigned; + DPL::Deserialization::Deserialize(stream, test_unsigned); + RUNNER_ASSERT(test_unsigned != NULL && *test_unsigned == c); + delete test_int; + delete test_bool; + delete test_unsigned; +} + +/* +Name: Serialize_strings +Description: Tests serialization of strings +Expected: serialized value after deserialization + should be equal to deserialied value +*/ +RUNNER_TEST(Serialize_strings) +{ + std::string str1 = "ALA MA KOTA"; + std::string str2 = "MULTILINE\nTEST"; + BinaryStream stream; + DPL::Serialization::Serialize(stream, str1); + DPL::Serialization::Serialize(stream, str2); + std::string test_str1; + DPL::Deserialization::Deserialize(stream, test_str1); + RUNNER_ASSERT(test_str1 == str1); + std::string test_str2; + DPL::Deserialization::Deserialize(stream, test_str2); + RUNNER_ASSERT(test_str2 == str2); +} + +/* +Name: Serialize_string_pointers +Description: Tests serialization of string pointers +Expected: serialized value after deserialization + should be equal to deserialied value +*/ +RUNNER_TEST(Serialize_string_pointers) +{ + std::string str1 = "ALA MA KOTA"; + std::string str2 = "MULTILINE\nTEST"; + BinaryStream stream; + DPL::Serialization::Serialize(stream, &str1); + DPL::Serialization::Serialize(stream, &str2); + std::string* test_str1; + DPL::Deserialization::Deserialize(stream, test_str1); + RUNNER_ASSERT(test_str1 != NULL && *test_str1 == str1); + std::string* test_str2; + DPL::Deserialization::Deserialize(stream, test_str2); + RUNNER_ASSERT(test_str2 != NULL && *test_str2 == str2); + delete test_str1; + delete test_str2; +} + +/* +Name: Serialize_containers +Description: Tests serialization of containers +Expected: serialized value after deserialization + should be equal to deserialied value +*/ +RUNNER_TEST(Serialize_containers) +{ + std::vector vec; + vec.push_back(134); + vec.push_back(265); + std::list list; + list.push_back(true); + list.push_back(false); + std::pair pair; + pair.first = -23; + pair.second = 1234; + std::map map; + map.insert(std::pair(45, "ALA MA CZARNEGO KOTA")); + map.insert(std::pair(-78, "...A MOZE\nMA\nWIELE LINIJEK")); + BinaryStream stream; + DPL::Serialization::Serialize(stream, vec); + DPL::Serialization::Serialize(stream, list); + DPL::Serialization::Serialize(stream, pair); + DPL::Serialization::Serialize(stream, map); + std::vector test_vec; + DPL::Deserialization::Deserialize(stream, test_vec); + RUNNER_ASSERT(test_vec.size() == vec.size() && + test_vec[0] == vec[0] && test_vec[1] == vec[1]); + std::list test_list; + DPL::Deserialization::Deserialize(stream, test_list); + RUNNER_ASSERT(test_list.size() == list.size() && + test_list.front() == list.front() && + test_list.back() == test_list.back()); + std::pair test_pair; + DPL::Deserialization::Deserialize(stream, test_pair); + RUNNER_ASSERT(test_pair.first == pair.first && + test_pair.second == pair.second); + std::map test_map; + DPL::Deserialization::Deserialize(stream, test_map); + RUNNER_ASSERT(test_map.size() == map.size() && + test_map.at(45) == map.at(45) && + test_map.at(-78) == map.at(-78)); +} + +/* +Name: Serialize_objects +Description: Tests serialization of DPL::ISerializable derived objects +Expected: serialized value after deserialization + should be equal to deserialied value +*/ +RUNNER_TEST(Serialize_objects) +{ + TestClass a(123, "ASDGHUADB\n\n5679b^^()*", "TEST_STRING"), + b(679, "HUSPIDNSAHDPA", "\nASDSADASD\naDSADASD8"); + BinaryStream stream; + DPL::Serialization::Serialize(stream, a); + DPL::Serialization::Serialize(stream, b); + TestClass test_a(0, "", ""), test_b(0, "", ""); + DPL::Deserialization::Deserialize(stream, test_a); + RUNNER_ASSERT(test_a == a); + DPL::Deserialization::Deserialize(stream, test_b); + RUNNER_ASSERT(test_b == b); +} + +/* +Name: Serialize_all +Description: Tests serialization of compound objects +Expected: serialized value after deserialization + should be equal to deserialied value +*/ +RUNNER_TEST(Serialize_all) +{ + std::map > map; + std::vector vec; + vec.push_back(new TestClass(123, "ASDGHUADB\n\n5679b^^()*", "TEST_STRING")); + vec.push_back(new TestClass(679, "HUSPIDNSAHDPA", "\nASDSADASD\naDSADASD8")); + map.insert(std::pair >("KEY1", vec)); + map.insert(std::pair >("KEY2", vec)); + BinaryStream stream; + + DPL::Serialization::Serialize(stream, map); + + std::map > test_map; + DPL::Deserialization::Deserialize(stream, test_map); + RUNNER_ASSERT(map.size() == test_map.size()); + std::vector test_vec1, test_vec2; + test_vec1 = map.at("KEY1"); + test_vec2 = test_map.at("KEY1"); + RUNNER_ASSERT(test_vec1.size() == test_vec2.size()); + unsigned i; + for (i = 0; i < test_vec1.size(); ++i) { + RUNNER_ASSERT((*test_vec1[i]) == (*test_vec2[i])); + } + test_vec1 = map.at("KEY2"); + test_vec2 = test_map.at("KEY2"); + RUNNER_ASSERT(test_vec1.size() == test_vec2.size()); + for (i = 0; i < test_vec1.size(); ++i) { + RUNNER_ASSERT((*test_vec1[i]) == (*test_vec2[i])); + } +} + diff --git a/tests/core/test_shared_ptr.cpp b/tests/core/test_shared_ptr.cpp new file mode 100644 index 0000000..8e59075 --- /dev/null +++ b/tests/core/test_shared_ptr.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_shared_ptr.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test shared ptr + */ +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: SharedPtr_Zero +Description: Tests behaviour of null shared pointer +Expected: pointer should imitate null pointer +*/ +RUNNER_TEST(SharedPtr_Zero) +{ + DPL::SharedPtr ptr; + + RUNNER_ASSERT(!ptr); + RUNNER_ASSERT(!!!ptr); + RUNNER_ASSERT(ptr == DPL::SharedPtr()); +} + +/* +Name: SharedPtr_NonZero +Description: Tests behaviour of not null shared pointer +Expected: pointer should imitate null pointer +*/ +RUNNER_TEST(SharedPtr_NonZero) +{ + DPL::SharedPtr ptr(new char(7)); + + RUNNER_ASSERT(ptr); + RUNNER_ASSERT(!!ptr); + RUNNER_ASSERT(ptr != DPL::SharedPtr()); +} + +/* +Name: SharedPtr_Copy +Description: Tests equality of shared pointer pointing same resource +Expected: pointers should imitate primitive pointer bahaviour +*/ +RUNNER_TEST(SharedPtr_Copy) +{ + DPL::SharedPtr ptr1(new char(7)); + DPL::SharedPtr ptr2(new char(7)); + + RUNNER_ASSERT(ptr1 != ptr2); + + ptr2 = ptr1; + + RUNNER_ASSERT(ptr1 == ptr2); +} + +/* +Name: SharedPtr_Reset +Description: Tests reseting shared pointer +Expected: pointers should imitate primitive pointer bahaviour after reset +*/ +RUNNER_TEST(SharedPtr_Reset) +{ + DPL::SharedPtr ptr(new char(7)); + ptr.Reset(); + + RUNNER_ASSERT(!ptr); + + ptr.Reset(new char); + RUNNER_ASSERT(ptr); +} + +/* +Name: SharedPtr_RefCounting +Description: Tests use count od shared pointer +Expected: counters should be equal for equal pointers + Count number should match expected +*/ +RUNNER_TEST(SharedPtr_RefCounting) +{ + DPL::SharedPtr ptr1(new char(7)); + DPL::SharedPtr ptr2; + + ptr2 = ptr1; + + RUNNER_ASSERT(ptr1 == ptr2); + RUNNER_ASSERT(ptr1.GetUseCount() == ptr2.GetUseCount()); + RUNNER_ASSERT(ptr1.GetUseCount() == 2); +} + +/* +Name: SharedPtr_Operators +Description: Tests use of operator* +Expected: pointers should imitate primitive pointer bahaviour +*/ +RUNNER_TEST(SharedPtr_Operators) +{ + DPL::SharedPtr ptr(new char(7)); + + RUNNER_ASSERT(*ptr == *ptr.Get()); +} diff --git a/tests/core/test_single_instance.cpp b/tests/core/test_single_instance.cpp new file mode 100644 index 0000000..b17d583 --- /dev/null +++ b/tests/core/test_single_instance.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_single_instance.cpp + * @author Slawomir Pajak (s.pajak@partner.samsung.com) + * @version 1.0 + * @brief This file is the implementation file of single instance tests + */ +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +using namespace DPL; + +/* +Name: SingleInstance_lock_release +Description: tests single instance simple case +Expected: all operations succeed, no exceptions +*/ +RUNNER_TEST(SingleInstance_lock_release) +{ + SingleInstance instance; + RUNNER_ASSERT(instance.TryLock("testLockFile")); + + instance.Release(); + //Multiple call should be fine. + instance.Release(); + +} diff --git a/tests/core/test_static_block.cpp b/tests/core/test_static_block.cpp new file mode 100644 index 0000000..b7596ef --- /dev/null +++ b/tests/core/test_static_block.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file test_static_block.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 0.1 + * @brief + */ + +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +namespace { +bool ok_namespace = false; +bool ok_class = false; + +STATIC_BLOCK +{ + ok_namespace = true; +} + +struct A +{ + static void init() + { + ok_class = true; + } +}; +STATIC_BLOCK_CLASS( A, init ) +} + +/* +Name: StaticBlockInitCheck +Description: checks if static blocks were run +Expected: variables should be set +*/ +RUNNER_TEST(StaticBlockInitCheck) +{ + RUNNER_ASSERT(ok_namespace); + RUNNER_ASSERT(ok_class); +} diff --git a/tests/core/test_string.cpp b/tests/core/test_string.cpp new file mode 100644 index 0000000..e124376 --- /dev/null +++ b/tests/core/test_string.cpp @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_string.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of string tests + */ +#include +#include +#include +#include +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +unsigned char GetBaseCode(int index); +unsigned char GetBaseCode(int index) +{ + /* aaaack but it's fast and const should make it shared text page. */ + static const unsigned char pr2six[256] = { + /* ASCII table */ + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + return pr2six[index]; +} + +/* Function adapted from APR library (http://apr.apache.org/) */ +int wbxml_base64_decode(const char *buffer, char **result); +int wbxml_base64_decode(const char *buffer, char **result) +{ + int nbytesdecoded = 0, nprbytes = 0; + const char *bufin = NULL; + char *bufout = NULL; + + if ((buffer == NULL) || (result == NULL)) { + return 0; + } + + /* Initialize output buffer */ + *result = NULL; + + bufin = buffer; + while (GetBaseCode(*(bufin++)) <= 63) {} + + nprbytes = (bufin - buffer) - 1; + nbytesdecoded = ((nprbytes + 3) / 4) * 3; + + /* Malloc result buffer */ + if ((*result = (char*) malloc(nbytesdecoded + 1)) == NULL) { + return 0; + } + memset(*result, 0, nbytesdecoded + 1); + + bufout = *result; + bufin = buffer; + + while (nprbytes > 4) { + *(bufout++) = + (char)(GetBaseCode(*bufin) << 2 | GetBaseCode(bufin[1]) >> 4); + *(bufout++) = + (char)(GetBaseCode(bufin[1]) << 4 | GetBaseCode(bufin[2]) >> 2); + *(bufout++) = (char)(GetBaseCode(bufin[2]) << 6 | GetBaseCode(bufin[3])); + bufin += 4; + nprbytes -= 4; + } + + /* Note: (nprbytes == 1) would be an error, so just ingore that case */ + if (nprbytes > 1) { + *(bufout++) = + (char)(GetBaseCode(*bufin) << 2 | GetBaseCode(bufin[1]) >> 4); + } + if (nprbytes > 2) { + *(bufout++) = + (char)(GetBaseCode(bufin[1]) << 4 | GetBaseCode(bufin[2]) >> 2); + } + if (nprbytes > 3) { + *(bufout++) = (char)(GetBaseCode(bufin[2]) << 6 | GetBaseCode(bufin[3])); + } + + nbytesdecoded -= (4 - nprbytes) & 3; + + return nbytesdecoded; +} + +//#define TEST_CONVERSION(in_string, out_string, buffer_type, function + +const char utf32Encoded[] = + "RDAAAI0wAABvMAAAazAAAHswAAB4MAAAaDAAAAAwAABhMAAAijAAAGwwAACLMAAAkjAAAAAwAACP\ +MAAASzAAAIgwAABfMAAAjDAAAF0wAAAAMAAAZDAAAG0wAABqMAAAiTAAAIAwAAAAMAAARjAAAJAw\ +AABuMAAASjAAAE8wAACEMAAAfjAAAAAwAABRMAAAdTAAAFMwAABIMAAAZjAAAAAwAABCMAAAVTAA\ +AE0wAACGMAAAgTAAAH8wAABXMAAAADAAAJEwAAByMAAAgjAAAFswAABZMAAACgAAANsFAADaBQAA\ +IAAAANQFAADqBQAA6AUAAOEFAADnBQAAIAAAAOAFAADkBQAA5QUAACAAAADiBQAA3AUAACAAAADS\ +BQAA1QUAANYFAADcBQAAIAAAAOcFAADYBQAA3wUAACwAAAAgAAAA6QUAANMFAADXBQAA4wUAACAA\ +AADQBQAA6gUAACAAAADmBQAA0QUAANkFAAAgAAAA3AUAAN4FAADZBQAA3QUAAAoAAACk0AAApMIA\ +AFjHAAAgAAAA4KwAACDHAABwyAAAdKwAAEDHAAAgAAAAhccAACDCAAB8sAAArLkAACAAAADMuQAA\ +mLAAAHzFAAAgAAAAWNUAAOCsAAAgAAAAudIAAMS8AABc1QAAIAAAADCuAAAgwgAAQMcAACAAAABE\ +1QAAlMYAAFjOAAAgAAAASsUAAOSyAAAKAAAAUAAAAGMAAABoAAAAbgAAAAUBAAAHAQAAIAAAAHcA\ +AAAgAAAAdAAAABkBAAAgAAAAQgEAAPMAAABkAAAAegEAACAAAABqAAAAZQAAAHwBAABhAAAAIAAA\ +AGwAAAB1AAAAYgAAACAAAABvAAAAWwEAAG0AAAAgAAAAcwAAAGsAAAByAAAAegAAAHkAAABEAQAA\ +IAAAAGYAAABpAAAAZwAAAC4AAAAKAAAAQgAAAGwAAABvAAAAdwAAAHoAAAB5AAAAIAAAAG4AAABp\ +AAAAZwAAAGgAAAB0AAAALQAAAGYAAAByAAAAdQAAAG0AAABwAAAAcwAAACAAAAB2AAAAZQAAAHgA\ +AAAnAAAAZAAAACAAAABKAAAAYQAAAGMAAABrAAAAIAAAAFEAAAAuAAAACgAAAEYGAAA1BgAAIAAA\ +AC0GAABDBgAASgYAAEUGAAAgAAAARAYAAEcGAAAgAAAAMwYAADEGAAAgAAAAQgYAACcGAAA3BgAA\ +OQYAACAAAABIBgAAMAYAAEgGAAAgAAAANAYAACMGAABGBgAAIAAAADkGAAA4BgAASgYAAEUGAAAg\ +AAAARQYAAEMGAAAqBgAASAYAACgGAAAgAAAAOQYAAEQGAABJBgAAIAAAACsGAABIBgAAKAYAACAA\ +AAAjBgAALgYAADYGAAAxBgAAIAAAAEgGAABFBgAAOgYAAEQGAABBBgAAIAAAACgGAAAsBgAARAYA\ +AC8GAAAgAAAAIwYAADIGAAAxBgAAQgYAACAAAAAKAAAAEgQAACAAAABHBAAAMAQAAEkEAAAwBAAA\ +RQQAACAAAABOBAAAMwQAADAEAAAgAAAANgQAADgEAAA7BAAAIAAAADEEAABLBAAAIAAAAEYEAAA4\ +BAAAQgQAAEAEAABDBAAAQQQAAD8AAAAgAAAAFAQAADAEAAAsAAAAIAAAAD0EAAA+BAAAIAAAAEQE\ +AAAwBAAAOwQAAEwEAABIBAAAOAQAADIEAABLBAAAOQQAACAAAABNBAAAOgQAADcEAAA1BAAAPAQA\ +AD8EAAA7BAAATwQAAEAEAAAhAAAACgAAAKQDAACsAwAAxwMAALkDAADDAwAAxAMAALcDAAAgAAAA\ +sQMAALsDAADOAwAAwAMAALcDAAC+AwAAIAAAALIDAACxAwAAxgMAAK4DAADCAwAAIAAAAMgDAAC3\ +AwAAvAMAAK0DAAC9AwAAtwMAACAAAACzAwAAtwMAACwAAAAgAAAAtAMAAMEDAACxAwAAwwMAALoD\ +AAC1AwAAuwMAAK8DAAC2AwAAtQMAALkDAAAgAAAAxQMAAMADAACtAwAAwQMAACAAAAC9AwAAyQMA\ +ALgDAADBAwAAvwMAAM0DAAAgAAAAugMAAMUDAAC9AwAAzAMAAMIDAAAKAAAAVgAAAGkAAABjAAAA\ +dAAAAG8AAAByAAAAIAAAAGoAAABhAAAAZwAAAHQAAAAgAAAAegAAAHcAAAD2AAAAbAAAAGYAAAAg\ +AAAAQgAAAG8AAAB4AAAAawAAAOQAAABtAAAAcAAAAGYAAABlAAAAcgAAACAAAABxAAAAdQAAAGUA\ +AAByAAAAIAAAAPwAAABiAAAAZQAAAHIAAAAgAAAAZAAAAGUAAABuAAAAIAAAAGcAAAByAAAAbwAA\ +AN8AAABlAAAAbgAAACAAAABTAAAAeQAAAGwAAAB0AAAAZQAAAHIAAAAgAAAARAAAAGUAAABpAAAA\ +YwAAAGgAAAAKAAAAlokAAM6RAAAhcQAAUJYAAONeAAAM/wAAl3oAABZZAAAJZwAAzYUAAClZAAAK\ +AAAACgAAAAAAAAA="; + +const char utf8Encoded[] = + "44GE44KN44Gv44Gr44G744G444Go44CA44Gh44KK44Gs44KL44KS44CA44KP44GL44KI44Gf44KM\ +44Gd44CA44Gk44Gt44Gq44KJ44KA44CA44GG44KQ44Gu44GK44GP44KE44G+44CA44GR44G144GT\ +44GI44Gm44CA44GC44GV44GN44KG44KB44G/44GX44CA44KR44Gy44KC44Gb44GZCteb15og15TX\ +qteo16HXpyDXoNek16Ug16LXnCDXkteV15bXnCDXp9eY158sINep15PXl9ejINeQ16og16bXkdeZ\ +INec157XmdedCu2CpOyKpOydmCDqs6DsnKDsobDqsbTsnYAg7J6F7Iig64G866asIOunjOuCmOyV\ +vCDtlZjqs6Ag7Yq567OE7ZWcIOq4sOyIoOydgCDtlYTsmpTsuZgg7JWK64ukClBjaG7EhcSHIHcg\ +dMSZIMWCw7NkxbogamXFvGEgbHViIG/Fm20gc2tyennFhCBmaWcuCkJsb3d6eSBuaWdodC1mcnVt\ +cHMgdmV4J2QgSmFjayBRLgrZhti1INit2YPZitmFINmE2Ycg2LPYsSDZgtin2LfYuSDZiNiw2Ygg\ +2LTYo9mGINi52LjZitmFINmF2YPYqtmI2Kgg2LnZhNmJINir2YjYqCDYo9iu2LbYsSDZiNmF2LrZ\ +hNmBINio2KzZhNivINij2LLYsdmCIArQkiDRh9Cw0YnQsNGFINGO0LPQsCDQttC40Lsg0LHRiyDR\ +htC40YLRgNGD0YE/INCU0LAsINC90L4g0YTQsNC70YzRiNC40LLRi9C5INGN0LrQt9C10LzQv9C7\ +0Y/RgCEKzqTOrM+HzrnPg8+EzrcgzrHOu8+Oz4DOt86+IM6yzrHPhs6uz4Igz4jOt868zq3Ovc63\ +IM6zzrcsIM60z4HOsc+DzrrOtc67zq/Ots61zrkgz4XPgM6tz4Egzr3Pic64z4HOv8+NIM66z4XO\ +vc+Mz4IKVmljdG9yIGphZ3QgenfDtmxmIEJveGvDpG1wZmVyIHF1ZXIgw7xiZXIgZGVuIGdyb8Of\ +ZW4gU3lsdGVyIERlaWNoCuimlumHjueEoemZkOW7o++8jOeql+WkluacieiXjeWkqQoKAA=="; + +const char asciiEncodedIso1[] = + "ISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ\ +WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fgA="; + +const char asciiEncodedUtf32[] = + "IQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAv\ +AAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0A\ +AAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAA\ +AEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAA\ +WgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABo\ +AAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYA\ +AAB3AAAAeAAAAHkAAAB6AAAAewAAAHwAAAB9AAAAfgAAAAAAAAA="; + +/* +Name: String_ConverterFromASCII +Description: tests construction of string from ascii data +Expected: data stored in buffer should match expected +*/ +RUNNER_TEST(String_ConverterFromASCII) +{ + char* inStr = NULL; + int inSize = wbxml_base64_decode(asciiEncodedIso1, &inStr); + RUNNER_ASSERT(inSize > 0); + RUNNER_ASSERT(NULL != inStr); + inStr[inSize] = '\0'; + { + DPL::String asciiString = DPL::FromASCIIString(inStr); + + std::string result = DPL::ToUTF8String(asciiString); + + RUNNER_ASSERT(strlen(inStr) == result.size()); + + RUNNER_ASSERT(0 == memcmp(inStr, result.c_str(), result.size())); + } + + free(inStr); +} + +/* +Name: String_ConverterFromUTF8 +Description: tests construction of string from UTF-8 data +Expected: data stored in buffer should match expected +*/ +RUNNER_TEST(String_ConverterFromUTF8) +{ + char* inStr = NULL; + int inSize = wbxml_base64_decode(asciiEncodedIso1, &inStr); + RUNNER_ASSERT(inSize > 0); + RUNNER_ASSERT(NULL != inStr); + { + DPL::String asciiString = DPL::FromUTF8String(inStr); + + std::string result = DPL::ToUTF8String(asciiString); + + RUNNER_ASSERT(strlen(inStr) == result.size()); + + RUNNER_ASSERT(0 == memcmp(inStr, result.c_str(), result.size())); + } + + free(inStr); +} + +/* +Name: String_ConverterFromUTF32 +Description: tests construction of string from UTF-32 data +Expected: data stored in buffer should match expected +*/ +RUNNER_TEST(String_ConverterFromUTF32) +{ + wchar_t* inStr = NULL; + int inSize = + wbxml_base64_decode(utf32Encoded, reinterpret_cast(&inStr)); + RUNNER_ASSERT(inSize > 0); + RUNNER_ASSERT(NULL != inStr); + char* outStr = NULL; + int outSize = wbxml_base64_decode(utf8Encoded, &outStr); + RUNNER_ASSERT(outSize > 0); + RUNNER_ASSERT(NULL != outStr); + outStr[outSize] = '\0'; + { + DPL::String utfString = DPL::FromUTF32String(inStr); + std::string result = DPL::ToUTF8String(utfString); + + RUNNER_ASSERT(strlen(outStr) == result.size()); + RUNNER_ASSERT(0 == memcmp(outStr, result.c_str(), result.size())); + + RUNNER_ASSERT(inSize / sizeof(wchar_t) - 1 == utfString.size()); + RUNNER_ASSERT(0 == + memcmp(inStr, &(utfString[0]), utfString.size() * + sizeof(wchar_t))); + } + + free(inStr); +} + +template +void String_TokenizeReal(const DelimiterType& delimiter) +{ + DPL::String str(L".##..abc.#."); + std::vector tokens; + DPL::Tokenize(str, delimiter, std::back_inserter(tokens)); + + std::vector expectedTokens; + for (int i = 0; i < 5; i++) { + expectedTokens.push_back(L""); + } + expectedTokens.push_back(L"abc"); + for (int i = 0; i < 3; i++) { + expectedTokens.push_back(L""); + } + + RUNNER_ASSERT(expectedTokens == tokens); + tokens.clear(); + expectedTokens.clear(); + + DPL::Tokenize(str, delimiter, std::back_inserter(tokens), true); + expectedTokens.push_back(L"abc"); + RUNNER_ASSERT(expectedTokens == tokens); +} + +/* +Name: String_Tokenize +Description: tests of string splitting +Expected: returned substring should match expected values +*/ +RUNNER_TEST(String_Tokenize) +{ + String_TokenizeReal(L"#."); + String_TokenizeReal(L".#"); + String_TokenizeReal(L".....####.###.."); + String_TokenizeReal(DPL::String(L".#")); + + std::vector tokens; + DPL::Tokenize(std::string("abc.def"), '.', std::back_inserter(tokens)); + std::vector expectedTokens; + expectedTokens.push_back("abc"); + expectedTokens.push_back("def"); + + RUNNER_ASSERT(tokens == expectedTokens); +} + +template +void TestInStreams( + std::basic_string argumentInString, + std::basic_string argumentResultString) +{ + typedef std::basic_string + String; + std::basic_istringstream + istream(argumentInString); + int intValue = 0; + double doubleValue = 0.0; + float floatValue = 0.0; + String stringValue; + + istream >> intValue; + RUNNER_ASSERT(!istream.fail()); + istream >> doubleValue; + RUNNER_ASSERT(!istream.fail()); + istream >> floatValue; + RUNNER_ASSERT(!istream.fail()); + istream >> stringValue; + RUNNER_ASSERT(!istream.fail()); + + RUNNER_ASSERT(1 == intValue); + RUNNER_ASSERT(fabs(1.1f - doubleValue) < 0.00001); + RUNNER_ASSERT(fabs(1.1f - floatValue) < 0.00001); + RUNNER_ASSERT(argumentResultString == stringValue); +} + +template +void TestOutStreams( + std::basic_string argumentInString, + std::basic_string argumentResultString) +{ + typedef std::basic_string + String; + + std::basic_ostringstream + ostream; + + int intValue = 1; + double doubleValue = 1.1; + float floatValue = 1.1f; + String stringValue = argumentInString; + + ostream << intValue; + RUNNER_ASSERT(!ostream.fail()); + ostream << doubleValue; + RUNNER_ASSERT(!ostream.fail()); + ostream << floatValue; + RUNNER_ASSERT(!ostream.fail()); + ostream << stringValue; + RUNNER_ASSERT(!ostream.fail()); + + RUNNER_ASSERT(ostream.str() == argumentResultString); +} + +/* +Name: String_Streams +Description: tests of input/output stream +Expected: returned substrign should match expected values +*/ +RUNNER_TEST(String_Streams) +{ + TestInStreams >("1 1.1 1.1 test", "test"); + TestInStreams >(L"1 1.1 1.1 test", L"test"); + TestInStreams(L"1 1.1 1.1 test", L"test"); + TestOutStreams >("test", "11.11.1test"); + TestOutStreams >(L"test", L"11.11.1test"); + TestOutStreams(L"test", L"11.11.1test"); +} + +/* +Name: String_CompareCaseSensitive +Description: tests case sensitive comparision +Expected: strings should be equal +*/ +RUNNER_TEST(String_CompareCaseSensitive) +{ + RUNNER_ASSERT( + DPL::StringCompare( + DPL::FromUTF32String(L"Ala Makota ma żołądkówkę"), + DPL::FromUTF32String(L"Ala Makota ma żołądkówkę")) == 0); +} + +/* +Name: String_CompareCaseInsensitive +Description: tests case insensitive comparision +Expected: strings should be equal +*/ +RUNNER_TEST(String_CompareCaseInsensitive) +{ + RUNNER_ASSERT( + DPL::StringCompare( + DPL::FromUTF32String(L"Ala Makota ma żołądkówkę"), + DPL::FromUTF32String(L"AlA MakOTA ma Å»oŁąDKÓwkę"), + true) == 0); +} + +/* +Name: String_Join +Description: tests joining strings algorithm +Expected: join should take place correctly +*/ +RUNNER_TEST(String_Join) +{ + std::vector strings; + RUNNER_ASSERT(DPL::Join(strings.begin(), strings.end(), "/") == ""); + strings.push_back("one"); + RUNNER_ASSERT(DPL::Join(strings.begin(), strings.end(), "/") == "one"); + strings.push_back("two"); + RUNNER_ASSERT(DPL::Join(strings.begin(), strings.end(), "/") == "one/two"); + strings.push_back("three"); + RUNNER_ASSERT(DPL::Join(strings.begin(), strings.end(), "/") == "one/two/three"); + strings.push_back("four"); + RUNNER_ASSERT(DPL::Join(strings.begin(), strings.end(), "/") == "one/two/three/four"); + RUNNER_ASSERT(DPL::Join(++strings.begin(), --strings.end(), "/") == "two/three"); + + RUNNER_ASSERT(DPL::Join(strings.begin(), strings.end(), "+") == "one+two+three+four"); + RUNNER_ASSERT(DPL::Join(strings.begin(), strings.end(), "delim") == "onedelimtwodelimthreedelimfour"); +} + +/* +Name: String_Trim +Description: tests trimming strings +Expected: trim strings +*/ +RUNNER_TEST(String_Trim) +{ + const std::string str = " value "; + + std::string test1 = str; + DPL::Trim(test1, " "); + RUNNER_ASSERT_MSG(test1 == "value", "Full trim failed"); + + std::string test2 = str; + DPL::TrimLeft(test2, " "); + RUNNER_ASSERT_MSG(test2 == "value ", "Left trim failed"); + + std::string test3 = str; + DPL::TrimRight(test3, " "); + RUNNER_ASSERT_MSG(test3 == " value", "Right trim failed"); + + std::string test4 = str; + DPL::Trim(test4, " ea"); + RUNNER_ASSERT_MSG(test4 == "valu", "Trim failed"); + + std::string test5 = str; + DPL::TrimRight(test5, " v"); + RUNNER_ASSERT_MSG(test5 == " value", "Trim failed"); + + DPL::String test6 = L"--aabbaabb--aa--bb--"; + DPL::Trim(test6, L"-a"); + RUNNER_ASSERT_MSG(test6 == L"bbaabb--aa--bb", "Trim failed"); + + DPL::String test7 = L"--aabbaabb--aa--bb--"; + DPL::Trim(test7, L"-ab"); + RUNNER_ASSERT_MSG(test7 == L"", "Trim to empty failed"); +} diff --git a/tests/core/test_thread.cpp b/tests/core/test_thread.cpp new file mode 100644 index 0000000..8eec1f0 --- /dev/null +++ b/tests/core/test_thread.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_thread.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of thread tests + */ +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +bool g_wasFooDeleted; + +class Foo +{ + public: + int id; + Foo(int i = 0) : id(i) + { + LogDebug("Foo: ctor: " << id); + } + + ~Foo() + { + LogDebug("Foo: dtor: " << id); + g_wasFooDeleted = true; + } + + void Bar() + { + LogDebug("Foo: bar"); + } +}; + +typedef DPL::ThreadLocalVariable TlsFoo; +TlsFoo g_foo; + +class FooThread : + public DPL::Thread +{ + protected: + virtual int ThreadEntry() + { + LogDebug("In thread"); + + RUNNER_ASSERT(!g_foo); + RUNNER_ASSERT(g_foo.IsNull()); + + g_foo = Foo(); + g_foo->Bar(); + + return 0; + } +}; + +/* +Name: Thread_ThreadLocalVariable_FooDeletion +Description: tests local thread variable pattern +Expected: local thread variables should not be affected by other threads +*/ +RUNNER_TEST(Thread_ThreadLocalVariable_FooDeletion) +{ + static TlsFoo staticFooForMain; + staticFooForMain = Foo(1); + + TlsFoo fooForMain; + fooForMain = Foo(2); + + RUNNER_ASSERT(!g_foo); + RUNNER_ASSERT(g_foo.IsNull()); + + g_wasFooDeleted = false; + + FooThread thread1; + thread1.Run(); + thread1.Quit(); + + RUNNER_ASSERT(!g_foo); + RUNNER_ASSERT(g_foo.IsNull()); + + RUNNER_ASSERT(g_wasFooDeleted == true); + + FooThread thread2; + thread2.Run(); + thread2.Quit(); + + RUNNER_ASSERT(!g_foo); + RUNNER_ASSERT(g_foo.IsNull()); +} diff --git a/tests/core/test_type_list.cpp b/tests/core/test_type_list.cpp new file mode 100644 index 0000000..b3e6285 --- /dev/null +++ b/tests/core/test_type_list.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file test_type_list.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 0.1 + * @brief + */ + +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: TypeList_TypeCount +Description: tests size of typelist idiom +Expected: size should match +*/ +RUNNER_TEST(TypeList_TypeCount) +{ + typedef DPL::TypeListDecl::Type TestTypeList1; + typedef DPL::TypeListDecl::Type TestTypeList2; + typedef DPL::TypeListDecl<>::Type TestTypeList3; + typedef DPL::TypeList TestTypeList4; + + RUNNER_ASSERT(TestTypeList1::Size == 3); + RUNNER_ASSERT(TestTypeList2::Size == 1); + RUNNER_ASSERT(TestTypeList3::Size == 0); + RUNNER_ASSERT(TestTypeList4::Size == 4); + + RUNNER_ASSERT(TestTypeList4::Tail::Tail::Size == 2); +} diff --git a/tests/core/test_waitable_handle_watch.cpp b/tests/core/test_waitable_handle_watch.cpp new file mode 100644 index 0000000..a456d3c --- /dev/null +++ b/tests/core/test_waitable_handle_watch.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_waitable_handle_watch.cpp + * @author Slawomir Pajak (s.pajak@partner.samsung.com) + * @version 1.0 + * @brief This file is the implementation file of WaitableHandleWatchSupport tests + */ +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +using namespace DPL; + +class TestListener: public WaitableHandleWatchSupport::WaitableHandleListener { +public: + int listenerHitCount; + TestListener() : + listenerHitCount(0) + { + } + virtual ~TestListener() + { + } + virtual void OnWaitableHandleEvent(WaitableHandle /*waitableHandle*/, WaitMode::Type /*mode*/) + { + listenerHitCount++; + } +}; + +class TestWaitableHandleWatch: public WaitableHandleWatchSupport { +public: + virtual ~TestWaitableHandleWatch() + { + } + + virtual Thread *GetInvokerThread() + { + return Thread::GetCurrentThread(); + } + + // Invoke direct invoker + virtual void HandleDirectInvoker() + { + + } + + using WaitableHandleWatchSupport::HandleWatcher; +}; + +/* + Name: WaitableHandleWatchSupport_SingleListener + Description: tests WaitableHandleWatchSupport simple case + Expected: listener is notified + */ +RUNNER_TEST(WaitableHandleWatchSupport_SingleListener) +{ + TestWaitableHandleWatch handleWatch; + WaitableHandle handle = 1; + TestListener listener; + handleWatch.AddWaitableHandleWatch(&listener, handle, WaitMode::Read); + + handleWatch.HandleWatcher(handle, WaitMode::Read); + RUNNER_ASSERT(1 == listener.listenerHitCount); +} + +/* + Name: WaitableHandleWatchSupport_MultipleListener + Description: tests WaitableHandleWatchSupport multiple listeners + Expected: listeners are notified correctly + */ +RUNNER_TEST(WaitableHandleWatchSupport_MultipleListener) +{ + TestWaitableHandleWatch handleWatch; + WaitableHandle handle = 1; + TestListener listenerR1; + TestListener listenerR2; + TestListener listenerW1; + TestListener listenerW2; + handleWatch.AddWaitableHandleWatch(&listenerR1, handle, WaitMode::Read); + handleWatch.AddWaitableHandleWatch(&listenerR2, handle, WaitMode::Read); + handleWatch.AddWaitableHandleWatch(&listenerW1, handle, WaitMode::Write); + handleWatch.AddWaitableHandleWatch(&listenerW2, handle, WaitMode::Write); + + handleWatch.HandleWatcher(handle, WaitMode::Read); + RUNNER_ASSERT(1 == listenerR1.listenerHitCount); + RUNNER_ASSERT(1 == listenerR2.listenerHitCount); + RUNNER_ASSERT(0 == listenerW1.listenerHitCount); + RUNNER_ASSERT(0 == listenerW2.listenerHitCount); + + handleWatch.HandleWatcher(handle, WaitMode::Write); + RUNNER_ASSERT(1 == listenerR1.listenerHitCount); + RUNNER_ASSERT(1 == listenerR2.listenerHitCount); + RUNNER_ASSERT(1 == listenerW1.listenerHitCount); + RUNNER_ASSERT(1 == listenerW2.listenerHitCount); +} + +/* + Name: WaitableHandleWatchSupport_MultipleHandle + Description: tests WaitableHandleWatchSupport multiple handles + Expected: listeners are notified correctly + */ +RUNNER_TEST(WaitableHandleWatchSupport_MultipleHandle) +{ + TestWaitableHandleWatch handleWatch; + TestListener listener; + WaitableHandle handle1 = 1; + WaitableHandle handle2 = 2; + handleWatch.AddWaitableHandleWatch(&listener, handle1, WaitMode::Read); + handleWatch.AddWaitableHandleWatch(&listener, handle2, WaitMode::Read); + handleWatch.AddWaitableHandleWatch(&listener, handle1, WaitMode::Write); + handleWatch.AddWaitableHandleWatch(&listener, handle2, WaitMode::Write); + + handleWatch.HandleWatcher(handle1, WaitMode::Read); + RUNNER_ASSERT(1 == listener.listenerHitCount); + + handleWatch.HandleWatcher(handle1, WaitMode::Write); + RUNNER_ASSERT(2 == listener.listenerHitCount); + + handleWatch.HandleWatcher(handle2, WaitMode::Read); + RUNNER_ASSERT(3 == listener.listenerHitCount); + + handleWatch.HandleWatcher(handle2, WaitMode::Write); + RUNNER_ASSERT(4 == listener.listenerHitCount); +} + +/* + Name: WaitableHandleWatchSupport_AddRemoveListener + Description: tests WaitableHandleWatchSupport removing listeners function + Expected: remaining listeners are notified correctly, removed are not notified + */ +RUNNER_TEST(WaitableHandleWatchSupport_AddRemoveListener) +{ + TestWaitableHandleWatch handleWatch; + TestListener listener; + WaitableHandle handle1 = 1; + WaitableHandle handle2 = 2; + handleWatch.AddWaitableHandleWatch(&listener, handle1, WaitMode::Read); + handleWatch.AddWaitableHandleWatch(&listener, handle2, WaitMode::Read); + handleWatch.AddWaitableHandleWatch(&listener, handle1, WaitMode::Write); + handleWatch.AddWaitableHandleWatch(&listener, handle2, WaitMode::Write); + + handleWatch.HandleWatcher(handle1, WaitMode::Read); + RUNNER_ASSERT(1 == listener.listenerHitCount); + + handleWatch.RemoveWaitableHandleWatch(&listener, handle1, WaitMode::Write); + handleWatch.HandleWatcher(handle1, WaitMode::Write); + RUNNER_ASSERT(1 == listener.listenerHitCount); + + handleWatch.RemoveWaitableHandleWatch(&listener, handle2, WaitMode::Read); + handleWatch.HandleWatcher(handle2, WaitMode::Read); + RUNNER_ASSERT(1 == listener.listenerHitCount); + + handleWatch.HandleWatcher(handle2, WaitMode::Write); + RUNNER_ASSERT(2 == listener.listenerHitCount); +} diff --git a/tests/core/test_zip_input.cpp b/tests/core/test_zip_input.cpp new file mode 100644 index 0000000..c62accb --- /dev/null +++ b/tests/core/test_zip_input.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_zip_input.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of zip input tests + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +const char* PATH_NO_FILE = "/opt/share/wrt/wrt-commons/tests/core/no_such_file"; +const char* PATH_ARCHIVE = "/opt/share/wrt/wrt-commons/tests/core/sample.zip"; +const char* ARCHIVED_FILE = "sample.txt"; +} + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ZipInput_OpenFailed +Description: tests opening non existing file +Expected: exception throw +*/ +RUNNER_TEST(ZipInput_OpenFailed) +{ + bool opened = true; + + Try + { + DPL::ZipInput zip(PATH_NO_FILE); + (void)zip; + } + Catch(DPL::ZipInput::Exception::OpenFailed) + { + opened = false; + } + + RUNNER_ASSERT(opened == false); +} + +/* +Name: ZipInput_OpenFile +Description: tests opening existing file +Expected: zip stats should mkatch expected +*/ +RUNNER_TEST(ZipInput_OpenFile) +{ + DPL::ZipInput zip(PATH_ARCHIVE); + + FOREACH(iter, zip) + { + LogDebug("---------"); + LogDebug("FileInfo: "); +#define FIELD(X) LogDebug(#X ": " << iter->X) + FIELD(name); + FIELD(comment); + FIELD(compressedSize); + FIELD(uncompressedSize); +#undef FIELD + } +} + +/* +Name: ZipInput_UnzipSingleFile +Description: tests opening existing file and unzipping single file +Expected: right content +*/ +RUNNER_TEST(ZipInput_UnzipSingleFile) +{ + DPL::ZipInput zip(PATH_ARCHIVE); + DPL::ZipInput::File *file = zip.OpenFile(ARCHIVED_FILE); + DPL::AbstractWaitableInputAdapter fileAdapter(file); + DPL::BinaryQueue buffer; + DPL::AbstractWaitableOutputAdapter bufferAdapter(&buffer); + + DPL::Copy(&fileAdapter, &bufferAdapter); + + DPL::ScopedArray data(new char[buffer.Size() + 1]); + buffer.Flatten(data.Get(), buffer.Size()); + data[buffer.Size()] = '\0'; + + RUNNER_ASSERT(std::string(data.Get()) == "test"); +} diff --git a/tests/dao/CMakeLists.txt b/tests/dao/CMakeLists.txt new file mode 100644 index 0000000..88c0e24 --- /dev/null +++ b/tests/dao/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Pawel Sikorski (p.sikorski@samsung.com) +# @version 1.0 +# @brief +# + +# common part +FILE(GLOB DAO_TESTS_SOURCES "${PROJECT_SOURCE_DIR}/tests/dao/*DAO.cpp") + +# target wrt-tests-dao +SET(TARGET_DAO_TEST "wrt-commons-tests-dao") +WRT_TEST_INCLUDE_DIRECTORIES(${TARGET_DAO_TEST} ${PROJECT_SOURCE_DIR}/modules/support/ ${PROJECT_SOURCE_DIR}/modules/widget_interface_dao/include/) +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_DAO_TEST} ${TARGET_WRT_DAO_RW_LIB} ${TARGET_CUSTOM_HANDLER_DAO_RW_LIB} + ${TARGET_CERTIFICATE_DAO_LIB} ${TARGET_SECURITY_ORIGIN_DAO_LIB} ${TARGET_WIDGET_INTERFACE_DAO_LIB}) + +WRT_TEST_BUILD(${TARGET_DAO_TEST} ${DAO_TESTS_SOURCES} tests_dao.cpp) +WRT_TEST_INSTALL(${TARGET_DAO_TEST}) + +# common installed files +INSTALL(PROGRAMS + ${PROJECT_SOURCE_DIR}/tests/dao/wrt_dao_tests_prepare_db.sh + DESTINATION bin + ) diff --git a/tests/dao/README b/tests/dao/README new file mode 100644 index 0000000..6c60a17 --- /dev/null +++ b/tests/dao/README @@ -0,0 +1,11 @@ +Wrt DAO +System tests. Tests database access layer: widgets information database, global configuration, plugins. +Binary file: wrt-tests-dao. Uses our test framework. Allows to use different types of output. Text output shows results on console - green passed. +To run: +1. Install wrt-extra on target +2. Run wrt-tests-dao --output=text + +Automatic: YES +Included in Daily Build: YES (http://build01.sprc.samsung.pl/browse/LINUXNGWAP-INT) +Included in Gerrit Builds: YES (http://build01.sprc.samsung.pl/browse/LINUXNGWAP-GERRIT) +Number of test cases: 45 \ No newline at end of file diff --git a/tests/dao/TestCases_CertificateDAO.cpp b/tests/dao/TestCases_CertificateDAO.cpp new file mode 100644 index 0000000..729b4a3 --- /dev/null +++ b/tests/dao/TestCases_CertificateDAO.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_CertificateDAO.cpp + * @author Slawomir Pajak (s.pajak@partner.samsung.com) + * @version 1.0 + * @brief This file contains tests for certificate dao class. + */ + +#include +#include + +RUNNER_TEST_GROUP_INIT(DAO) + +using namespace CertificateDB; + +namespace { + +class CertificateDAOWrapper { +public: + static CertificateDAO* getCertificateDAO() + { + static CertificateDAOPtr certificateDAO( + new CertificateDB::CertificateDAO(DPL::FromASCIIString("testWidget123"))); + return certificateDAO.get(); + } +}; +} + +/** + * Name: certificate_dao_save_remove_by_certdata + * Description: Tests saves certificateDao object, reads it, and removes it at the end + * using certificate data value. + * Expected: All operations should succeed. + */ +RUNNER_TEST(certificate_dao_save_remove_by_certdata) +{ + CertificateDAO* certificateDAO = CertificateDAOWrapper::getCertificateDAO(); + + CertificateDataList dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "CertificateDataList should be empty"); + + CertificateData certData(DPL::FromASCIIString("sampleCetificate")); + certificateDAO->setCertificateData(certData, RESULT_ALLOW_ONCE); + + dataList = certificateDAO->getCertificateDataList(); + + RUNNER_ASSERT_MSG(dataList.size() == 1, "CertificateDataList should not be empty"); + RUNNER_ASSERT_MSG((*dataList.begin())->certificate == DPL::FromASCIIString("sampleCetificate"), + "Wrong element in table"); + + RUNNER_ASSERT_MSG(certificateDAO->getResult(**dataList.begin()) == RESULT_ALLOW_ONCE, "Wrong result"); + + certificateDAO->removeCertificateData(certData); + + dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "CertificateDataList should be empty"); + +} + +/** + * Name: certificate_dao_save_remove_by_result + * Description: Tests saves certificateDao object, reads it, and removes it at the end + * using result value. + * Expected: All operations should succeed. + */ +RUNNER_TEST(certificate_dao_save_remove_by_result) +{ + CertificateDAO* certificateDAO = CertificateDAOWrapper::getCertificateDAO(); + + CertificateDataList dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "CertificateDataList should be empty"); + + CertificateData certData(DPL::FromASCIIString("sampleCetificate1")); + certificateDAO->setCertificateData(certData, RESULT_ALLOW_ALWAYS); + + CertificateData certData2(DPL::FromASCIIString("sampleCetificate2")); + certificateDAO->setCertificateData(certData2, RESULT_ALLOW_ALWAYS); + + dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.size() == 2, "CertificateDataList should not be empty"); + + certificateDAO->removeCertificateData(RESULT_ALLOW_ALWAYS); + dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "CertificateDataList should be empty"); +} + +/** + * Name: certificate_dao_update + * Description: Tests update of certificateDao object. + * Expected: All operations should succeed. + */ +RUNNER_TEST(certificate_dao_update) +{ + CertificateDAO* certificateDAO = CertificateDAOWrapper::getCertificateDAO(); + + CertificateDataList dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "CertificateDataList should be empty"); + + CertificateData certData(DPL::FromASCIIString("sampleCetificate3")); + certificateDAO->setCertificateData(certData, RESULT_ALLOW_ONCE); + + dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.size() == 1, "CertificateDataList should not be empty"); + RUNNER_ASSERT_MSG((*dataList.begin())->certificate == DPL::FromASCIIString("sampleCetificate3"), + "Wrong element in table"); + RUNNER_ASSERT_MSG(certificateDAO->getResult(**dataList.begin()) == RESULT_ALLOW_ONCE, "Wrong result"); + + certificateDAO->setCertificateData(certData, RESULT_DENY_ALWAYS); + dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.size() == 1, "CertificateDataList should not be empty"); + RUNNER_ASSERT_MSG((*dataList.begin())->certificate == DPL::FromASCIIString("sampleCetificate3"), + "Wrong element in table"); + RUNNER_ASSERT_MSG(certificateDAO->getResult(**dataList.begin()) == RESULT_DENY_ALWAYS, "Wrong result"); + + certificateDAO->removeCertificateData(certData); + dataList = certificateDAO->getCertificateDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "CertificateDataList should be empty"); +} + +/** + * Name: certificate_dao_equality_operator + * Description: Tests CertificateData equality operators. + * Expected: All operations should succeed. + */ +RUNNER_TEST(certificate_dao_equality_operator) +{ + CertificateData certData1(DPL::FromASCIIString("sampleCetificate1")); + CertificateData certData2(DPL::FromASCIIString("sampleCetificate1")); + CertificateData certData3(DPL::FromASCIIString("sampleCetificate2")); + + RUNNER_ASSERT_MSG(certData1 == certData2, "Object should be equal"); + RUNNER_ASSERT_MSG(certData1 != certData3, "Object should not be equal"); + RUNNER_ASSERT_MSG(certData2 != certData3, "Object should not be equal"); +} + diff --git a/tests/dao/TestCases_CustomHandlerDAO.cpp b/tests/dao/TestCases_CustomHandlerDAO.cpp new file mode 100644 index 0000000..d606b03 --- /dev/null +++ b/tests/dao/TestCases_CustomHandlerDAO.cpp @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_CustomHandlerDAO.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief This file contains tests for custom handler dao class. + */ + +#include +#include +#include +#include + +using namespace CustomHandlerDB; + +RUNNER_TEST_GROUP_INIT(DAO) + +namespace { +const DPL::String P_TARGET(L"p_target"); +const DPL::String P_BASE_URL(L"p_base_url"); +const DPL::String P_URL(L"p_url"); +const DPL::String P_TITLE(L"p_title"); + +const DPL::String C_TARGET(L"c_target"); +const DPL::String C_BASE_URL(L"c_base_url"); +const DPL::String C_URL(L"c_url"); +const DPL::String C_TITLE(L"c_title"); + +void checkHandlersExistence(CustomHandlerDAOReadOnly& dao, + bool protocol, + bool content) +{ + CustomHandlerDB::CustomHandlerPtr handler; + handler = dao.getProtocolHandler(P_TARGET, P_URL); + RUNNER_ASSERT_MSG((!!handler) == protocol, "Protocol handler check"); + handler = dao.getContentHandler(C_TARGET, C_URL); + RUNNER_ASSERT_MSG((!!handler) == content, "Content handler check"); +} +} // namespace + +RUNNER_TEST(custom_handler_empty_db_read) +{ + CustomHandlerDAOReadOnly dao(DPL::String(L"test")); +} + +RUNNER_TEST(custom_handlers) +{ + CustomHandlerDAOReadOnly dao_ro(L"test"); + CustomHandlerDAO dao_rw(L"test"); + + CustomHandlerDB::CustomHandlerPtr handler; + CustomHandlerDB::CustomHandler p_handler; + p_handler.target = P_TARGET; + p_handler.base_url = P_BASE_URL; + p_handler.url = P_URL; + p_handler.title = P_TITLE; + p_handler.user_decision = Agreed; + + // initial check + checkHandlersExistence(dao_ro, false, false); + + // Protocol handler registration + dao_rw.registerProtocolHandler(p_handler); + checkHandlersExistence(dao_ro, true, false); + + handler = dao_ro.getProtocolHandler(P_TARGET, P_URL); + RUNNER_ASSERT(handler); + RUNNER_ASSERT(handler->target == P_TARGET); + RUNNER_ASSERT(handler->base_url == P_BASE_URL); + RUNNER_ASSERT(handler->url == P_URL); + RUNNER_ASSERT(handler->title == P_TITLE); + RUNNER_ASSERT(handler->user_decision == Agreed); + + // Content handler registration + CustomHandlerDB::CustomHandler c_handler; + c_handler.target = C_TARGET; + c_handler.base_url = C_BASE_URL; + c_handler.url = C_URL; + c_handler.title = C_TITLE; + c_handler.user_decision = DeclinedPermanently; + + dao_rw.registerContentHandler(c_handler); + checkHandlersExistence(dao_ro, true, true); + handler = dao_ro.getContentHandler(C_TARGET, C_URL); + + RUNNER_ASSERT(handler); + RUNNER_ASSERT(handler->target == C_TARGET); + RUNNER_ASSERT(handler->base_url == C_BASE_URL); + RUNNER_ASSERT(handler->url == C_URL); + RUNNER_ASSERT(handler->title == C_TITLE); + RUNNER_ASSERT(handler->user_decision == DeclinedPermanently); + + // Handler unregistration + dao_rw.unregisterProtocolHandler(P_TARGET, P_URL); + checkHandlersExistence(dao_ro, false, true); + + // Nonexistent unregistration + dao_rw.unregisterContentHandler(L"blah", L"blah"); + checkHandlersExistence(dao_ro, false, true); + + // Cleanup + dao_rw.unregisterContentHandler(C_TARGET, C_URL); + checkHandlersExistence(dao_ro, false, false); +} + +RUNNER_TEST(custom_handler_unregister) +{ + CustomHandlerDAOReadOnly dao_ro(L"test"); + CustomHandlerDAO dao_rw(L"test"); + + // initial check + checkHandlersExistence(dao_ro, false, false); + + CustomHandlerDB::CustomHandler p_handler; + p_handler.target = P_TARGET; + p_handler.base_url = P_BASE_URL; + p_handler.url = P_URL; + p_handler.title = P_TITLE; + p_handler.user_decision = Agreed; + + // Protocol handler registration + dao_rw.registerProtocolHandler(p_handler); + checkHandlersExistence(dao_ro, true, false); + + // Content handler registration + CustomHandlerDB::CustomHandler c_handler; + c_handler.target = C_TARGET; + c_handler.base_url = C_BASE_URL; + c_handler.url = C_URL; + c_handler.title = C_TITLE; + c_handler.user_decision = DeclinedPermanently; + + dao_rw.registerContentHandler(c_handler); + checkHandlersExistence(dao_ro, true, true); + + // Handler unregistration + dao_rw.unregisterProtocolHandler(P_TARGET, P_URL, P_BASE_URL); + checkHandlersExistence(dao_ro, false, true); + + // Cleanup + dao_rw.unregisterContentHandler(C_TARGET, C_URL, C_BASE_URL); + checkHandlersExistence(dao_ro, false, false); +} + +RUNNER_TEST(custom_handler_update) +{ + CustomHandlerDAOReadOnly dao_ro(L"test"); + CustomHandlerDAO dao_rw(L"test"); + + // initial check + checkHandlersExistence(dao_ro, false, false); + + CustomHandlerDB::CustomHandler p_handler; + p_handler.target = P_TARGET; + p_handler.base_url = P_BASE_URL; + p_handler.url = P_URL; + p_handler.title = P_TITLE; + p_handler.user_decision = Agreed; + + // Protocol handler registration + dao_rw.registerProtocolHandler(p_handler); + checkHandlersExistence(dao_ro, true, false); + + // Content handler registration + CustomHandlerDB::CustomHandlerPtr handler; + CustomHandlerDB::CustomHandler c_handler; + c_handler.target = C_TARGET; + c_handler.base_url = C_BASE_URL; + c_handler.url = C_URL; + c_handler.title = C_TITLE; + c_handler.user_decision = DeclinedPermanently; + + dao_rw.registerContentHandler(c_handler); + checkHandlersExistence(dao_ro, true, true); + + p_handler.title = L"newTitle"; + p_handler.user_decision = AgreedPermanently; + + // Protocol handler update + dao_rw.registerProtocolHandler(p_handler); + + handler = dao_ro.getProtocolHandler(P_TARGET, P_URL); + RUNNER_ASSERT(handler); + RUNNER_ASSERT(handler->target == P_TARGET); + RUNNER_ASSERT(handler->base_url == P_BASE_URL); + RUNNER_ASSERT(handler->url == P_URL); + RUNNER_ASSERT(handler->title == L"newTitle"); + RUNNER_ASSERT(handler->user_decision == AgreedPermanently); + + c_handler.title = L"newTitle2"; + c_handler.user_decision = Agreed; + // Content handler update + dao_rw.registerContentHandler(c_handler); + + handler = dao_ro.getContentHandler(C_TARGET, C_URL); + + RUNNER_ASSERT(handler); + RUNNER_ASSERT(handler->target == C_TARGET); + RUNNER_ASSERT(handler->base_url == C_BASE_URL); + RUNNER_ASSERT(handler->url == C_URL); + RUNNER_ASSERT(handler->title == L"newTitle2"); + RUNNER_ASSERT(handler->user_decision == Agreed); + + // Handler unregistration + dao_rw.removeWidgetProtocolHandlers(); + checkHandlersExistence(dao_ro, false, true); + + // Cleanup + dao_rw.removeWidgetContentHandlers(); + checkHandlersExistence(dao_ro, false, false); +} + +RUNNER_TEST(custom_handler_get_active_protocol) +{ + CustomHandlerDAOReadOnly dao_ro(L"test"); + CustomHandlerDAO dao_rw(L"test"); + + CustomHandlerDB::CustomHandler p_handler; + p_handler.target = P_TARGET; + p_handler.base_url = P_BASE_URL; + p_handler.url = L"url1"; + p_handler.title = L"title1"; + p_handler.user_decision = DeclinedPermanently; + // Protocol handler registration + dao_rw.registerProtocolHandler(p_handler); + + CustomHandlerDB::CustomHandlerPtr handler = dao_ro.getActivProtocolHandler(P_TARGET); + RUNNER_ASSERT(!handler); + + CustomHandlerDB::CustomHandler p_handler2; + p_handler2.target = P_TARGET; + p_handler2.base_url = P_BASE_URL; + p_handler2.url = L"url2"; + p_handler2.title = L"title2"; + p_handler2.user_decision = AgreedPermanently; + // Protocol handler registration + dao_rw.registerProtocolHandler(p_handler2); + + handler = dao_ro.getActivProtocolHandler(P_TARGET); + RUNNER_ASSERT(handler); + RUNNER_ASSERT(handler->target == P_TARGET); + RUNNER_ASSERT(handler->base_url == P_BASE_URL); + RUNNER_ASSERT(handler->url == L"url2"); + RUNNER_ASSERT(handler->title == L"title2"); + RUNNER_ASSERT(handler->user_decision == AgreedPermanently); + + // Handler unregistration + dao_rw.removeWidgetProtocolHandlers(); +} + +RUNNER_TEST(custom_handler_get_active_content) +{ + CustomHandlerDAOReadOnly dao_ro(L"test"); + CustomHandlerDAO dao_rw(L"test"); + + CustomHandlerDB::CustomHandler c_handler; + c_handler.target = C_TARGET; + c_handler.base_url = C_BASE_URL; + c_handler.url = L"url2"; + c_handler.title = L"title2"; + c_handler.user_decision = DeclinedPermanently; + // Protocol handler registration + dao_rw.registerContentHandler(c_handler); + + CustomHandlerDB::CustomHandlerPtr handler = dao_ro.getActivProtocolHandler(C_TARGET); + RUNNER_ASSERT(!handler); + + CustomHandlerDB::CustomHandler c_handler2; + c_handler2.target = C_TARGET; + c_handler2.base_url = C_BASE_URL; + c_handler2.url = L"url1"; + c_handler2.title = C_TITLE; + c_handler2.user_decision = Agreed; + // Protocol handler registration + dao_rw.registerContentHandler(c_handler2); + + handler = dao_ro.getActivContentHandler(C_TARGET); + RUNNER_ASSERT(handler); + RUNNER_ASSERT(handler->target == C_TARGET); + RUNNER_ASSERT(handler->base_url == C_BASE_URL); + RUNNER_ASSERT(handler->url == L"url1"); + RUNNER_ASSERT(handler->title == C_TITLE); + RUNNER_ASSERT(handler->user_decision == Agreed); + + // Handler unregistration + dao_rw.removeWidgetContentHandlers(); +} diff --git a/tests/dao/TestCases_FeatureDAO.cpp b/tests/dao/TestCases_FeatureDAO.cpp new file mode 100644 index 0000000..f01355c --- /dev/null +++ b/tests/dao/TestCases_FeatureDAO.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_FeatureDAO.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains tests for feature dao class. + */ + +#include +#include +#include +#include +#include + +using namespace WrtDB; + +#define RUNNER_ASSERT_WHAT_EQUALS(in, test) \ + { std::string tmp(in); \ + RUNNER_ASSERT_MSG(tmp == test, "Equals: [" + tmp + "]"); } + +RUNNER_TEST_GROUP_INIT(DAO) + +/* + * Name: feature_dao_test_register_features + * Description: Checks if plugin registeration performs features registration + * and if registration is made properly + * Expected: registrartion should succeed + */ +RUNNER_TEST(feature_dao_test_register_features) +{ + PluginHandle plHandle; + { + std::string libraryPath("nfp1 lib_path"); + std::string libraryName("nfp1"); + + PluginMetafileData pluginData; + pluginData.m_libraryName = libraryName; + + plHandle = PluginDAO::registerPlugin(pluginData, libraryPath); + RUNNER_ASSERT(PluginDAO::isPluginInstalled(libraryName) == true); + + FeatureHandleList old = FeatureDAOReadOnly::GetHandleList(); + PluginMetafileData::Feature f; + f.m_name = std::string("new_f1"); + + FeatureHandle handle = FeatureDAO::RegisterFeature(f, plHandle); + RUNNER_ASSERT_MSG(handle != -1, "Already registered"); + RUNNER_ASSERT_MSG(old.size() < FeatureDAOReadOnly::GetHandleList().size(), + "New feature should be saved"); + + FeatureDAOReadOnly dao(handle); + + RUNNER_ASSERT_WHAT_EQUALS(dao.GetName(), "new_f1"); + plHandle = dao.GetPluginHandle(); + } + + { + FeatureHandleList old = FeatureDAOReadOnly::GetHandleList(); + + PluginMetafileData::Feature f; + f.m_name = std::string("new_f2"); + + FeatureHandle handle = FeatureDAO::RegisterFeature(f, plHandle); + RUNNER_ASSERT_MSG(handle != -1, "Already registered"); + RUNNER_ASSERT_MSG(old.size() < FeatureDAOReadOnly::GetHandleList().size(), + "New feature should be saved"); + + FeatureDAOReadOnly dao(handle); + + RUNNER_ASSERT_MSG(plHandle == dao.GetPluginHandle(), + "New plugin registered (should be old used)"); + + FeatureDAO::UnregisterFeature(handle); + PluginDAO::unregisterPlugin(plHandle); + } +} + +/* + * Name: feature_dao_test_get_feature_handle + * Description: Checks GetFeatureHandleListForPlugin + * Expected: no errors found + * directly + */ +RUNNER_TEST(feature_dao_test_get_feature_handle) +{ + PluginHandleSetPtr plugins = + PluginDAO::getPluginHandleByStatus(PluginDAO::INSTALLATION_COMPLETED); + + RUNNER_ASSERT(plugins->size() == 5); + + FOREACH(it, *plugins) { + FeatureHandleListPtr featureListPtr = + FeatureDAOReadOnly::GetFeatureHandleListForPlugin(*it); + int size = featureListPtr->size(); + + switch(*it) + { + case 1: + RUNNER_ASSERT(size == 1); + break; + case 2: + RUNNER_ASSERT(size == 0); + break; + case 3: + RUNNER_ASSERT(size == 0); + break; + case 4: + RUNNER_ASSERT(size == 3); + break; + case 5: + RUNNER_ASSERT(size == 0); + break; + default: + RUNNER_ASSERT_MSG(false, "Wrong plugin handle"); + break; + } + } +} + +/* + * Name: feature_dao_test_get_device_capability + * Description: Checks GetDeviceCapability + * Expected: no errors found + * directly + */ +RUNNER_TEST(feature_dao_test_get_device_capability) +{ + RUNNER_ASSERT(FeatureDAOReadOnly::GetDeviceCapability(L"feature1").size() == 1); + RUNNER_ASSERT(FeatureDAOReadOnly::GetDeviceCapability(L"feature2").size() == 2); + RUNNER_ASSERT(FeatureDAOReadOnly::GetDeviceCapability(L"feature3").size() == 1); + RUNNER_ASSERT(FeatureDAOReadOnly::GetDeviceCapability(L"feature4").size() == 0); +} + +/* + * Name: feature_dao_test_unregister + * Description: Checks UnregisterFeature + * Expected: no errors found + */ +RUNNER_TEST(feature_dao_test_unregister) +{ + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled("feature5") == false); + unsigned int size = FeatureDAOReadOnly::GetHandleList().size(); + + PluginHandle plHandle; + PluginMetafileData pluginData; + pluginData.m_libraryName = "nfp1 lib_path"; + plHandle = PluginDAO::registerPlugin(pluginData, "lib_path"); + + PluginMetafileData::Feature f0; + f0.m_name = std::string("feature5"); + f0.m_deviceCapabilities.insert("1devicecap"); + f0.m_deviceCapabilities.insert("2devicecap"); + f0.m_deviceCapabilities.insert("3devicecap"); + + FeatureHandle handle0 = FeatureDAO::RegisterFeature(f0, plHandle); + RUNNER_ASSERT_MSG(handle0 != -1, "Already registered"); + + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled(handle0) == true); + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled("feature5") == true); + RUNNER_ASSERT(FeatureDAOReadOnly::GetHandleList().size() == size + 1); + + FeatureDAO::UnregisterFeature(handle0); + + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled(handle0) == false); + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled("feature5") == false); + RUNNER_ASSERT(FeatureDAOReadOnly::GetHandleList().size() == size); + + PluginMetafileData::Feature f1; + f1.m_name = std::string("feature5"); + + FeatureHandle handle1 = FeatureDAO::RegisterFeature(f1, plHandle); + RUNNER_ASSERT_MSG(handle1 != -1, "Already registered"); + + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled(handle1) == true); + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled("feature5") == true); + RUNNER_ASSERT(FeatureDAOReadOnly::GetHandleList().size() == size + 1); + + FeatureDAO::UnregisterFeature(handle1); + + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled(handle1) == false); + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled("feature5") == false); + RUNNER_ASSERT(FeatureDAOReadOnly::GetHandleList().size() == size); + + PluginDAO::unregisterPlugin(plHandle); +} + +/* + * Name: feature_dao_test_get_device_capabilities + * Description: Checks GetDeviceCapabilities + * Expected: no errors found + */ +RUNNER_TEST(feature_dao_test_get_device_capabilities) +{ + FeatureDAOReadOnly f1("feature1"); + RUNNER_ASSERT(f1.GetDeviceCapabilities().size() == 1); + + FeatureDAOReadOnly f2("feature2"); + RUNNER_ASSERT(f2.GetDeviceCapabilities().size() == 2); + + FeatureDAOReadOnly f3("feature3"); + RUNNER_ASSERT(f3.GetDeviceCapabilities().size() == 1); + + FeatureDAOReadOnly f4("feature4"); + RUNNER_ASSERT(f4.GetDeviceCapabilities().size() == 0); +} + +/* + * Name: feature_dao_test_get_names + * Description: Checks GetNames + * Expected: no errors found + * directly + */ +RUNNER_TEST(feature_dao_test_get_names) +{ + FeatureDAOReadOnly::NameMap names = FeatureDAOReadOnly::GetNames(); + + RUNNER_ASSERT(names.size() == 4); + + int count = 0; + FOREACH(n, names){ + if(n->second == "feature1" || n->second == "feature2" || + n->second == "feature3" || n->second == "feature4") + count++; + else RUNNER_ASSERT_MSG(false, "Wrong feature name"); + } + + RUNNER_ASSERT(count == 4); +} + +/* + * Name: feature_dao_test_dev_cap_with_feature_handle + * Description: Checks GetDevCapWithFeatureHandle + * Expected: no errors found + */ +RUNNER_TEST(feature_dao_test_dev_cap_with_feature_handle) +{ + FeatureDAOReadOnly::DeviceCapabilitiesMap map = FeatureDAOReadOnly::GetDevCapWithFeatureHandle(); + RUNNER_ASSERT(map.size() == 4); + + int count = 0; + FOREACH(n, map){ + if(n->second == "devicecap1" || n->second == "devicecap2" || + n->second == "devicecap3" || n->second == "devicecap4") + count++; + else RUNNER_ASSERT_MSG(false, "Wrong device capability"); + } + + RUNNER_ASSERT(count == 4); +} + + +/* + * Name: feature_dao_test_get_features + * Description: Checks GetFeatures + * Expected: no errors + */ +RUNNER_TEST(feature_dao_test_get_features) +{ +//tests commented because internal error occured due to many GetFeatures() calls +// std::list fs0(4); +// RUNNER_ASSERT(FeatureDAOReadOnly::GetFeatures(fs0).size() == 0); +// +// std::list fs1(4); +// fs1.push_front("feature"); +// fs1.push_front("feature2"); +// RUNNER_ASSERT(FeatureDAOReadOnly::GetFeatures(fs1).size() == 2); +// std::list fs2(4); +// fs2.push_front("feature"); +// fs2.push_front("feature2"); +// RUNNER_ASSERT(FeatureDAOReadOnly::GetFeatures(fs2).size() == 1); + + std::list fs3(4); + fs3.push_front("feature1"); + fs3.push_front("feature2"); + fs3.push_front("feature3"); + fs3.push_front("feature4"); + RUNNER_ASSERT(FeatureDAOReadOnly::GetFeatures(fs3).size() == 4); +} + +/* + * Name: feature_dao_test_get_feature_properties + * Description: Checks properties of inserted features + * Expected: properties of features should match values inserted to database + * directly + */ +RUNNER_TEST(feature_dao_test_get_feature_properties) +{ + { + FeatureDAOReadOnly dao("feature1"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetName(), "feature1"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetLibraryName(), "plugin1"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetLibraryPath(), ""); + } + + { + FeatureDAOReadOnly dao("feature2"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetName(), "feature2"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetLibraryName(), "p4"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetLibraryPath(), "path_to_p4"); + } + + { + FeatureDAOReadOnly dao("feature3"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetName(), "feature3"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetLibraryName(), "p4"); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetLibraryPath(), "path_to_p4"); + } +} + +/* + * Name: feature_dao_test_feature_constructor_name + * Description: - + * Expected: - + * + * TODO: test + */ +RUNNER_TEST(feature_dao_test_feature_constructor_name) +{ + std::list preinstalled; + preinstalled.push_back("feature1"); + preinstalled.push_back("feature2"); + preinstalled.push_back("feature3"); + preinstalled.push_back("feature4"); + + FOREACH(it, preinstalled) + { + FeatureDAOReadOnly dao(*it); + RUNNER_ASSERT_WHAT_EQUALS(dao.GetName(), *it); + } + + //TODO check exception that may occur (feature does not exist) +} + +/* + * Name: feature_dao_test_feature_handle_list + * Description: Checks if list of installed features is returend correctly + * Expected: list size should be at last equal number of preinserted features + */ +RUNNER_TEST(feature_dao_test_feature_handle_list) +{ + RUNNER_ASSERT(FeatureDAOReadOnly::GetHandleList().size() == 4); +} + +/* + * Name: feature_dao_test_is_feature_installed + * Description: Checks if installed features are showed correctly. + * Expected: correct installed features should be present + */ +RUNNER_TEST(feature_dao_test_is_feature_installed) +{ + //installed + { + std::list preinstalled; + preinstalled.push_back("feature1"); + preinstalled.push_back("feature2"); + preinstalled.push_back("feature3"); + preinstalled.push_back("feature4"); + + FOREACH(it, preinstalled) + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled(*it)); + } + + //not installed + { + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled( + "not_installed1") == false); + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled( + "plugin1") == false); + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled("") == false); + RUNNER_ASSERT(FeatureDAOReadOnly::isFeatureInstalled("ff") == false); + } +} + +/* + * Name: feature_dao_test_is_device_capab_installed + * Description: Checks if FeatureDAOReadOnly::isDeviceCapabilityInstalled works + * correctly. + * Expected: correct capabilities should be present + */ +RUNNER_TEST(feature_dao_test_is_device_capab_installed) +{ + //installed + std::list preinstalled; + preinstalled.push_back("devicecap1"); + preinstalled.push_back("devicecap2"); + preinstalled.push_back("devicecap3"); + preinstalled.push_back("devicecap4"); + + FOREACH(it, preinstalled) + RUNNER_ASSERT(FeatureDAOReadOnly::isDeviceCapabilityInstalled(*it)); + + //not installed + std::list notinstalled; + notinstalled.push_back("notinstalled1"); + notinstalled.push_back("plugin1"); + notinstalled.push_back(""); + notinstalled.push_back("ff"); + + FOREACH(it, notinstalled) + RUNNER_ASSERT(!FeatureDAOReadOnly::isDeviceCapabilityInstalled(*it)); +} + +#undef RUNNER_ASSERT_WHAT_EQUALS diff --git a/tests/dao/TestCases_PluginDAO.cpp b/tests/dao/TestCases_PluginDAO.cpp new file mode 100644 index 0000000..091d8ed --- /dev/null +++ b/tests/dao/TestCases_PluginDAO.cpp @@ -0,0 +1,499 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_PluginDAO.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains tests for feature dao class. + */ + +#include +#include +#include +#include +#include +//#include +#include +#include + +using namespace WrtDB; + +#define RUNNER_ASSERT_WHAT_EQUALS(in, test) \ + { std::string tmp(in); \ + RUNNER_ASSERT_MSG(tmp == test, "Equals: [" + tmp + "]"); } + +RUNNER_TEST_GROUP_INIT(DAO) + +/* + * Name: plugin_dao_test_register_plugins + * Description: registers new plugin and check if it was correctly registered + * Expected: plugin should be correctly registered + */ +RUNNER_TEST(plugin_dao_test_register_plugins) +{ + { + std::string libraryPath("np1 lib_path"); + std::string libraryName("np1"); + + PluginMetafileData pluginData; + pluginData.m_libraryName = libraryName; + + PluginHandle handle = PluginDAO::registerPlugin(pluginData, libraryPath); + PluginDAO::setPluginInstallationStatus( + handle, + PluginDAO:: + INSTALLATION_COMPLETED); + RUNNER_ASSERT(PluginDAO::isPluginInstalled(libraryName) == true); + + PluginDAO dao(handle); + std::string tmp; + tmp = dao.getLibraryPath(); //do for each + RUNNER_ASSERT_MSG(tmp == libraryPath, "Equals: " + tmp); + + unsigned int size = PluginDAO::getPluginHandleList().size(); + PluginDAO::unregisterPlugin(handle); + RUNNER_ASSERT(PluginDAO::getPluginHandleList().size() == size - 1); + } + + { + std::string libraryName("np2"); + + PluginMetafileData pluginData; + pluginData.m_libraryName = libraryName; + + PluginHandle handle = PluginDAO::registerPlugin(pluginData, ""); + PluginDAO::setPluginInstallationStatus( + handle, + PluginDAO:: + INSTALLATION_COMPLETED); + RUNNER_ASSERT(PluginDAO::isPluginInstalled(libraryName) == true); + + PluginDAO dao(handle); + RUNNER_ASSERT(dao.getLibraryPath() == ""); + + unsigned int size = PluginDAO::getPluginHandleList().size(); + PluginDAO::unregisterPlugin(handle); + RUNNER_ASSERT(PluginDAO::getPluginHandleList().size() == size - 1); + } +} + +/* + * Name: plugin_dao_test_register_plugin_implemented_object + * Description: registers new PluginImplementedObject + * and check if it was correctly registered + * Expected: plugin dao shoudld be upodated with PluginImplementedObject + */ +RUNNER_TEST(plugin_dao_test_register_plugin_implemented_object) +{ + { + std::string libraryPath("np3 lib_path"); + std::string libraryName("np3"); + + PluginMetafileData pluginData; + pluginData.m_libraryName = libraryName; + + PluginHandle handle = + PluginDAO::registerPlugin(pluginData, libraryPath); + RUNNER_ASSERT(PluginDAO::isPluginInstalled(libraryName) == true); + + std::string object1("object1"); + std::string object2("object2"); + PluginDAO::registerPluginImplementedObject(object1, handle); + PluginDAO::registerPluginImplementedObject(object2, handle); + + PluginHandle retHandle1 = + PluginDAO::getPluginHandleForImplementedObject(object1); + PluginHandle retHandle2 = + PluginDAO::getPluginHandleForImplementedObject(object1); + RUNNER_ASSERT(retHandle1 == handle); + RUNNER_ASSERT(retHandle2 == handle); + } +} + +/* + * Name: plugin_dao_test_get_root_plugin_handle_list + * Description: test of returning root plugin handle list + * Expected: - + */ +RUNNER_TEST(plugin_dao_test_get_root_plugin_handle_list) +{ + PluginHandleList handles = PluginDAOReadOnly::getRootPluginHandleList(); + RUNNER_ASSERT(handles.size() == 3); + + int count = 0; + FOREACH(n, handles){ + if(*n == 2 || *n == 3 || *n == 5) + count++; + else RUNNER_ASSERT_MSG(false, "Wrong plugin handle"); + } + + RUNNER_ASSERT(count == 3); +} + +/* + * Name: plugin_dao_test_get_implemented_objects + * Description: test of returning plugin handle list + * Expected: - + */ +RUNNER_TEST(plugin_dao_test_get_implemented_objects) +{ + ImplementedObjectsList handles = PluginDAOReadOnly::getImplementedObjects(); + RUNNER_ASSERT(handles.size() == 6); + + int count = 0; + FOREACH(n, handles){ + if(*n == "" || *n == "Plugin_3_Object_A" || *n == "Plugin_4_Object_A" || + *n == "Plugin_4_Object_B" || *n == "Plugin_4_Object_C" || *n == "Plugin_5_Object_A") + count++; + else RUNNER_ASSERT_MSG(false, "Wrong implemented object"); + } + + RUNNER_ASSERT(count == 6); +} + +/* + * Name: plugin_dao_test_register_plugin_implemented_object + * Description: registers dependecies for plugins and checks if they were saved + * Expected: registered dependecies should be returned from database + */ +RUNNER_TEST(plugin_dao_test_register_library_dependencies) +{ + { + std::string libraryPath("np4 lib_path"); + std::string libraryName("np4"); + + PluginMetafileData pluginData; + pluginData.m_libraryName = libraryName; + + PluginHandle handle = + PluginDAO::registerPlugin(pluginData, libraryPath); + PluginDAO::setPluginInstallationStatus( + handle, + PluginDAO:: + INSTALLATION_COMPLETED); + RUNNER_ASSERT(PluginDAO::isPluginInstalled(libraryName) == true); + + PluginHandle depHandles[] = { 117, 119 }; + + PluginHandleSetPtr dependencies(new PluginHandleSet); + dependencies->insert(depHandles[0]); + dependencies->insert(depHandles[1]); + + PluginDAO::registerPluginLibrariesDependencies(handle, dependencies); + + PluginDAO dao(handle); + PluginHandleSetPtr retDependencies; + retDependencies = dao.getLibraryDependencies(); + + RUNNER_ASSERT( + retDependencies->size() == sizeof(depHandles) / + sizeof(depHandles[0])); + RUNNER_ASSERT( + retDependencies->find(depHandles[0]) != retDependencies->end()); + RUNNER_ASSERT( + retDependencies->find(depHandles[1]) != retDependencies->end()); + } +} + +/* + * Name: plugin_dao_test_register_required_object + * Description: registers required plugin objects for plugins and checks if they + * were saved + * Expected: registered required plugin objects should be returned from database + */ +RUNNER_TEST(plugin_dao_test_register_required_object) +{ + { + std::string libraryPath("np5 lib_path"); + std::string libraryName("np5"); + + PluginMetafileData pluginData; + pluginData.m_libraryName = libraryName; + + PluginHandle handle = + PluginDAO::registerPlugin(pluginData, libraryPath); + PluginDAO::setPluginInstallationStatus( + handle, + PluginDAO:: + INSTALLATION_COMPLETED); + RUNNER_ASSERT(PluginDAO::isPluginInstalled(libraryName) == true); + + const size_t numObjects = 2; + std::string objectReq[numObjects]; + objectReq[0] = std::string("object1.req"); + objectReq[1] = std::string("object2.req"); + PluginDAO::registerPluginRequiredObject(objectReq[0], handle); + PluginDAO::registerPluginRequiredObject(objectReq[1], handle); + + WrtDB::PluginObjectsDAO::ObjectsPtr objects = + PluginDAO::getRequiredObjectsForPluginHandle(handle); + + RUNNER_ASSERT(objects->size() == numObjects + && objects->find(objectReq[0]) != objects->end() + && objects->find(objectReq[1]) != objects->end()); + } +} + +/* + * Name: plugin_dao_test_is_library_installed + * Description: tests if plugin isntallation/registrartion works + * Expected: only registered plugins should be reported as installed + */ +RUNNER_TEST(plugin_dao_test_is_library_installed) +{ + { + //exist + std::list preinstalled; + preinstalled.push_back("plugin1"); + preinstalled.push_back("plugin2"); + preinstalled.push_back("plugin3"); + preinstalled.push_back("p4"); + preinstalled.push_back("p5"); + + FOREACH(it, preinstalled) + RUNNER_ASSERT_MSG(PluginDAO::isPluginInstalled(*it), + std::string("Not found: ") + *it); + } + + { + //does not exist + RUNNER_ASSERT_MSG( + PluginDAO::isPluginInstalled("not_installed1") == false, + "Found not_installed1"); + RUNNER_ASSERT_MSG(PluginDAO::isPluginInstalled("p 4") == false, + "Found p 4"); + RUNNER_ASSERT_MSG(PluginDAO::isPluginInstalled("") == false, + "Found "); + RUNNER_ASSERT_MSG(PluginDAO::isPluginInstalled("p33") == false, + "Found p33"); + RUNNER_ASSERT_MSG(PluginDAO::isPluginInstalled("feature1") == false, + "Found feature1"); + } +} + +/* + * Name: plugin_dao_test_get_plugin_handle_list + * Description: test of returning plugin handle list + * Expected: returned list should be no less than number of registered plugins + */ +RUNNER_TEST(plugin_dao_test_get_plugin_handle_list) +{ + PluginHandleList handles = PluginDAO::getPluginHandleList(); + RUNNER_ASSERT(handles.size() >= 5); +} + +/* + * Name: plugin_dao_test_constructor_name + * Description: tests construction of plugin dao based on plugin name + * Expected: Instance of dao should be constructed only + * if there is given plugin in database + */ +RUNNER_TEST(plugin_dao_test_constructor_name) +{ + { + //exist + std::list preinstalled; + preinstalled.push_back("plugin1"); + preinstalled.push_back("plugin2"); + preinstalled.push_back("plugin3"); + preinstalled.push_back("p4"); + preinstalled.push_back("p5"); + + FOREACH(it, preinstalled) + { + PluginDAO dao(*it); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryName(), *it); + } + } + + { + //does not exist + std::list not_installed; + not_installed.push_back("plugin 1"); + not_installed.push_back(""); + not_installed.push_back("p 3"); + + FOREACH(it, not_installed) + { + Try { + //Plugin not exist + PluginDAO dao(*it); + RUNNER_ASSERT_MSG(false, "should not be found"); + } + Catch(PluginDAO::Exception::PluginNotExist) { + continue; + } + } + } +} + +/* + * Name: plugin_dao_test_get_plugin_properties + * Description: tests reading plugin properties from database + * Expected: Data, inserted into database, should be accessible via dao + */ +RUNNER_TEST(plugin_dao_test_get_plugin_properties) +{ + { + PluginDAO dao("p4"); + RUNNER_ASSERT(dao.getPluginHandle() == 4); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryName(), "p4"); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryPath(), "path_to_p4"); + } + + { + PluginDAO dao(5); + RUNNER_ASSERT(dao.getPluginHandle() == 5); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryName(), "p5"); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryPath(), "path_to_p5"); + } + + { + PluginDAO dao(2); + RUNNER_ASSERT(dao.getPluginHandle() == 2); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryName(), "plugin2"); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryPath(), "path_to_plugin2"); + } + + { + PluginDAO dao(1); + RUNNER_ASSERT(dao.getPluginHandle() == 1); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryName(), "plugin1"); + RUNNER_ASSERT_WHAT_EQUALS(dao.getLibraryPath(), ""); + } +} + +/* + * Name: plugin_dao_test_get_implemented_objects_for_plugin_handle_1 + * Description: tests receiving from dao Implemented Objects + * Expected: returned object is size 0 + */ +RUNNER_TEST(plugin_dao_test_get_implemented_objects_for_plugin_handle_1) +{ + { + const int handle = 1; + PluginDAOReadOnly dao(handle); + auto dbHandle = dao.getPluginHandle(); + RUNNER_ASSERT(dbHandle == handle); + auto objects = dao.getImplementedObjectsForPluginHandle(dbHandle); + + RUNNER_ASSERT(objects.empty()); + } +} + +/* + * Name: plugin_dao_test_get_implemented_objects_for_plugin_handle_2 + * Description: tests receiving from dao Implemented Objects + * Expected: returned object is size as it was inserted + */ +RUNNER_TEST(plugin_dao_test_get_implemented_objects_for_plugin_handle_2) +{ + { + std::set< std::string > preinstalled = { + "" + }; + + PluginDAOReadOnly dao(2); + auto dbHandle = dao.getPluginHandle(); + auto objects = dao.getImplementedObjectsForPluginHandle(dbHandle); + + //LogError("\n" << objects.size() << " " << preinstalled.size() << + // "\n"); + + RUNNER_ASSERT(objects.size() == preinstalled.size()); + + FOREACH(dbObject, objects) + { + RUNNER_ASSERT(preinstalled.find(*dbObject) != preinstalled.end()); + } + } +} + +/* + * Name: plugin_dao_test_get_implemented_objects_for_plugin_handle_3 + * Description: tests receiving from dao Implemented Objects + * Expected: returned objects list has preinserted object + */ +RUNNER_TEST(plugin_dao_test_get_implemented_objects_for_plugin_handle_3) +{ + { + std::set< std::string > preinstalled = { + "Plugin_3_Object_A" + }; + + PluginDAOReadOnly dao(3); + auto dbHandle = dao.getPluginHandle(); + auto objects = dao.getImplementedObjectsForPluginHandle(dbHandle); + RUNNER_ASSERT(objects.size() == preinstalled.size()); + + FOREACH(dbObject, objects) + { + RUNNER_ASSERT(preinstalled.find(*dbObject) != preinstalled.end()); + } + } +} + +/* + * Name: plugin_dao_test_get_implemented_objects_for_plugin_handle_4 + * Description: tests receiving from dao Implemented Objects + * Expected: returned objects list has all preinserted objects + */ +RUNNER_TEST(plugin_dao_test_get_implemented_objects_for_plugin_handle_4) +{ + { + std::set< std::string > preinstalled = { + "Plugin_4_Object_A", + "Plugin_4_Object_B", + "Plugin_4_Object_C", + }; + + PluginDAOReadOnly dao(4); + auto dbHandle = dao.getPluginHandle(); + auto objects = dao.getImplementedObjectsForPluginHandle(dbHandle); + RUNNER_ASSERT(objects.size() == preinstalled.size()); + + FOREACH(dbObject, objects) + { + RUNNER_ASSERT(preinstalled.find(*dbObject) != preinstalled.end()); + } + } +} + +/* + * Name: plugin_dao_test_get_implemented_objects_for_plugin_handle_5 + * Description: tests receiving from dao Implemented Objects + * Expected: returned objects list do not have object that was not inserted + */ +RUNNER_TEST(plugin_dao_test_get_implemented_objects_for_plugin_handle_5) +{ + { + std::set< std::string > preinstalled = { + "Plugin_5_Object_B", + }; + + PluginDAOReadOnly dao(5); + auto dbHandle = dao.getPluginHandle(); + auto objects = dao.getImplementedObjectsForPluginHandle(dbHandle); + RUNNER_ASSERT(objects.size() == preinstalled.size()); + + FOREACH(dbObject, objects) + { + RUNNER_ASSERT(preinstalled.find(*dbObject) == preinstalled.end()); + } + } +} + +#undef RUNNER_ASSERT_WHAT_EQUALS diff --git a/tests/dao/TestCases_PropertyDAO.cpp b/tests/dao/TestCases_PropertyDAO.cpp new file mode 100644 index 0000000..8ff2ad6 --- /dev/null +++ b/tests/dao/TestCases_PropertyDAO.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_PropertyDAO.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains tests for property dao class. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace WrtDB; +using namespace WrtDB::PropertyDAOReadOnly; + +// Widgets used "tizenid201", "tizenid202", "tizenid203", 2003(saved by +// wrt_dao_tests_prepare_db.sh) + +#define RUNNER_ASSERT_WHAT_EQUALS(in, test) \ + { std::string tmp(in); \ + RUNNER_ASSERT_MSG(tmp == test, "Equals: [" + tmp + "]"); } + +#define RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(in, test) \ + { \ + if (in.IsNull()) { RUNNER_ASSERT_MSG(false, "NULL"); } \ + else { RUNNER_ASSERT_WHAT_EQUALS(DPL::ToUTF8String(*in), test); } \ + } + +RUNNER_TEST_GROUP_INIT(DAO) + + +/* + * Name: property_dao_get_lists + * Description: tests returning list of properties for given id + * Expected: data received should match those, which were inserted in prepare + * script + */ +RUNNER_TEST(property_dao_get_lists) +{ + { //property list + struct three_field{ + WrtDB::TizenAppId tappid; + DbWidgetHandle whandleid; + size_t nrow; + }; + + three_field f3; + std::list prefList; + std::list::iterator it; + + f3.tappid=L"tizenid201";f3.whandleid=2000;f3.nrow=2; + prefList.push_back(f3); + f3.tappid=L"tizenid202"; f3.whandleid=2001;f3.nrow=1; + prefList.push_back(f3); + f3.tappid=L"tizenid203"; f3.whandleid=2002;f3.nrow=2; + prefList.push_back(f3); + f3.tappid=L"tizenid204"; f3.whandleid=2003;f3.nrow=0; + prefList.push_back(f3); + + for(it=prefList.begin();it!=prefList.end();++it) + { + PropertyDAOReadOnly::WidgetPreferenceList prefs_tid = + PropertyDAOReadOnly::GetPropertyList(it->tappid); + RUNNER_ASSERT(prefs_tid.size() == it->nrow); + } + } + { //property key list + WidgetPropertyKeyList orig_2000; + orig_2000.push_back(DPL::FromUTF8String("key1_for_2000")); + orig_2000.push_back(DPL::FromUTF8String("key2_for_2000")); + + WidgetPropertyKeyList orig_2001; + orig_2001.push_back(DPL::FromUTF8String("key1_for_2001")); + + WidgetPropertyKeyList orig_2002; + orig_2002.push_back(DPL::FromUTF8String("key1_for_2002")); + orig_2002.push_back(DPL::FromUTF8String("key2_for_2002")); + + std::map prefsKeyMap; + prefsKeyMap.insert(std::pair( + L"tizenid201", &orig_2000)); + prefsKeyMap.insert(std::pair( + L"tizenid202", &orig_2001)); + prefsKeyMap.insert(std::pair( + L"tizenid203", &orig_2002)); + + FOREACH(it_out, prefsKeyMap) { + WidgetPropertyKeyList got = PropertyDAOReadOnly::GetPropertyKeyList( + it_out->first); + RUNNER_ASSERT(got.size() == it_out->second->size()); + //TODO + // FOREACH(it_in, got) + // { + // RUNNER_ASSERT(it_out->second. + // } + } + } +} + + +/* + * Name: property_dao_get_list_exceptions + * Description: tests returning exception for given tizen_appid if is + * not inserted into WidgetInfo table + * Expected: procedure passes when is exception. Widget absent in the WidgetInfo + * table. + */ +RUNNER_TEST(property_dao_get_list_exceptions) +{ + { + bool assert_flag; + WrtDB::TizenAppId app_id_non_exists = L"non_exists"; + + assert_flag=true; + Try{ + PropertyDAOReadOnly::WidgetPreferenceList prefs = + PropertyDAOReadOnly::GetPropertyList(app_id_non_exists); + } Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) + { + assert_flag=false; + } + RUNNER_ASSERT_MSG(!(assert_flag),"Error, value doesn't make exception"); + } +} + + +/* + * Name: property_dao_set_update_remove + * Description: tests set new property for widget, updating property and + * removing it + * Expected: given operation should works + */ +RUNNER_TEST(property_dao_set_update_remove) +{ + WidgetPropertyKeyList keys = PropertyDAOReadOnly::GetPropertyKeyList( + L"tizenid201"); + + //ADD + PropertyDAO::SetProperty(L"tizenid201", + DPL::FromUTF8String("new_key"), + DPL::FromUTF8String("new_value1")); + + RUNNER_ASSERT_MSG( + keys.size() + 1 == + PropertyDAOReadOnly::GetPropertyKeyList(L"tizenid201").size(), + "new property not added"); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL( + PropertyDAOReadOnly::GetPropertyValue(L"tizenid201", + DPL::FromUTF8String("new_key")), + "new_value1"); + + //UPDATE + PropertyDAO::SetProperty(L"tizenid201", + DPL::FromUTF8String("new_key"), + DPL::FromUTF8String("new_value2")); + RUNNER_ASSERT_MSG( + keys.size() + 1 == + PropertyDAOReadOnly::GetPropertyKeyList(L"tizenid201").size(), + "new property not added"); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL( + PropertyDAOReadOnly::GetPropertyValue(L"tizenid201", + DPL::FromUTF8String("new_key")), + "new_value2"); + + //REMOVE + PropertyDAO::RemoveProperty(L"tizenid201", DPL::FromUTF8String("new_key")); + + RUNNER_ASSERT_MSG( + keys.size() == PropertyDAOReadOnly::GetPropertyKeyList( + L"tizenid201").size(), + "property not removed"); +} + +/* + * Name: property_dao_get_value + * Description: tests if properties can be received from database + * Expected: value, which were inserted before test, should be present + */ +RUNNER_TEST(property_dao_get_value) +{ + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL( + PropertyDAOReadOnly::GetPropertyValue( + L"tizenid201", DPL::FromUTF8String("key1_for_2000")), + "value_for_key1_2000"); + + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL( + PropertyDAOReadOnly::GetPropertyValue( + L"tizenid201", DPL::FromUTF8String("key2_for_2000")), + "value_for_key2_2000"); +} + +#undef RUNNER_ASSERT_WHAT_EQUALS diff --git a/tests/dao/TestCases_SecurityOriginDAO.cpp b/tests/dao/TestCases_SecurityOriginDAO.cpp new file mode 100644 index 0000000..fc4e46e --- /dev/null +++ b/tests/dao/TestCases_SecurityOriginDAO.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_SecurityOriginDAO.cpp + * @author Slawomir Pajak (s.pajak@partner.samsung.com) + * @version 1.0 + * @brief This file contains tests for security origin dao class. + */ + +#include +#include + + +RUNNER_TEST_GROUP_INIT(DAO) + +using namespace SecurityOriginDB; + +namespace { + +class SecurityOriginDAOWrapper { +public: + static SecurityOriginDAO* getSecurityOriginDAO() + { + static SecurityOriginDAOPtr securityOriginDAO( + new SecurityOriginDB::SecurityOriginDAO(DPL::FromASCIIString("testWidget123"))); + return securityOriginDAO.get(); + } +}; +} + +/** + * Name: security_origin_dao_set_remove + * Description: Test saves SecurityOriginData object, reads it, and removes it at the end. + * Expected: All operations should succeed. + */ +RUNNER_TEST(security_origin_dao_set_remove) +{ + SecurityOriginDAO* securityOriginDAO = SecurityOriginDAOWrapper::getSecurityOriginDAO(); + + SecurityOriginDataList dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "SecurityOriginDataList should be empty"); + + Origin origin(L"scheme", L"host", 123); + SecurityOriginData securityData(WrtDB::FEATURE_WEB_NOTIFICATION, origin); + securityOriginDAO->setSecurityOriginData(securityData, RESULT_ALLOW_ONCE, false); + + Origin origin2(L"scheme2", L"host2", 1234); + SecurityOriginData securityData2(WrtDB::FEATURE_GEOLOCATION, origin2); + securityOriginDAO->setSecurityOriginData(securityData2, RESULT_DENY_ONCE, true); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + + RUNNER_ASSERT_MSG(dataList.size() == 2, "CertificateDataList should not be empty"); + + securityOriginDAO->removeSecurityOriginData(securityData); + securityOriginDAO->removeSecurityOriginData(securityData2); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "SecurityOriginDataList should be empty"); +} + +/** + * Name: security_origin_dao_update + * Description: Test checks update operation for SecurityOriginData. + * Expected: All operations should succeed. + */ +RUNNER_TEST(security_origin_dao_update) +{ + SecurityOriginDAO* securityOriginDAO = SecurityOriginDAOWrapper::getSecurityOriginDAO(); + + SecurityOriginDataList dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "SecurityOriginDataList should be empty"); + + Origin origin(L"scheme", L"host", 123); + SecurityOriginData securityData(WrtDB::FEATURE_WEB_NOTIFICATION, origin); + securityOriginDAO->setSecurityOriginData(securityData, RESULT_ALLOW_ONCE, true); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.size() == 1, "CertificateDataList should not be empty"); + RUNNER_ASSERT((*dataList.begin())->feature == WrtDB::FEATURE_WEB_NOTIFICATION); + RUNNER_ASSERT((*dataList.begin())->origin.host == L"host"); + RUNNER_ASSERT((*dataList.begin())->origin.scheme == L"scheme"); + RUNNER_ASSERT((*dataList.begin())->origin.port == 123); + RUNNER_ASSERT(securityOriginDAO->getResult(**dataList.begin()) == RESULT_ALLOW_ONCE); + RUNNER_ASSERT(securityOriginDAO->isReadOnly(**dataList.begin())); + + securityOriginDAO->setSecurityOriginData(securityData, RESULT_DENY_ONCE, false); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.size() == 1, "CertificateDataList should not be empty"); + RUNNER_ASSERT((*dataList.begin())->feature == WrtDB::FEATURE_WEB_NOTIFICATION); + RUNNER_ASSERT((*dataList.begin())->origin.host == L"host"); + RUNNER_ASSERT((*dataList.begin())->origin.scheme == L"scheme"); + RUNNER_ASSERT((*dataList.begin())->origin.port == 123); + RUNNER_ASSERT(securityOriginDAO->getResult(**dataList.begin()) == RESULT_DENY_ONCE); + RUNNER_ASSERT(!securityOriginDAO->isReadOnly(**dataList.begin())); + + securityOriginDAO->removeSecurityOriginData(securityData); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "SecurityOriginDataList should be empty"); +} + + +/** + * Name: security_origin_dao_remove_by_result + * Description: Test remove by result operation for SecurityOriginData. + * Expected: All operations should succeed. + */ +RUNNER_TEST(security_origin_dao_remove_by_result) +{ + SecurityOriginDAO* securityOriginDAO = SecurityOriginDAOWrapper::getSecurityOriginDAO(); + + SecurityOriginDataList dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "SecurityOriginDataList should be empty"); + + Origin origin(L"scheme", L"host", 123); + SecurityOriginData securityData(WrtDB::FEATURE_WEB_NOTIFICATION, origin); + securityOriginDAO->setSecurityOriginData(securityData, RESULT_ALLOW_ONCE, false); + + Origin origin2(L"scheme2", L"host2", 1234); + SecurityOriginData securityData2(WrtDB::FEATURE_GEOLOCATION, origin2); + securityOriginDAO->setSecurityOriginData(securityData2, RESULT_DENY_ONCE, true); + + Origin origin3(L"scheme3", L"host3", 2546); + SecurityOriginData securityData3(WrtDB::FEATURE_FULLSCREEN_MODE, origin3); + securityOriginDAO->setSecurityOriginData(securityData3, RESULT_DENY_ONCE, false); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.size() == 3, "CertificateDataList should not be empty"); + + securityOriginDAO->removeSecurityOriginData(RESULT_DENY_ONCE); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.size() == 1, "CertificateDataList should not be empty"); + + securityOriginDAO->removeSecurityOriginData(RESULT_ALLOW_ONCE); + + dataList = securityOriginDAO->getSecurityOriginDataList(); + RUNNER_ASSERT_MSG(dataList.empty(), "SecurityOriginDataList should be empty"); +} + +/** + * Name: security_origin_dao_origin_operators + * Description: Test comparison operators for Origin class. + * Expected: All operations should succeed. + */ +RUNNER_TEST(security_origin_dao_origin_operators) +{ + Origin origin1(L"scheme", L"host", 123); + Origin origin2(L"scheme", L"host", 123); + Origin origin3(L"scheme1", L"host", 123); + Origin origin4(L"scheme", L"host2", 123); + Origin origin5(L"scheme", L"host", 122); + + RUNNER_ASSERT(origin1 == origin2); + RUNNER_ASSERT(origin2 == origin1); + RUNNER_ASSERT(origin1 != origin3); + RUNNER_ASSERT(origin1 != origin4); + RUNNER_ASSERT(origin1 != origin5); + RUNNER_ASSERT(origin3 != origin4); + RUNNER_ASSERT(origin4 != origin5); +} + +/** + * Name: security_origin_dao_data_operators + * Description: Test comparison operators for SecurityOriginData class. + * Expected: All operations should succeed. + */ +RUNNER_TEST(security_origin_dao_data_operators) +{ + SecurityOriginData data1(WrtDB::FEATURE_WEB_NOTIFICATION, Origin(L"scheme", L"host", 123)); + SecurityOriginData data2(WrtDB::FEATURE_WEB_NOTIFICATION, Origin(L"scheme", L"host", 123)); + SecurityOriginData data3(WrtDB::FEATURE_END, Origin(L"scheme", L"host", 123)); + SecurityOriginData data4(WrtDB::FEATURE_WEB_NOTIFICATION, Origin(L"scheme1", L"host", 123)); + SecurityOriginData data5(WrtDB::FEATURE_WEB_NOTIFICATION, Origin(L"scheme", L"host1", 123)); + SecurityOriginData data6(WrtDB::FEATURE_WEB_NOTIFICATION, Origin(L"scheme", L"host", 124)); + + RUNNER_ASSERT(data1 == data2); + RUNNER_ASSERT(data2 == data1); + RUNNER_ASSERT(data1 != data3); + RUNNER_ASSERT(data1 != data4); + RUNNER_ASSERT(data1 != data5); + RUNNER_ASSERT(data1 != data6); + RUNNER_ASSERT(data3 != data4); + RUNNER_ASSERT(data3 != data5); + RUNNER_ASSERT(data3 != data6); + RUNNER_ASSERT(data4 != data5); + RUNNER_ASSERT(data4 != data6); + RUNNER_ASSERT(data5 != data6); +} diff --git a/tests/dao/TestCases_WidgetDAO.cpp b/tests/dao/TestCases_WidgetDAO.cpp new file mode 100755 index 0000000..bbcc249 --- /dev/null +++ b/tests/dao/TestCases_WidgetDAO.cpp @@ -0,0 +1,1636 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_WidgetDAO.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains tests for widget dao class. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace WrtDB; + +namespace { +class WacSecurityMock : public WrtDB::IWidgetSecurity +{ + public: + WacSecurityMock() : + mRecognized(false), + mDistributorSigned(false) + {} + + virtual const WidgetCertificateDataList& getCertificateList() const + { + return mList; + } + + virtual bool isRecognized() const + { + return mRecognized; + } + virtual bool isDistributorSigned() const + { + return mDistributorSigned; + } + virtual void getCertificateChainList(CertificateChainList& /*lst*/) const {} + virtual void getCertificateChainList(CertificateChainList& /*lst*/, + CertificateSource /*source*/) const {} + + WrtDB::WidgetCertificateDataList& getCertificateListRef() + { + return mList; + } + + void setRecognized(bool recognized) + { + mRecognized = recognized; + } + void setDistributorSigned(bool distributorSigned) + { + mDistributorSigned = distributorSigned; + } + + private: + WrtDB::WidgetCertificateDataList mList; + // author signature verified + bool mRecognized; + // known distribuor + bool mDistributorSigned; + // distributor is wac +}; + +TizenAppId _registerWidget(const WidgetRegisterInfo& regInfo, + const IWidgetSecurity& sec, + int line) +{ + TizenAppId tizenAppId; + Try { + auto previous = WidgetDAO::getTizenAppIdList(); + + // register widget + tizenAppId = WidgetDAO::registerWidgetGeneratePkgId(regInfo, sec); + + RUNNER_ASSERT_MSG(!tizenAppId.empty(), + "(called from line " << line << ")"); + + auto current = WidgetDAO::getTizenAppIdList(); + RUNNER_ASSERT_MSG(previous.size() + 1 == current.size(), + "(called from line " << line << ")"); + + RUNNER_ASSERT_MSG(WidgetDAO::isWidgetInstalled( + tizenAppId), + "(called from line " << line << " tizenAppId: " << + tizenAppId << ")"); + } + Catch(WidgetDAO::Exception::AlreadyRegistered) { + RUNNER_ASSERT_MSG( + false, + "Unexpected exception (called from line " << line << ")"); + } + return tizenAppId; +} + +#define REGISTER_WIDGET(regInfo, sec) _registerWidget((regInfo), \ + (sec), \ + __LINE__) + +template +bool checkException(Function fun) +{ + Try + { + fun(); + } + Catch(Exception){ + return true; + } + return false; +} + +} // namespace + +// Widgets used <2300,2500), 2000, 2001, 2002, 2003 + +#define RUNNER_ASSERT_WHAT_EQUALS(in, test) \ + { std::string tmp(in); \ + RUNNER_ASSERT_MSG(tmp == test, "Equals: [" + tmp + "]"); } + +#define RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(in, test) \ + { \ + if (in.IsNull()) { RUNNER_ASSERT_MSG(false, "NULL"); } \ + else { RUNNER_ASSERT_WHAT_EQUALS(DPL::ToUTF8String(*in), test); } \ + } + +#define RUNNER_ASSERT_WHAT_EQUALS_OPTIONALINT(in, test) \ + { \ + if (in.IsNull()) { RUNNER_ASSERT_MSG(false, "NULL"); } \ + else { RUNNER_ASSERT_MSG(*in == test, "Equals: [" + *in + "]"); } \ + } + +#define RUNNER_ASSERT_EXCEPTION(exceptionType, function) \ + { \ + RUNNER_ASSERT(checkException([](){function})); \ + } + +RUNNER_TEST_GROUP_INIT(DAO) + +//2300 +/* + * Name: widget_dao_test_register_widget_empty_strings + * Description: Tests registeration of new widget with empty values + * Expected: widget should be registered in database + */ +RUNNER_TEST(widget_dao_test_register_widget_empty_strings) +{ + WidgetRegisterInfo regInfo; + + //info + regInfo.configInfo.widget_id = DPL::FromUTF8String(""); + regInfo.configInfo.version = DPL::FromUTF8String(""); + regInfo.configInfo.width = 10; + regInfo.configInfo.height = 10; + regInfo.configInfo.authorName = DPL::FromUTF8String(""); + regInfo.configInfo.authorEmail = DPL::FromUTF8String(""); + regInfo.configInfo.authorHref = DPL::FromUTF8String(""); + regInfo.baseFolder = ""; + //TODO authenticated, etc... + regInfo.configInfo.flashNeeded = false; + regInfo.configInfo.minVersionRequired = DPL::FromUTF8String("1.0"); + regInfo.configInfo.backSupported = true; + + //loc info + ConfigParserData::LocalizedData locData; + locData.name = DPL::FromUTF8String(""); + locData.shortName = DPL::FromUTF8String(""); + locData.description = DPL::FromUTF8String(""); + locData.license = DPL::FromUTF8String(""); + locData.licenseFile = DPL::FromUTF8String(""); + locData.licenseHref = DPL::FromUTF8String(""); + regInfo.configInfo.localizedDataSet.insert( + std::make_pair(DPL::FromUTF8String("en"), locData)); + + //userAgentLoc + + //icons + ConfigParserData::Icon icon(DPL::FromUTF8String("")); + icon.width = 10; + icon.height = 10; + LocaleSet locs; + locs.insert(DPL::FromUTF8String("en")); + WidgetRegisterInfo::LocalizedIcon locIcon(icon, locs); + regInfo.localizationData.icons.push_back(locIcon); + + //start file + WidgetRegisterInfo::StartFileProperties prop; + prop.encoding = DPL::FromUTF8String(""); + prop.type = DPL::FromUTF8String(""); + WidgetRegisterInfo::LocalizedStartFile file; + file.path = DPL::FromUTF8String(""); + file.propertiesForLocales.insert( + std::make_pair(DPL::FromUTF8String("en"), prop)); + regInfo.localizationData.startFiles.push_back(file); + + //widget pref + ConfigParserData::Preference pref(DPL::FromUTF8String(""), false); + pref.value = DPL::FromUTF8String(""); + regInfo.configInfo.preferencesList.insert(pref); + + //widget feature + ConfigParserData::Feature feat(DPL::FromUTF8String("")); + regInfo.configInfo.featuresList.insert(feat); + + //win modes + regInfo.configInfo.windowModes.insert(DPL::FromUTF8String("")); + + //WARP info + ConfigParserData::AccessInfo access(DPL::FromUTF8String(""), true); + regInfo.configInfo.accessInfoSet.insert(access); + + //certificates + WidgetCertificateData cert; + cert.owner = WidgetCertificateData::AUTHOR; + cert.type = WidgetCertificateData::ROOT; + cert.chainId = 1; + cert.strMD5Fingerprint = ""; + cert.strSHA1Fingerprint = ""; + cert.strCommonName = DPL::FromUTF8String(""); + + WacSecurityMock security; + security.getCertificateListRef().push_back(cert); + + REGISTER_WIDGET(regInfo, security); +} + +/* + * Name: widget_dao_test_register_widget_empty_strings + * Description: Tests possiblity of registering twice same content (different + * tizenId) + * Expected: it should be possible + */ +RUNNER_TEST(widget_dao_test_twice_install_same_widget) +{ + WacSecurityMock sec; + { + WidgetRegisterInfo regInfo; + REGISTER_WIDGET(regInfo, sec); + } + { + WidgetRegisterInfo regInfo; + REGISTER_WIDGET(regInfo, sec); + } +} + +/* + * Name: widget_dao_test_register_widget_minimum_info + * Description: Tests simplest registeration of new widget + * Expected: widget should be registered in database + */ +RUNNER_TEST(widget_dao_test_register_widget_minimum_info) +{ + WacSecurityMock sec; + const std::size_t NUMBER_OF_WIDGETS = 5; + + TizenAppId lastTizenAppId; + + for (std::size_t number = 0; number < NUMBER_OF_WIDGETS; ++number) { + WidgetRegisterInfo regInfo; + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + lastTizenAppId = tizenAppId; + + WidgetDAO dao(tizenAppId); + //TODO check nulls + } +} + +/* + * Name: widget_dao_test_register_widget_info + * Description: Tests registeration of many widgets + * Expected: all widgets should be registered in database + */ +RUNNER_TEST(widget_dao_test_register_widget_info) +{ + WacSecurityMock sec; + const std::size_t NUMBER_OF_WIDGETS = 5; + + for (std::size_t number = 0; number < NUMBER_OF_WIDGETS; ++number) { + std::ostringstream str; + str << "register_info_test_" << number; + + WidgetRegisterInfo regInfo; + regInfo.configInfo.widget_id = DPL::FromUTF8String(str.str()); + regInfo.configInfo.version = DPL::FromUTF8String(str.str()); + regInfo.configInfo.width = 10; + regInfo.configInfo.height = 10; + regInfo.configInfo.authorName = DPL::FromUTF8String(str.str()); + regInfo.configInfo.authorEmail = DPL::FromUTF8String(str.str()); + regInfo.configInfo.authorHref = DPL::FromUTF8String(str.str()); + regInfo.baseFolder = str.str(); //base folder at the end has / + regInfo.configInfo.flashNeeded = false; + //TODO authenticated, etc... + //in wrt-installer: TaskWidgetConfig::fillWidgetConfig: + //regInfo.minVersion = regInfo.configInfo.minVersionRequired + regInfo.minVersion = DPL::FromUTF8String("1.0"); + regInfo.configInfo.backSupported = true; + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getGUID(), str.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getVersion(), str.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getAuthorName(), str.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getAuthorEmail(), str.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getAuthorHref(), str.str()); + RUNNER_ASSERT_WHAT_EQUALS(dao.getBaseFolder(), str.str() + "/"); + RUNNER_ASSERT(dao.getWebkitPluginsRequired() == false); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getMinimumWacVersion(), "1.0"); + } +} + +/* + * Name: widget_dao_test_register_widget_extended_info + * Description: Tests registeration of widget_extended_info + * Expected: registeration of extended inforamtion is checked + * via existence of backgroudn page value + */ +RUNNER_TEST(widget_dao_test_register_widget_extended_info) +{ + WacSecurityMock sec; + const std::size_t NUMBER_OF_WIDGETS = 5; + + for (std::size_t number = 0; number < NUMBER_OF_WIDGETS; ++number) { + std::ostringstream str; + str << "register_ext_info_test_" << number; + + WidgetRegisterInfo regInfo; + + regInfo.configInfo.backgroundPage = L"background.html"; + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getBackgroundPage(), + "background.html"); + } +} + +/* + * Name: widget_dao_test_register_widget_localized_info + * Description: Tests registeration of localized widgets information + * Expected: values received by dao should match those which were registered + */ +RUNNER_TEST(widget_dao_test_register_widget_localized_info) +{ + WacSecurityMock sec; + const std::size_t NUMBER_OF_WIDGETS = 5; + + for (std::size_t number = 0; number < NUMBER_OF_WIDGETS; ++number) { + WidgetRegisterInfo regInfo; + std::ostringstream str_en; + std::ostringstream str_pl; + str_en << "register_loc_info_test_en_" << number; + str_pl << "register_loc_info_test_pl_" << number; + { //EN + ConfigParserData::LocalizedData locDataEn; + locDataEn.name = DPL::FromUTF8String(str_en.str()); + locDataEn.shortName = DPL::FromUTF8String(str_en.str()); + locDataEn.description = DPL::FromUTF8String(str_en.str()); + locDataEn.license = DPL::FromUTF8String(str_en.str()); + locDataEn.licenseFile = DPL::FromUTF8String(str_en.str()); + locDataEn.licenseHref = DPL::FromUTF8String(str_en.str()); + regInfo.configInfo.localizedDataSet.insert( + std::make_pair(DPL::FromUTF8String("en"), locDataEn)); + } + + { //PL + ConfigParserData::LocalizedData locDataPl; + locDataPl.name = DPL::FromUTF8String(str_pl.str()); + locDataPl.shortName = DPL::FromUTF8String(str_pl.str()); + locDataPl.description = DPL::FromUTF8String(str_pl.str()); + locDataPl.license = DPL::FromUTF8String(str_pl.str()); + locDataPl.licenseFile = DPL::FromUTF8String(str_pl.str()); + locDataPl.licenseHref = DPL::FromUTF8String(str_pl.str()); + regInfo.configInfo.localizedDataSet.insert( + std::make_pair(DPL::FromUTF8String("pl"), locDataPl)); + } + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + RUNNER_ASSERT_MSG(dao.getLanguageTags().size() == 2, + "language tags list invalid"); + + { //EN + WidgetLocalizedInfo locInfo = + dao.getLocalizedInfo(DPL::FromUTF8String("en")); + + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.name, + str_en.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.shortName, + str_en.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.description, + str_en.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.license, + str_en.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.licenseHref, + str_en.str()); + } + + { //PL + WidgetLocalizedInfo locInfo = + dao.getLocalizedInfo(DPL::FromUTF8String("pl")); + + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.name, + str_pl.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.shortName, + str_pl.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.description, + str_pl.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.license, + str_pl.str()); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(locInfo.licenseHref, + str_pl.str()); + } + } +} + +/* + * Name: widget_dao_test_register_widget_icons + * Description: Tests registeration of localized icons information + * Expected: values received by dao should match those which were registered + * for icon + */ +RUNNER_TEST(widget_dao_test_register_widget_icons) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + + ConfigParserData::Icon icon(L"icon1"); + icon.width = 10; + icon.height = 10; + LocaleSet locs; + locs.insert(DPL::FromUTF8String("en")); + WidgetRegisterInfo::LocalizedIcon locIcon(icon, locs); + regInfo.localizationData.icons.push_back(locIcon); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + WidgetDAOReadOnly::WidgetIconList list = dao.getIconList(); + + RUNNER_ASSERT(list.size() == regInfo.localizationData.icons.size()); + WidgetDAOReadOnly::WidgetIconList::const_iterator it1 = list.begin(); + WidgetRegisterInfo::LocalizedIconList::const_iterator it2 = + regInfo.localizationData.icons.begin(); + for (; it1 != list.end() && it2 != regInfo.localizationData.icons.end(); + ++it1, ++it2) + { + RUNNER_ASSERT(it2->height == it1->iconHeight); + RUNNER_ASSERT(it2->width == it1->iconWidth); + RUNNER_ASSERT(it2->src == it1->iconSrc); + RUNNER_ASSERT(it2->availableLocales == locs); + } +} + +/* + * Name: widget_dao_test_register_widget_start_files + * Description: Tests registeration of localized start files + * Expected: no expectations as it should be removed + */ +RUNNER_TEST(widget_dao_test_register_widget_start_files) +{ + WacSecurityMock sec; + + WidgetRegisterInfo::LocalizedStartFileList files; + WidgetRegisterInfo::StartFilePropertiesForLocalesMap map1; + WidgetRegisterInfo::StartFileProperties prop1; + prop1.encoding = DPL::FromUTF8String("enc1"); + prop1.type = DPL::FromUTF8String("type1"); + + map1.insert(std::make_pair(DPL::FromUTF8String("en"), prop1)); + map1.insert(std::make_pair(DPL::FromUTF8String("pl"), prop1)); + + WidgetRegisterInfo::LocalizedStartFile file1; + WidgetRegisterInfo::LocalizedStartFile file2; + file1.path = DPL::FromUTF8String("path1"); + file1.propertiesForLocales = map1; + file2.path = DPL::FromUTF8String("path2"); + file2.propertiesForLocales = map1; + + files.push_back(file1); + files.push_back(file1); + + WidgetRegisterInfo regInfo; + regInfo.localizationData.startFiles = files; + + REGISTER_WIDGET(regInfo, sec); + + //TODO no getter in WidgetDAO (getter in LocalizedWidgetDAO, + // but it will be removed +} + +/* + * Name: widget_dao_test_register_widget_features + * Description: Tests registeration of features of widget + * Expected: number of features should match (for given widget reginfo) + */ +RUNNER_TEST(widget_dao_test_register_widget_features) +{ + WacSecurityMock sec; + ConfigParserData::FeaturesList features; + features.insert(ConfigParserData::Feature(DPL::FromUTF8String("f1"))); + features.insert(ConfigParserData::Feature(DPL::FromUTF8String("f2"))); + features.insert(ConfigParserData::Feature(DPL::FromUTF8String("f3"))); + + WidgetRegisterInfo regInfo; + FOREACH(it, features) + regInfo.configInfo.featuresList.insert(*it); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + WidgetFeatureSet out = dao.getFeaturesList(); + RUNNER_ASSERT_MSG(out.size() == features.size(), + "wrong number of features"); + // FOREACH(it, out) + // RUNNER_ASSERT(features.find(*it) != features.end()); +} + +/* + * Name: widget_dao_test_register_widget_win_modes + * Description: Tests registeration of window modes + * Expected: all modes should be returned from dao + */ +RUNNER_TEST(widget_dao_test_register_widget_win_modes) +{ + WacSecurityMock sec; + std::set modes; + modes.insert(DPL::FromUTF8String("full")); + modes.insert(DPL::FromUTF8String("window")); + + WidgetRegisterInfo regInfo; + + FOREACH(it, modes) + regInfo.configInfo.windowModes.insert(*it); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + std::list wins = dao.getWindowModes(); + RUNNER_ASSERT_MSG(modes.size() == wins.size(), + "wrong number of window modes"); + FOREACH(it, wins) + RUNNER_ASSERT(modes.find(*it) != modes.end()); +} + +/* + * Name: widget_dao_test_register_widget_warp_info + * Description: Tests registeration of access info iris + * Expected: all access info iris should be returned from dao + */ +RUNNER_TEST(widget_dao_test_register_widget_warp_info) +{ + WacSecurityMock sec; + ConfigParserData::AccessInfoSet orig; + orig.insert(ConfigParserData::AccessInfo(DPL::FromUTF8String("iri1"), + true)); + orig.insert(ConfigParserData::AccessInfo(DPL::FromUTF8String("iri2"), + false)); + orig.insert(ConfigParserData::AccessInfo(DPL::FromUTF8String("iri3"), + true)); + + WidgetRegisterInfo regInfo; + FOREACH(it, orig) + regInfo.configInfo.accessInfoSet.insert(*it); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + + WidgetAccessInfoList out; + dao.getWidgetAccessInfo(out); + RUNNER_ASSERT_MSG(out.size() == orig.size(), + "wrong number of access info elem"); + FOREACH(it, out){ + ConfigParserData::AccessInfo tmp(it->strIRI, it->bSubDomains); + RUNNER_ASSERT(orig.find(tmp) != orig.end()); + } +} + +/* + * Name: widget_dao_test_register_widget_certificates + * Description: Tests registeration of widget certificates + * Expected: all certificates should be returned from dao + * and should contain inserted data + */ +RUNNER_TEST(widget_dao_test_register_widget_certificates) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + + WidgetCertificateData cert; + cert.owner = WidgetCertificateData::AUTHOR; + cert.type = WidgetCertificateData::ROOT; + cert.chainId = 1; + cert.strMD5Fingerprint = "md5"; + cert.strSHA1Fingerprint = "sha1"; + cert.strCommonName = DPL::FromUTF8String("common name"); + + WidgetCertificateDataList& certListRef = sec.getCertificateListRef(); + certListRef.push_back(cert); + + // register widget + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + + // certificates + WidgetCertificateDataList recList = dao.getCertificateDataList(); + RUNNER_ASSERT(recList.size() == certListRef.size()); + + auto recListIt = recList.begin(); + auto certListIt = certListRef.begin(); + for (; recListIt != recList.end() && certListIt != certListRef.end(); + ++recListIt, ++certListIt) + { + RUNNER_ASSERT(recListIt->chainId == certListIt->chainId); + RUNNER_ASSERT(recListIt->owner == certListIt->owner); + RUNNER_ASSERT(recListIt->strCommonName == certListIt->strCommonName); + RUNNER_ASSERT(recListIt->strMD5Fingerprint == + certListIt->strMD5Fingerprint); + RUNNER_ASSERT(recListIt->strSHA1Fingerprint == + certListIt->strSHA1Fingerprint); + RUNNER_ASSERT(recListIt->type == certListIt->type); + } + + // fingerprints + RUNNER_ASSERT(dao.getKeyFingerprints(WidgetCertificateData::DISTRIBUTOR, + WidgetCertificateData::ENDENTITY). + empty()); + RUNNER_ASSERT(dao.getKeyFingerprints(WidgetCertificateData::AUTHOR, + WidgetCertificateData::ENDENTITY). + empty()); + RUNNER_ASSERT(dao.getKeyFingerprints(WidgetCertificateData::DISTRIBUTOR, + WidgetCertificateData::ROOT).empty()); + + FingerPrintList fingerprints = dao.getKeyFingerprints( + WidgetCertificateData::AUTHOR, + WidgetCertificateData::ROOT); + + RUNNER_ASSERT(fingerprints.size() == certListRef.size() * 2); + FOREACH(it, certListRef) + { + auto md5 = std::find(fingerprints.begin(), + fingerprints.end(), + it->strMD5Fingerprint); + RUNNER_ASSERT(md5 != fingerprints.end()); + + auto sha = std::find(fingerprints.begin(), + fingerprints.end(), + it->strSHA1Fingerprint); + RUNNER_ASSERT(sha != fingerprints.end()); + } + + // common names + RUNNER_ASSERT(dao.getKeyCommonNameList(WidgetCertificateData::DISTRIBUTOR, + WidgetCertificateData::ENDENTITY). + empty()); + RUNNER_ASSERT(dao.getKeyCommonNameList(WidgetCertificateData::AUTHOR, + WidgetCertificateData::ENDENTITY). + empty()); + RUNNER_ASSERT(dao.getKeyCommonNameList(WidgetCertificateData::DISTRIBUTOR, + WidgetCertificateData::ROOT).empty()); + + FingerPrintList commonNames = dao.getKeyCommonNameList( + WidgetCertificateData::AUTHOR, + WidgetCertificateData::ROOT); + + RUNNER_ASSERT(commonNames.size() == certListRef.size()); + FOREACH(it, certListRef) + { + auto cn = std::find(commonNames.begin(), + commonNames.end(), + DPL::ToUTF8String(it->strCommonName)); + RUNNER_ASSERT(cn != commonNames.end()); + } +} + +/* + * Name: widget_dao_test_register_widget_privileges + * Description: Tests registration of widget privileges + */ +RUNNER_TEST(widget_dao_test_register_widget_privileges) +{ + + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + + ConfigParserData::PrivilegeList& privilegeList = + regInfo.configInfo.privilegeList; + privilegeList.insert(DPL::FromUTF8String("name")); + privilegeList.insert(DPL::FromUTF8String("name2")); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + WidgetDAO dao(tizenAppId); + + WrtDB::PrivilegeList privListFromDB; + privListFromDB = dao.getWidgetPrivilege(); + + RUNNER_ASSERT(privilegeList.size() == privListFromDB.size()); + + auto privListIt = privilegeList.begin(); + auto privDBIt = privListFromDB.begin(); + for(; privListIt != privilegeList.end() && privDBIt != privListFromDB.end(); + ++privListIt, ++privDBIt) + { + RUNNER_ASSERT(*privDBIt == privListIt->name); + } +} + +/* + * Name: widget_dao_test_register_app_control + * Description: Tests app control + */ +RUNNER_TEST(widget_dao_test_register_app_control) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + + ConfigParserData::AppControlInfo appControl(DPL::FromUTF8String("operation")); + appControl.m_disposition + = ConfigParserData::AppControlInfo::Disposition::WINDOW; + appControl.m_mimeList.insert(DPL::FromUTF8String("mime")); + appControl.m_src = DPL::FromUTF8String("src"); + appControl.m_uriList.insert(DPL::FromUTF8String("uri")); + + ConfigParserData::AppControlInfoList& appControlListRef + = regInfo.configInfo.appControlList; + appControlListRef.push_back(appControl); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + + WrtDB::WidgetAppControlList appControlInfoListDB; + dao.getAppControlList(appControlInfoListDB); + RUNNER_ASSERT(appControlInfoListDB.size() == appControlListRef.size()); + auto appDBIt = appControlInfoListDB.begin(); + auto appRefIt = appControlListRef.begin(); + + for (;appDBIt != appControlInfoListDB.end() + && appRefIt != appControlListRef.end(); + ++appDBIt, ++appRefIt) + { + RUNNER_ASSERT((WidgetAppControl::Disposition) + appRefIt->m_disposition == appDBIt->disposition); + RUNNER_ASSERT(appRefIt->m_index == appDBIt->index); + RUNNER_ASSERT(appRefIt->m_operation == appDBIt->operation); + RUNNER_ASSERT(appRefIt->m_src == appDBIt->src); + for(auto it = appRefIt->m_mimeList.begin(); + it != appRefIt->m_mimeList.end(); + ++it) + { + RUNNER_ASSERT((*it) == appDBIt->mime); + } + for(auto it = appRefIt->m_uriList.begin(); + it != appRefIt->m_uriList.end(); + ++it) + { + RUNNER_ASSERT((*it) == appDBIt->uri); + } + } +} + +/* + * Name: widget_dao_test_is_widget_installed + * Description: Tests checking if widgets are installed + * Expected: installed widgets should be stated as installed + */ +RUNNER_TEST(widget_dao_test_is_widget_installed) +{ + RUNNER_ASSERT(WidgetDAO::isWidgetInstalled(L"tizenid201")); + + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + RUNNER_ASSERT(WidgetDAO::isWidgetInstalled(tizenAppId)); +} + +/* + * Name: widget_dao_test_unregister_widget + * Description: Tests unregistering widgets + * Expected: widget register informations should be successfully removed + */ +RUNNER_TEST(widget_dao_test_unregister_widget) +{ + WacSecurityMock sec; + TizenAppIdList ids = WidgetDAO::getTizenAppIdList(); + + WidgetRegisterInfo regInfo; + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO::unregisterWidget(tizenAppId); + + RUNNER_ASSERT_MSG(ids.size() == WidgetDAO::getTizenAppIdList().size(), + "Widget unregister failed"); +} + +/* + * Name: widget_dao_test_register_or_update_widget + * Description: Tests reregistering widgets + * Expected: widget should be successfully replaced + */ +RUNNER_TEST(widget_dao_test_register_or_update_widget) +{ + WacSecurityMock sec; + + WidgetRegisterInfo regInfo; + regInfo.configInfo.version = L"1.0"; + regInfo.configInfo.authorName = L"AAA"; + + WidgetRegisterInfo regInfo2; + regInfo2.configInfo.version = L"1.1"; + regInfo2.configInfo.authorName = L"BBB"; + + WrtDB::TizenAppId tizenAppId(L"abcdefghij"); + + //first installation + WidgetDAO::registerWidget(tizenAppId, regInfo, sec); + RUNNER_ASSERT_MSG(WidgetDAO::isWidgetInstalled( + tizenAppId), "Widget is not registered"); + + //success full update + WidgetDAO::updateTizenAppId(tizenAppId, L"backup"); + WidgetDAO::registerWidget(tizenAppId, regInfo2, sec); + WidgetDAO::unregisterWidget(L"backup"); + RUNNER_ASSERT_MSG(WidgetDAO::isWidgetInstalled( + tizenAppId), "Widget is not reregistered"); + WidgetDAO dao(tizenAppId); + RUNNER_ASSERT_MSG( + *dao.getVersion() == L"1.1", "Data widget was not updated"); + RUNNER_ASSERT_MSG( + *dao.getAuthorName() == L"BBB", "Data widget was not updated"); + + + WidgetDAO::unregisterWidget(tizenAppId); +} + +/* + * Name: widget_dao_test_get_widget_tizenAppId_list + * Description: Tests getTizenAppIdList API for backendlib + * Expected: For all position in database should be returned one item in list + */ +RUNNER_TEST(widget_dao_test_get_widget_tizenAppId_list) +{ + TizenAppIdList tizenAppIds = WidgetDAO::getTizenAppIdList(); + RUNNER_ASSERT(tizenAppIds.size() >= 3); +} + +/* + * Name: widget_dao_test_get_widget_list + * Description: Tests getTizenAppIdList API for backendlib + * Expected: For all position in database should be returned one item in list + * Those item should contain valid tizenAppId + */ +RUNNER_TEST(widget_dao_test_get_widget_list) +{ + WidgetDAOReadOnlyList list = WidgetDAOReadOnly::getWidgetList(); + RUNNER_ASSERT(list.size() >= 3); + RUNNER_ASSERT_MSG(!!list.front(), "widget dao exists"); + WidgetDAOReadOnlyPtr dao = list.front(); +} + +/* + * Name: widget_dao_test_get_widget_attributes + * Description: Tests returning basic widget attributes by dao + * Expected: Attributes should match values inserted into database + */ +RUNNER_TEST(widget_dao_test_get_widget_attributes) +{ + { + TizenAppId tizenAppId = L"tizenid201"; + WidgetDAO dao(tizenAppId); + + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getGUID(), "w_id_2000"); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getVersion(), "1.0.0"); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getAuthorName(), "a_name_2000"); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getAuthorEmail(), + "a_email_2000"); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getAuthorHref(), "a_href_2000"); + RUNNER_ASSERT_WHAT_EQUALS(dao.getBaseFolder(), "basef_2000/"); + RUNNER_ASSERT(dao.getWebkitPluginsRequired() == true); + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL(dao.getMinimumWacVersion(), "1.0"); + } +} + +/* + * Name: widget_dao_test_localization + * Description: Tests inserting and returning localization info + * Expected: Values inserted into database should match values received from + * database + */ +RUNNER_TEST(widget_dao_test_localization) +{ + WacSecurityMock sec; + + // icon + WidgetRegisterInfo regInfo; + ConfigParserData::Icon icon(L"icon1"); + icon.width = 10; + icon.height = 10; + LocaleSet locs; + locs.insert(DPL::FromUTF8String("en")); + locs.insert(DPL::FromUTF8String("pl")); + WidgetRegisterInfo::LocalizedIcon locIcon(icon, locs); + regInfo.localizationData.icons.push_back(locIcon); + + //start file + WidgetRegisterInfo::StartFileProperties prop_en; + prop_en.encoding = DPL::FromUTF8String("encoding_en"); + prop_en.type = DPL::FromUTF8String("type_en"); + + WidgetRegisterInfo::StartFileProperties prop_pl; + prop_pl.encoding = DPL::FromUTF8String("encoding_pl"); + prop_pl.type = DPL::FromUTF8String("type_pl"); + + WidgetRegisterInfo::LocalizedStartFile file; + file.path = DPL::FromUTF8String("path"); + file.propertiesForLocales.insert( + std::make_pair(DPL::FromUTF8String("en"), prop_en)); + file.propertiesForLocales.insert( + std::make_pair(DPL::FromUTF8String("pl"), prop_pl)); + regInfo.localizationData.startFiles.push_back(file); + + // register widget + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAO dao(tizenAppId); + + // check localized icons + WidgetDAO::WidgetLocalizedIconList locList = dao.getLocalizedIconList(); + RUNNER_ASSERT(locList.size() == locs.size()); + + // non-localized icon + WidgetDAO::WidgetIconList list = dao.getIconList(); + int iconId = list.front().iconId; + + // compare every icon with the origin + auto locsIt = locs.begin(); + auto iconIt = locList.begin(); + for (; locsIt != locs.end() && iconIt != locList.end(); ++locsIt, + ++iconIt) + { + RUNNER_ASSERT(iconIt->appId == dao.getHandle()); + RUNNER_ASSERT(iconIt->iconId == iconId); + RUNNER_ASSERT(iconIt->widgetLocale == *locsIt); + } + + // localized start file list + WidgetDAO::LocalizedStartFileList fList = dao.getLocalizedStartFileList(); + RUNNER_ASSERT(fList.size() == file.propertiesForLocales.size()); + + int startFileId = dao.getStartFileList().front().startFileId; + + FOREACH(it, fList) + { + RUNNER_ASSERT(it->appId == dao.getHandle()); + auto propIt = file.propertiesForLocales.find(it->widgetLocale); + RUNNER_ASSERT(propIt != file.propertiesForLocales.end()); + RUNNER_ASSERT(it->encoding == propIt->second.encoding); + RUNNER_ASSERT(it->type == propIt->second.type); + RUNNER_ASSERT(it->startFileId == startFileId); + } +} + +/* + * Name: widget_dao_test_register_scp + * Description: Tests inserting and returning scp policy information + * Expected: Value inserted into database should match values received from + * database + */ +RUNNER_TEST(widget_dao_test_register_scp) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + DPL::OptionalString policy = DPL::FromUTF8String("Some awesome csp policy"); + regInfo.configInfo.cspPolicy = policy; + { + // register widget + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + WidgetDAO dao(tizenAppId); + + RUNNER_ASSERT_WHAT_EQUALS_OPTIONAL( + dao.getCspPolicy(), DPL::ToUTF8String(*policy)); + } +} + +/* + * Name: widget_dao_test_register_csp_empty + * Description: Tests inserting and returning empty csp policy + * Expected: Value inserted into database should match values received from + * database + */ +RUNNER_TEST(widget_dao_test_register_csp_empty) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + { + // register widget + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + WidgetDAO dao(tizenAppId); + + RUNNER_ASSERT_MSG(dao.getCspPolicy().IsNull(), "Policy is not null"); + } +} + +/* + * Name: widget_dao_test_widget_privileges_basics + * Description: Tests basic operators of privileges + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_privileges_basics) +{ + ConfigParserData::Privilege f1(DPL::FromUTF8String("a")); + ConfigParserData::Privilege f2(DPL::FromUTF8String("f2")); + ConfigParserData::Privilege f3(DPL::FromUTF8String("f3")); + ConfigParserData::Privilege f1prim(DPL::FromUTF8String("a")); + + RUNNER_ASSERT_MSG(f1 != f2, "features not equal"); + RUNNER_ASSERT_MSG(f2 != f3, "features not equal"); + RUNNER_ASSERT_MSG(f1 != f3, "features not equal"); + RUNNER_ASSERT_MSG(f1 == f1prim, "features equal"); + + RUNNER_ASSERT(f1 >= f1prim); + RUNNER_ASSERT(f1 <= f1prim); + RUNNER_ASSERT(f1 < f2); + RUNNER_ASSERT(f1 <= f2); + RUNNER_ASSERT(f3 > f2); + RUNNER_ASSERT(f3 >= f2); +} + +/* + * Name: widget_dao_test_widget_preferences_basics + * Description: Tests basic operators of preferences + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_preferences_basics) +{ + ConfigParserData::Preference f1(DPL::FromUTF8String("a")); + ConfigParserData::Preference f2(DPL::FromUTF8String("f2")); + ConfigParserData::Preference f3(DPL::FromUTF8String("f3")); + ConfigParserData::Preference f1prim(DPL::FromUTF8String("a")); + + RUNNER_ASSERT_MSG(f1 != f2, "preferences not equal"); + RUNNER_ASSERT_MSG(f2 != f3, "preferences not equal"); + RUNNER_ASSERT_MSG(f1 != f3, "preferences not equal"); + RUNNER_ASSERT_MSG(f1 == f1prim, "preferences equal"); + + RUNNER_ASSERT(f1 >= f1prim); + RUNNER_ASSERT(f1 <= f1prim); + RUNNER_ASSERT(f1 < f2); + RUNNER_ASSERT(f1 <= f2); + RUNNER_ASSERT(f3 > f2); + RUNNER_ASSERT(f3 >= f2); +} + +/* + * Name: widget_dao_test_widget_features_basics + * Description: Tests basic operators of features + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_features_basics) +{ + ConfigParserData::Feature f1(DPL::FromUTF8String("a")); + ConfigParserData::Feature f2(DPL::FromUTF8String("f2")); + ConfigParserData::Feature f3(DPL::FromUTF8String("f3")); + ConfigParserData::Feature f1prim(DPL::FromUTF8String("a")); + + RUNNER_ASSERT_MSG(f1 != f2, "features not equal"); + RUNNER_ASSERT_MSG(f2 != f3, "features not equal"); + RUNNER_ASSERT_MSG(f1 != f3, "features not equal"); + RUNNER_ASSERT_MSG(f1 == f1prim, "features equal"); + + RUNNER_ASSERT(f1 >= f1prim); + RUNNER_ASSERT(f1 <= f1prim); + RUNNER_ASSERT(f1 < f2); + RUNNER_ASSERT(f1 <= f2); + RUNNER_ASSERT(f3 > f2); + RUNNER_ASSERT(f3 >= f2); +} + +/* + * Name: widget_dao_test_widget_icons_basics + * Description: Tests basic operators for icons + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_icons_basics) +{ + ConfigParserData::Icon f1(DPL::FromUTF8String("a")); + ConfigParserData::Icon f2(DPL::FromUTF8String("f2")); + ConfigParserData::Icon f3(DPL::FromUTF8String("f3")); + ConfigParserData::Icon f1prim(DPL::FromUTF8String("a")); + + RUNNER_ASSERT_MSG(f1 != f2, "icons not equal"); + RUNNER_ASSERT_MSG(f2 != f3, "icons not equal"); + RUNNER_ASSERT_MSG(f1 != f3, "icons not equal"); + RUNNER_ASSERT_MSG(f1 == f1prim, "icons equal"); + + RUNNER_ASSERT(f1 >= f1prim); + RUNNER_ASSERT(f1 <= f1prim); + RUNNER_ASSERT(f1 < f2); + RUNNER_ASSERT(f1 <= f2); + RUNNER_ASSERT(f3 > f2); + RUNNER_ASSERT(f3 >= f2); +} + +/* + * Name: widget_dao_test_widget_settings_basics + * Description: Tests basic operators for settings of widget + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_settings_basics) +{ + ConfigParserData::Setting f1(DPL::FromUTF8String("a"), DPL::FromUTF8String("1")); + ConfigParserData::Setting f2(DPL::FromUTF8String("a"), DPL::FromUTF8String("2")); + ConfigParserData::Setting f3(DPL::FromUTF8String("b"), DPL::FromUTF8String("2")); + ConfigParserData::Setting f1prim(DPL::FromUTF8String("a"), DPL::FromUTF8String("1")); + + RUNNER_ASSERT_MSG(f1 != f2, "settings not equal"); + RUNNER_ASSERT_MSG(f2 != f3, "settings not equal"); + RUNNER_ASSERT_MSG(f1 != f3, "settings not equal"); + RUNNER_ASSERT_MSG(f1 == f1prim, "settings equal"); + + RUNNER_ASSERT(f1 >= f1prim); + RUNNER_ASSERT(f1 <= f1prim); + RUNNER_ASSERT(f1 <= f2); + RUNNER_ASSERT(f3 > f2); + RUNNER_ASSERT(f2 < f3); + RUNNER_ASSERT(f3 >= f2); +} + +/* + * Name: widget_dao_test_widget_access_basics + * Description: Tests basic operators for access of widget + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_access_basics) +{ + ConfigParserData::AccessInfo a(DPL::FromUTF8String("a"), true); + ConfigParserData::AccessInfo b(DPL::FromUTF8String("b"), true); + ConfigParserData::AccessInfo a1(DPL::FromUTF8String("a"), true); + ConfigParserData::AccessInfo a2(DPL::FromUTF8String("a"), false); + + RUNNER_ASSERT_MSG(a != b, "access info not equal"); + RUNNER_ASSERT_MSG(a == a1, "access info equal"); + RUNNER_ASSERT_MSG(b == b, "access info equal"); + RUNNER_ASSERT_MSG(a1 != b, "access info are not equal"); + RUNNER_ASSERT_MSG(a1 != a2, "access info are not equal"); + RUNNER_ASSERT(a2 < a1); + RUNNER_ASSERT(a1 < b); +} + +/* + * Name: widget_dao_test_widget_metadata_basics + * Description: Tests basic operators for metadata + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_metadata_basics) +{ + ConfigParserData::Metadata a(DPL::FromUTF8String("a"), DPL::FromUTF8String("1")); + ConfigParserData::Metadata b(DPL::FromUTF8String("b"), DPL::FromUTF8String("1")); + ConfigParserData::Metadata a1(DPL::FromUTF8String("a"), DPL::FromUTF8String("1")); + ConfigParserData::Metadata a2(DPL::FromUTF8String("a"), DPL::FromUTF8String("2")); + + RUNNER_ASSERT_MSG(a != b, "metadata not equal"); + RUNNER_ASSERT_MSG(a == a1, "metadata equal"); + RUNNER_ASSERT_MSG(b == b, "metadata equal"); + RUNNER_ASSERT_MSG(a1 != b, "metadata not equal"); + RUNNER_ASSERT_MSG(a1 != a2, "metadata not equal"); +} + +/* + * Name: widget_dao_test_widget_appcontrolinfo_basics + * Description: Tests basic operators for app control info + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_appcontrolinfo_basics) +{ + ConfigParserData::AppControlInfo a(DPL::FromUTF8String("operation")); + a.m_disposition = ConfigParserData::AppControlInfo::Disposition::WINDOW; + a.m_mimeList.insert(DPL::FromUTF8String("mime")); + a.m_src = DPL::FromUTF8String("src"); + a.m_uriList.insert(DPL::FromUTF8String("uri")); + + ConfigParserData::AppControlInfo a0(DPL::FromUTF8String("operation1")); + a0.m_disposition = ConfigParserData::AppControlInfo::Disposition::WINDOW; + a0.m_mimeList.insert(DPL::FromUTF8String("mime")); + a0.m_src = DPL::FromUTF8String("src"); + a0.m_uriList.insert(DPL::FromUTF8String("uri")); + + ConfigParserData::AppControlInfo a1(DPL::FromUTF8String("operation")); + a1.m_disposition = ConfigParserData::AppControlInfo::Disposition::UNDEFINE; + a1.m_mimeList.insert(DPL::FromUTF8String("mime")); + a1.m_src = DPL::FromUTF8String("src"); + a1.m_uriList.insert(DPL::FromUTF8String("uri")); + + ConfigParserData::AppControlInfo a2(DPL::FromUTF8String("operation")); + a2.m_disposition = ConfigParserData::AppControlInfo::Disposition::WINDOW; + a2.m_mimeList.insert(DPL::FromUTF8String("mime1")); + a2.m_src = DPL::FromUTF8String("src"); + a2.m_uriList.insert(DPL::FromUTF8String("uri")); + + ConfigParserData::AppControlInfo a3(DPL::FromUTF8String("operation")); + a3.m_disposition = ConfigParserData::AppControlInfo::Disposition::WINDOW; + a3.m_mimeList.insert(DPL::FromUTF8String("mime")); + a3.m_src = DPL::FromUTF8String("src1"); + a3.m_uriList.insert(DPL::FromUTF8String("uri")); + + ConfigParserData::AppControlInfo a4(DPL::FromUTF8String("operation")); + a4.m_disposition = ConfigParserData::AppControlInfo::Disposition::WINDOW; + a4.m_mimeList.insert(DPL::FromUTF8String("mime")); + a4.m_src = DPL::FromUTF8String("src"); + a4.m_uriList.insert(DPL::FromUTF8String("uri1")); + + ConfigParserData::AppControlInfo a5(DPL::FromUTF8String("operation")); + a5.m_disposition = ConfigParserData::AppControlInfo::Disposition::WINDOW; + a5.m_mimeList.insert(DPL::FromUTF8String("mime")); + a5.m_src = DPL::FromUTF8String("src"); + a5.m_uriList.insert(DPL::FromUTF8String("uri")); + + RUNNER_ASSERT_MSG(a != a0, "app control info not equal"); + RUNNER_ASSERT_MSG(a != a1, "app control info not equal"); + RUNNER_ASSERT_MSG(a != a2, "app control info not equal"); + RUNNER_ASSERT_MSG(a != a3, "app control info not equal"); + RUNNER_ASSERT_MSG(a != a4, "app control info not equal"); + RUNNER_ASSERT_MSG(a == a5, "app control info equal"); + RUNNER_ASSERT_MSG(a == a, "app control info equal"); +} + +/* + * Name: widget_dao_test_widget_metadata_basics + * Description: Tests basic operators for livebox info + * Expected: operators should behave properly + */ +RUNNER_TEST(widget_dao_test_widget_livebox_basics) +{ + ConfigParserData::LiveboxInfo a; + a.m_icon = DPL::FromUTF8String("icon"); + a.m_liveboxId = DPL::FromUTF8String("id"); + a.m_autoLaunch = DPL::FromUTF8String("auto"); + a.m_updatePeriod = DPL::FromUTF8String("period"); + a.m_primary = DPL::FromUTF8String("primary"); + + ConfigParserData::LiveboxInfo a0; + a0.m_icon = DPL::FromUTF8String("icon0"); + a0.m_liveboxId = DPL::FromUTF8String("id"); + a0.m_autoLaunch = DPL::FromUTF8String("auto"); + a0.m_updatePeriod = DPL::FromUTF8String("period"); + a0.m_primary = DPL::FromUTF8String("primary"); + + ConfigParserData::LiveboxInfo a1; + a1.m_icon = DPL::FromUTF8String("icon"); + a1.m_liveboxId = DPL::FromUTF8String("id0"); + a1.m_autoLaunch = DPL::FromUTF8String("auto"); + a1.m_updatePeriod = DPL::FromUTF8String("period"); + a1.m_primary = DPL::FromUTF8String("primary"); + + ConfigParserData::LiveboxInfo a2; + a2.m_icon = DPL::FromUTF8String("icon"); + a2.m_liveboxId = DPL::FromUTF8String("id"); + a2.m_autoLaunch = DPL::FromUTF8String("auto0"); + a2.m_updatePeriod = DPL::FromUTF8String("period"); + a2.m_primary = DPL::FromUTF8String("primary"); + + ConfigParserData::LiveboxInfo a3; + a3.m_icon = DPL::FromUTF8String("icon"); + a3.m_liveboxId = DPL::FromUTF8String("id"); + a3.m_autoLaunch = DPL::FromUTF8String("auto"); + a3.m_updatePeriod = DPL::FromUTF8String("period0"); + a3.m_primary = DPL::FromUTF8String("primary"); + + ConfigParserData::LiveboxInfo a4; + a4.m_icon = DPL::FromUTF8String("icon"); + a4.m_liveboxId = DPL::FromUTF8String("id"); + a4.m_autoLaunch = DPL::FromUTF8String("auto"); + a4.m_updatePeriod = DPL::FromUTF8String("period"); + a4.m_primary = DPL::FromUTF8String("primary0"); + + ConfigParserData::LiveboxInfo a5; + a5.m_icon = DPL::FromUTF8String("icon"); + a5.m_liveboxId = DPL::FromUTF8String("id"); + a5.m_autoLaunch = DPL::FromUTF8String("auto"); + a5.m_updatePeriod = DPL::FromUTF8String("period"); + a5.m_primary = DPL::FromUTF8String("primary"); + + const DPL::String s1 = DPL::FromUTF8String("1"); + const DPL::String s2 = DPL::FromUTF8String("2"); + + ConfigParserData::LiveboxInfo a10; + a10.m_icon = DPL::FromUTF8String("icon"); + a10.m_liveboxId = DPL::FromUTF8String("id"); + a10.m_autoLaunch = DPL::FromUTF8String("auto"); + a10.m_updatePeriod = DPL::FromUTF8String("period"); + a10.m_primary = DPL::FromUTF8String("primary"); + a10.m_label.push_back(std::pair(s1, s1)); + + ConfigParserData::LiveboxInfo a11; + a11.m_icon = DPL::FromUTF8String("icon"); + a11.m_liveboxId = DPL::FromUTF8String("id"); + a11.m_autoLaunch = DPL::FromUTF8String("auto"); + a11.m_updatePeriod = DPL::FromUTF8String("period"); + a11.m_primary = DPL::FromUTF8String("primary"); + a11.m_label.push_back(std::pair(s1, s2)); + a11.m_label.push_back(std::pair(s1, s2)); + + ConfigParserData::LiveboxInfo a12; + a12.m_icon = DPL::FromUTF8String("icon"); + a12.m_liveboxId = DPL::FromUTF8String("id"); + a12.m_autoLaunch = DPL::FromUTF8String("auto"); + a12.m_updatePeriod = DPL::FromUTF8String("period"); + a12.m_primary = DPL::FromUTF8String("primary"); + a12.m_label.push_back(std::pair(s1, s1)); + + RUNNER_ASSERT_MSG(a != a0, "livebox info not equal"); + RUNNER_ASSERT_MSG(a != a1, "livebox info not equal"); + RUNNER_ASSERT_MSG(a != a2, "livebox info not equal"); + RUNNER_ASSERT_MSG(a != a3, "livebox info not equal"); + RUNNER_ASSERT_MSG(a != a4, "livebox info not equal"); + RUNNER_ASSERT_MSG(a == a5, "livebox info equal"); + RUNNER_ASSERT_MSG(a == a, "livebox info equal"); + RUNNER_ASSERT_MSG(a10 != a11, "livebox info not equal"); + RUNNER_ASSERT_MSG(a10 == a12, "livebox info equal"); +} + +/* + * Name: widget_dao_test_get_widget_by_guid + * Description: Tests creating WidgetDAO using GUID + * Expected: Correct WidgetDAO should be created + */ +RUNNER_TEST(widget_dao_test_get_widget_by_guid) +{ + WidgetDAO dao(DPL::OptionalString(L"w_id_2000")); + RUNNER_ASSERT(dao.getTizenAppId() == L"tizenid201"); +} + +/* + * Name: widget_dao_test_set_tizen_app_id + * Description: Tests changing TizenAppId + * Expected: Change should be possible + */ +RUNNER_TEST(widget_dao_test_set_tizen_app_id) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + TizenAppId originaltizenAppId = REGISTER_WIDGET(regInfo, sec); + TizenAppId changedTizenAppId = L"changedTizenAppId"; + + TizenAppIdList ids = WidgetDAO::getTizenAppIdList(); + RUNNER_ASSERT(std::count(ids.begin(),ids.end(),originaltizenAppId) == 1); + + //Change tizenAppId + WidgetDAO dao(originaltizenAppId); + dao.setTizenAppId(changedTizenAppId); + + ids = WidgetDAO::getTizenAppIdList(); + RUNNER_ASSERT(std::count(ids.begin(), ids.end(), originaltizenAppId) == 0); + RUNNER_ASSERT(std::count(ids.begin(), ids.end(), changedTizenAppId) == 1); + + bool exceptionCaught = checkException < WidgetDAOReadOnly::Exception::WidgetNotExist > ([&]() { + WidgetDAO dao2(originaltizenAppId); + //Changing should fail because original tizenAppId doesn't exist any more. + dao2.setTizenAppId(changedTizenAppId); + }); + RUNNER_ASSERT(exceptionCaught); + + WidgetDAO::unregisterWidget(changedTizenAppId); + ids = WidgetDAO::getTizenAppIdList(); + RUNNER_ASSERT(std::count(ids.begin(),ids.end(),originaltizenAppId) == 0); + RUNNER_ASSERT(std::count(ids.begin(),ids.end(),changedTizenAppId) == 0); + +} + +/* + * Name: widget_dao_test_update_feature_reject_status + * Description: Tests updating feature reject status + * Expected: Reject status should be properly updated + */ +RUNNER_TEST(widget_dao_test_update_feature_reject_status) +{ + WidgetDAO dao(L"tizenid202"); + DbWidgetFeatureSet featureSet = dao.getFeaturesList(); + + RUNNER_ASSERT(featureSet.size() == 1); + DbWidgetFeature feature = *featureSet.begin(); + RUNNER_ASSERT(!feature.rejected); + + feature.rejected = true; + dao.updateFeatureRejectStatus(feature); + + featureSet = dao.getFeaturesList(); + RUNNER_ASSERT(featureSet.size() == 1); + DbWidgetFeature feature2 = *featureSet.begin(); + RUNNER_ASSERT(feature.rejected); + + feature2.rejected = false; + dao.updateFeatureRejectStatus(feature2); +} + +/* + * Name: widget_dao_test_register_widget_allow_navigation + * Description: Tests AllowNavigationInfo registration + * Expected: AllowNavigationInfo registration should be possible + */ +RUNNER_TEST(widget_dao_test_register_widget_allow_navigation) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + ConfigParserData::AllowNavigationInfo navigationInfo1(L"scheme1", L"host1"); + ConfigParserData::AllowNavigationInfo navigationInfo2(L"scheme2", L"host2"); + regInfo.configInfo.allowNavigationInfoList.push_back(navigationInfo1); + regInfo.configInfo.allowNavigationInfoList.push_back(navigationInfo2); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAOReadOnly dao(tizenAppId); + WidgetAllowNavigationInfoList navigationList; + dao.getWidgetAllowNavigationInfo(navigationList); + + RUNNER_ASSERT(navigationList.size() == 2); + RUNNER_ASSERT( + std::count_if(navigationList.begin(), navigationList.end(), [] (const WidgetAllowNavigationInfo& navInfo) + { return navInfo.host == L"host1" && navInfo.scheme == L"scheme1"; }) == 1); + RUNNER_ASSERT( + std::count_if(navigationList.begin(), navigationList.end(), [] (const WidgetAllowNavigationInfo& navInfo) + { return navInfo.host == L"host2" && navInfo.scheme == L"scheme2"; }) == 1); + +} + +/* + * Name: widget_dao_test_register_external_locations + * Description: Tests ExternalLocation registration + * Expected: ExternalLocation registration should be possible + */ +RUNNER_TEST(widget_dao_test_register_external_locations) +{ + WacSecurityMock sec; + WidgetRegisterInfo regInfo; + regInfo.externalLocations.push_back("location1"); + regInfo.externalLocations.push_back("location2"); + + TizenAppId tizenAppId = REGISTER_WIDGET(regInfo, sec); + + WidgetDAOReadOnly dao(tizenAppId); + ExternalLocationList locationList = dao.getWidgetExternalLocations(); + + RUNNER_ASSERT(locationList.size() == 2); + RUNNER_ASSERT(std::count(locationList.begin(), locationList.end(), "location1") == 1); + RUNNER_ASSERT(std::count(locationList.begin(), locationList.end(), "location2") == 1); +} + + /* + * Name: widget_dao_test_get_tz_app_id + * Description: Tests getTizenAppId functions + * Expected: TizenAppId is correctly fetched for correct widgets, exception for not existing. + */ +RUNNER_TEST(widget_dao_test_get_tz_app_id) +{ + //No such widget + RUNNER_ASSERT_EXCEPTION(WidgetDAOReadOnly::Exception::WidgetNotExist, WidgetDAOReadOnly::getTizenAppId(1234); ); + + TizenAppId appId = WidgetDAOReadOnly::getTizenAppId(2001); + RUNNER_ASSERT(L"tizenid202" == appId); + + RUNNER_ASSERT_EXCEPTION(WidgetDAOReadOnly::Exception::WidgetNotExist, WidgetDAOReadOnly::getTizenAppId(L"no_such_widget"); ); + + appId = WidgetDAOReadOnly::getTizenAppId(L"pkgid202"); + RUNNER_ASSERT(L"tizenid202" == appId); +} + +/* + * Name: widget_dao_test_get_tz_pkg_id + * Description: Tests getTizenPkgId functions + * Expected: TizenPkgId is correctly fetched for correct widgets, exception for not existing. + */ +RUNNER_TEST(widget_dao_test_get_tz_pkg_id) +{ + //No such widget + RUNNER_ASSERT_EXCEPTION(WidgetDAOReadOnly::Exception::WidgetNotExist, WidgetDAOReadOnly::getTizenPkgId(1234); ); + + + TizenPkgId pkgId = WidgetDAOReadOnly::getTizenPkgId(2001); + RUNNER_ASSERT(L"pkgid202" == pkgId); + + RUNNER_ASSERT_EXCEPTION(WidgetDAOReadOnly::Exception::WidgetNotExist, WidgetDAOReadOnly::getTizenPkgId(L"no_such_widget");); + + pkgId = WidgetDAOReadOnly::getTizenPkgId(L"tizenid202"); + RUNNER_ASSERT(L"pkgid202" == pkgId); +} + +/* + * Name: widget_dao_test_get_property_key + * Description: Tests getPropertyKeyList function + * Expected: Property keys are fetched correctly. + */ +RUNNER_TEST(widget_dao_test_get_property_key) +{ + WidgetDAOReadOnly dao(L"tizenid201"); + PropertyDAOReadOnly::WidgetPropertyKeyList propertyKeys = dao.getPropertyKeyList(); + + RUNNER_ASSERT(propertyKeys.size() == 2); + RUNNER_ASSERT(std::count(propertyKeys.begin(), propertyKeys.end(), L"key1_for_2000") == 1); + RUNNER_ASSERT(std::count(propertyKeys.begin(), propertyKeys.end(), L"key2_for_2000") == 1); +} + +/* + * Name: widget_dao_test_get_property_value + * Description: Tests getPropertyValue function + * Expected: Property key values are fetched correctly. + */ +RUNNER_TEST(widget_dao_test_get_property_value) +{ + WidgetDAOReadOnly dao(L"tizenid201"); + + RUNNER_ASSERT(dao.getPropertyValue(L"key1_for_2000") == L"value_for_key1_2000"); + RUNNER_ASSERT(dao.getPropertyValue(L"key2_for_2000") == L"value_for_key2_2000"); + RUNNER_ASSERT(dao.getPropertyValue(L"not_existing").IsNull()); + RUNNER_ASSERT(dao.getPropertyValue(L"").IsNull()); +} + +/* + * Name: widget_dao_test_get_property_read_flag + * Description: Tests checkPropertyReadFlag function + * Expected: Property read flags values are fetched correctly. + */ +RUNNER_TEST(widget_dao_test_get_property_read_flag) +{ + WidgetDAOReadOnly dao(L"tizenid201"); + + RUNNER_ASSERT(dao.checkPropertyReadFlag(L"key1_for_2000") == 0); + RUNNER_ASSERT(dao.checkPropertyReadFlag(L"key2_for_2000") == 0); + RUNNER_ASSERT(dao.checkPropertyReadFlag(L"not_existing").IsNull()); + RUNNER_ASSERT(dao.checkPropertyReadFlag(L"").IsNull()); +} + +/* + * Name: widget_dao_test_get_pkg_id_list + * Description: Tests getTizenPkgIdList function + * Expected: All pkg ids are returned. + */ +RUNNER_TEST(widget_dao_test_get_pkg_id_list) +{ + TizenPkgIdList pkgIds = WidgetDAOReadOnly::getTizenPkgIdList(); + + RUNNER_ASSERT(pkgIds.size() == 4); + RUNNER_ASSERT(std::count(pkgIds.begin(), pkgIds.end(), L"pkgid201") == 1); + RUNNER_ASSERT(std::count(pkgIds.begin(), pkgIds.end(), L"pkgid202") == 1); + RUNNER_ASSERT(std::count(pkgIds.begin(), pkgIds.end(), L"") == 2); +} + +/* + * Name: widget_dao_test_get_back_supported + * Description: Tests getBackSupported function + * Expected: Back supported information is fetched properly. + */ +RUNNER_TEST(widget_dao_test_get_back_supported) +{ + WidgetDAOReadOnly dao1(L"tizenid201"); + RUNNER_ASSERT(dao1.getBackSupported()); + + WidgetDAOReadOnly dao2(L"tizenid202"); + RUNNER_ASSERT(!dao2.getBackSupported()); +} + +/* + * Name: widget_dao_test_get_csp_policy_report + * Description: Tests getCspPolicyReportOnly function + * Expected: CSP policy information is fetched properly. + */ +RUNNER_TEST(widget_dao_test_get_csp_policy_report) +{ + WidgetDAOReadOnly dao1(L"tizenid201"); + RUNNER_ASSERT(DPL::OptionalString(L"policy_report201") == dao1.getCspPolicyReportOnly()); + + WidgetDAOReadOnly dao2(L"tizenid202"); + RUNNER_ASSERT(DPL::OptionalString(L"policy_report202") == dao2.getCspPolicyReportOnly()); +} + +/* + * Name: widget_dao_test_get_install_time + * Description: Tests getInstallTime function + * Expected: Installation time is fetched properly. + */ +RUNNER_TEST(widget_dao_test_get_install_time) +{ + WidgetDAOReadOnly dao1(L"tizenid201"); + RUNNER_ASSERT(1256 == dao1.getInstallTime()); + + WidgetDAOReadOnly dao2(L"tizenid202"); + RUNNER_ASSERT(5687 == dao2.getInstallTime()); +} + +/* + * Name: widget_dao_test_get_icon_language_tags + * Description: Tests getIconLanguageTags function + * Expected: Information about icon localization is fetched properly. + */ +RUNNER_TEST(widget_dao_test_get_icon_language_tags) +{ + WidgetDAOReadOnly dao1(L"tizenid201"); + LanguageTags languageTags = dao1.getIconLanguageTags(); + + RUNNER_ASSERT(2 == languageTags.size()); + RUNNER_ASSERT(std::count(languageTags.begin(), languageTags.end(), L"en") == 1); + RUNNER_ASSERT(std::count(languageTags.begin(), languageTags.end(), L"pl") == 1); +} + +#undef RUNNER_ASSERT_WHAT_EQUALS diff --git a/tests/dao/TestCases_WidgetInterfaceDAO.cpp b/tests/dao/TestCases_WidgetInterfaceDAO.cpp new file mode 100644 index 0000000..fae5e11 --- /dev/null +++ b/tests/dao/TestCases_WidgetInterfaceDAO.cpp @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases_widgetInterfaceDAO.cpp + * @author Dominik Duda (d.duda@samsung.com) + * @version 1.0 + * @brief This file contains tests for WidgetInterfaceDAO class. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WIDGET_ID 2000 + +using namespace WrtDB; +using namespace WidgetInterfaceDB; + +RUNNER_TEST_GROUP_INIT(DAO) + +/* + * Name: widget_interface_dao_test_01_initialization + * Description: Tests database creation. + * Expected: The database should be successfully created. + */ +RUNNER_TEST(widget_interface_dao_test_01_initialization) +{ + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_01_initialization_Exception + * Description: Tests if an exception will be thrown when incorrect widgetID + * is used. + * Expected: The exception should be thrown. + */ +RUNNER_TEST(widget_interface_dao_test_01_initialization_Exception) +{ + Try + { + WidgetInterfaceDAO dao(5555000); + } + Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) + { + RUNNER_ASSERT_MSG(true, _rethrown_exception.GetMessage()); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_02_readValue + * Description: Tests getting a value for a given key. + * Expected: The desired value should be returned. + */ +RUNNER_TEST(widget_interface_dao_test_02_readValue) +{ + DPL::Optional value; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + value = dao.getValue("key1_for_2000"); + + RUNNER_ASSERT(value == "value_for_key1_2000"); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_02_readValue_badKey + * Description: Tests if an empty value is returned for an incorrect key. + * Expected: The empty (NULL) value should be returned. + */ +RUNNER_TEST(widget_interface_dao_test_02_readValue_badKey) +{ + DPL::Optional value; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + value = dao.getValue("key1_for_200011111"); + + RUNNER_ASSERT(value.IsNull()); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_03_setItem + * Description: Tests if a new readonly item can be add into a database. + * Expected: The new item should be successfully added. + */ +RUNNER_TEST(widget_interface_dao_test_03_setItem) +{ + DPL::Optional value; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + dao.setItem("key3_for_2000", "value_for_key3_2000", 1); + + value = dao.getValue("key3_for_2000"); + + RUNNER_ASSERT(value == "value_for_key3_2000"); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_03_setItem_Exception + * Description: Tests if a readonly item can be overwritten. + * Expected: An exception should be thrown. + */ +RUNNER_TEST(widget_interface_dao_test_03_setItem_Exception) +{ + DPL::Optional value; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + dao.setItem("key3_for_2000", "value_for_key3_2000", 1); + + RUNNER_ASSERT_MSG(false, "Readonly value should not be overwritten"); + } + Catch(WidgetInterfaceDAO::Exception::LocalStorageValueNoModifableException) + { + RUNNER_ASSERT(true); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_04_setItem + * Description: Tests inserting a new item with non readonly and fromConfigXML + * properties set. + * Expected: The new item should be added. + */ +RUNNER_TEST(widget_interface_dao_test_04_setItem) +{ + DPL::Optional value; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + dao.setItem("key4_for_2000", "value_for_key4_2000", 0, 1); + + value = dao.getValue("key4_for_2000"); + + RUNNER_ASSERT(value == "value_for_key4_2000"); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_05_getKeyByIndex + * Description: Tests getting a key by a given index. + * Expected: The key should be successfully read. + */ +RUNNER_TEST(widget_interface_dao_test_05_getKeyByIndex) +{ + std::string key; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + key = dao.getKeyByIndex(1); + + RUNNER_ASSERT(key == "key2_for_2000"); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_05_getKeyByIndex_badIndex_01 + * Description: Tests if an exception will be thrown when getting a key + * by a negative index. + * Expected: An exception should be thrown. + */ +RUNNER_TEST(widget_interface_dao_test_05_getKeyByIndex_badIndex_01) +{ + std::string key; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + key = dao.getKeyByIndex(-111); + + RUNNER_ASSERT_MSG(false, "A key should not be returned for " + "a negative index!"); + } + Catch(WidgetInterfaceDAO::Exception::InvalidArgumentException) + { + RUNNER_ASSERT_MSG(true, _rethrown_exception.GetMessage()); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_05_getKeyByIndex_badIndex_02 + * Description: Tests if an exception will be thrown when getting a key + * by a non existing index. + * Expected: An exception should be thrown. + */ +RUNNER_TEST(widget_interface_dao_test_05_getKeyByIndex_badIndex_02) +{ + std::string key; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + key = dao.getKeyByIndex(1111); + + RUNNER_ASSERT_MSG(false, "A key should not be returned for " + "a non existing index!"); + } + Catch(WidgetInterfaceDAO::Exception::InvalidArgumentException) + { + RUNNER_ASSERT(true); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_06_removeItem + * Description: Tests removing an item for a given key. + * Expected: An item should be successfully removed. The table size should be + * smaller after removing. + */ +RUNNER_TEST(widget_interface_dao_test_06_removeItem) +{ + std::string key; + size_t sizeBefore, sizeAfter; + DPL::Optional value; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + sizeBefore = dao.getStorageSize(); + + if (sizeBefore == 0) + { + RUNNER_ASSERT_MSG(false, "Database is empty!"); + return; + } + + dao.removeItem("key4_for_2000"); + + sizeAfter = dao.getStorageSize(); + value = dao.getValue("key4_for_2000"); + + RUNNER_ASSERT(sizeAfter == sizeBefore - 1); + RUNNER_ASSERT(value.IsNull()); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_06_removeItem_Exception + * Description: Tests if an exception will be thrown when a readonly item + * is removed. + * Expected: An exception should be thrown. + */ +RUNNER_TEST(widget_interface_dao_test_06_removeItem_Exception) +{ + WidgetInterfaceDAO* dao = NULL; + DPL::Optional value; + size_t sizeBefore, sizeAfter; + + Try + { + dao = new WidgetInterfaceDAO(WIDGET_ID); + + sizeBefore = dao->getStorageSize(); + + if (sizeBefore == 0) + { + RUNNER_ASSERT_MSG(false, "Database is empty!"); + return; + } + + dao->removeItem("key3_for_2000"); + + RUNNER_ASSERT_MSG(false, "A readonly item should not be removed!"); + } + Catch(WidgetInterfaceDAO::Exception::LocalStorageValueNoModifableException) + { + sizeAfter = dao->getStorageSize(); + value = dao->getValue("key3_for_2000"); + + RUNNER_ASSERT(sizeAfter == sizeBefore); + RUNNER_ASSERT(value == "value_for_key3_2000"); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } + + if (dao != NULL) + delete dao; +} + +/* + * Name: widget_interface_dao_test_07_clear + * Description: Tests removing all non readonly rows from the table. + * Expected: The size of the table should be smaller than before removing rows. + */ +RUNNER_TEST(widget_interface_dao_test_07_clear) +{ + size_t sizeBefore, sizeAfter; + DPL::Optional value; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + sizeBefore = dao.getStorageSize(); + dao.clear(false); + + sizeAfter = dao.getStorageSize(); + value = dao.getValue("key3_for_2000"); + + RUNNER_ASSERT(sizeAfter == 1); + RUNNER_ASSERT(sizeAfter < sizeBefore); + RUNNER_ASSERT(value == "value_for_key3_2000"); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} + +/* + * Name: widget_interface_dao_test_07_clearAll + * Description: Tests removing all rows from the table. + * Expected: The size of the table should be 0. + */ +RUNNER_TEST(widget_interface_dao_test_07_clearAll) +{ + size_t sizeAfter; + + Try + { + WidgetInterfaceDAO dao(WIDGET_ID); + + dao.clear(true); + sizeAfter = dao.getStorageSize(); + + RUNNER_ASSERT(sizeAfter == 0); + } + Catch(WidgetInterfaceDAO::Exception::DatabaseError) + { + RUNNER_ASSERT_MSG(false, _rethrown_exception.GetMessage()); + } +} diff --git a/tests/dao/tests_dao.cpp b/tests/dao/tests_dao.cpp new file mode 100644 index 0000000..ae3c7cd --- /dev/null +++ b/tests/dao/tests_dao.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file tests_plugin_dao.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains tests for plugin dao class. + */ + +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + int ret = system("/usr/bin/wrt_dao_tests_prepare_db.sh start"); + if (ret != 0) { + LogError("Preparation script has return error: " << ret + << ". Quitting"); + return -1; + } + + WrtDB::WrtDatabase::attachToThreadRW(); + CustomHandlerDB::Interface::attachDatabaseRW(); + + LogDebug("Starting tests"); + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, + argv); + + CustomHandlerDB::Interface::detachDatabase(); + WrtDB::WrtDatabase::detachFromThread(); + + ret = system("/usr/bin/wrt_dao_tests_prepare_db.sh stop"); + if (ret != 0) { + LogError("Finalization script has return error: " << ret); + return -1; + } + return status; +} diff --git a/tests/dao/wrt_dao_tests_prepare_db.sh b/tests/dao/wrt_dao_tests_prepare_db.sh new file mode 100755 index 0000000..4bb3f0e --- /dev/null +++ b/tests/dao/wrt_dao_tests_prepare_db.sh @@ -0,0 +1,151 @@ +#!/bin/sh +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +WRT_DB=/opt/dbspace/.wrt.db +WRT_DB_BCK=/tmp/wrt.db_backup + +if [ "x$1" == "xstart" ]; then + echo start; + cp $WRT_DB $WRT_DB_BCK + wrt_commons_create_clean_db.sh; + + #simple plugins + INS_MIN_PLUGINPROP="insert into PluginProperties(PluginPropertiesId, InstallationState, PluginLibraryName" + INS_ALL_PLUGINPROP="insert into PluginProperties(PluginPropertiesId, InstallationState, PluginLibraryName, PluginLibraryPath)" + INS_PLUGIN_OBJECTS="insert into PluginImplementedObjects(PluginObject, PluginPropertiesId)" + INS_PLUGIN_DEPEND="insert into PluginDependencies(PluginPropertiesId, RequiredPluginPropertiesId)" + + sqlite3 $WRT_DB "${INS_MIN_PLUGINPROP}) VALUES(1, 1, 'plugin1')"; + sqlite3 $WRT_DB "${INS_MIN_PLUGINPROP}, PluginLibraryPath) VALUES(2, 1, 'plugin2', 'path_to_plugin2')"; + sqlite3 $WRT_DB "${INS_MIN_PLUGINPROP}) VALUES(3, 1, 'plugin3')"; + sqlite3 $WRT_DB "${INS_ALL_PLUGINPROP} VALUES(4, 1, 'p4', 'path_to_p4')"; + sqlite3 $WRT_DB "${INS_ALL_PLUGINPROP} VALUES(5, 1, 'p5', 'path_to_p5')"; + + #plugin dependendencies + sqlite3 $WRT_DB "${INS_PLUGIN_DEPEND} VALUES(1, 5)"; + sqlite3 $WRT_DB "${INS_PLUGIN_DEPEND} VALUES(1, 4)"; + sqlite3 $WRT_DB "${INS_PLUGIN_DEPEND} VALUES(4, 2)"; + + #plugin implemented objects + #sqlite3 $WRT_DB "${INS_PLUGIN_OBJECTS} VALUES(1, )"; + sqlite3 $WRT_DB "${INS_PLUGIN_OBJECTS} VALUES('', 2)"; + sqlite3 $WRT_DB "${INS_PLUGIN_OBJECTS} VALUES('Plugin_3_Object_A', 3)"; + sqlite3 $WRT_DB "${INS_PLUGIN_OBJECTS} VALUES('Plugin_4_Object_A', 4)"; + sqlite3 $WRT_DB "${INS_PLUGIN_OBJECTS} VALUES('Plugin_4_Object_B', 4)"; + sqlite3 $WRT_DB "${INS_PLUGIN_OBJECTS} VALUES('Plugin_4_Object_C', 4)"; + sqlite3 $WRT_DB "${INS_PLUGIN_OBJECTS} VALUES('Plugin_5_Object_A', 5)"; + + #simple features + INS_ALL_FEATURESLIST="insert into FeaturesList(FeatureUUID, FeatureName, PluginPropertiesId)" + sqlite3 $WRT_DB "${INS_ALL_FEATURESLIST} VALUES(1, 'feature1', 1)"; + sqlite3 $WRT_DB "${INS_ALL_FEATURESLIST} VALUES(2, 'feature2', 4)"; + sqlite3 $WRT_DB "${INS_ALL_FEATURESLIST} VALUES(3, 'feature3', 4)"; + sqlite3 $WRT_DB "${INS_ALL_FEATURESLIST} VALUES(4, 'feature4', 4)"; + + #device capabilities + INS_ALL_DEVICECAPS="insert into DeviceCapabilities(DeviceCapID, DeviceCapName, DeviceCapDefaultValue)" + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPS} VALUES(1, 'devicecap1', 1)"; + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPS} VALUES(2, 'devicecap2', 2)"; + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPS} VALUES(3, 'devicecap3', 3)"; + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPS} VALUES(4, 'devicecap4', 4)"; + + #device capabilities proxy + INS_ALL_DEVICECAPSPROXY="insert into FeatureDeviceCapProxy(DeviceCapID, FeatureUUID)" + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPSPROXY} VALUES(1, 1)"; + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPSPROXY} VALUES(1, 2)"; + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPSPROXY} VALUES(2, 2)"; + sqlite3 $WRT_DB "${INS_ALL_DEVICECAPSPROXY} VALUES(3, 3)"; + + #Widgets + INS_ALL_WIDGETEXT="insert into WidgetExtendedInfo(app_id, install_time)" + INS_ALL_WIDGET="insert into WidgetInfo(app_id, widget_id, widget_version, widget_width, widget_height, author_name, author_email, author_href, base_folder, webkit_plugins_required, wac_signed, min_version, tizen_pkgid, tizen_appid, back_supported, csp_policy_report_only)" + INS_ALL_WIDGET_LOC="insert into LocalizedWidgetInfo(app_id, widget_locale, widget_name, widget_shortname, widget_description, widget_license, widget_license_file, widget_license_href)" + INS_ALL_WIDGET_ICONS="insert into WidgetIcon(app_id, icon_src, icon_width, icon_height)" + INS_ALL_WIDGET_LOC_ICONS="insert into WidgetLocalizedIcon(app_id, icon_id, widget_locale)" + INS_ALL_WIDGET_STARTFILE="insert into WidgetStartFile(app_id, src)" + INS_ALL_WIDGET_LOC_STARTFILE="insert into WidgetLocalizedStartFile(app_id, start_file_id, widget_locale, type, encoding)" + INS_ALL_WIDGET_DEFPREF="insert into WidgetDefaultPreference(app_id, key_name, key_value, readonly)" + INS_ALL_WIDGET_PREF="insert into WidgetPreference(app_id,tizen_appid, key_name, key_value, readonly)" + INS_ALL_WIDGET_FEATURE="insert into WidgetFeature(widget_feature_id, app_id, name, rejected)" + INS_ALL_WIDGET_WINMODES="insert into WidgetWindowModes(app_id, window_mode)" + INS_ALL_WIDGET_WARP="insert into WidgetWARPInfo(app_id, iri, subdomain_access)" + INS_ALL_WIDGET_CERT="insert into WidgetCertificateFingerprint(app_id, owner, chainid, type, md5_fingerprint, sha1_fingerprint, common_name)" + INS_ALL_WIDGET_POWDERLEV="insert into PowderLevels(app_id, category, level)" + INS_ALL_WIDGET_POWDERLEV_CONT="insert into PowderLevelContexts(levelid, context)" + + + sqlite3 $WRT_DB "${INS_ALL_WIDGET} VALUES(2000, 'w_id_2000', '1.0.0', 100, 200, 'a_name_2000', 'a_email_2000', 'a_href_2000', 'basef_2000', 1, 1, '1.0', 'pkgid201', 'tizenid201', 1, 'policy_report201')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET} VALUES(2001, 'w_id_2001', '2.0.0', 100, 200, 'a_name_2001', 'a_email_2001', 'a_href_2001', 'basef_2001', 1, 1, '0.5', 'pkgid202', 'tizenid202', 0, 'policy_report202')"; + sqlite3 $WRT_DB "insert into WidgetInfo(app_id, back_supported, tizen_appid) VALUES(2002, 0, 'tizenid203')"; + sqlite3 $WRT_DB "insert into WidgetInfo(app_id, back_supported, tizen_appid) VALUES(2003, 0, 'tizenid204')"; # for properties tests + + sqlite3 $WRT_DB "${INS_ALL_WIDGETEXT} VALUES(2000, 1256)"; + sqlite3 $WRT_DB "${INS_ALL_WIDGETEXT} VALUES(2001, 5687)"; + sqlite3 $WRT_DB "insert into WidgetExtendedInfo(app_id) VALUES(2002)"; + sqlite3 $WRT_DB "insert into WidgetExtendedInfo(app_id) VALUES(2003)"; + + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC} VALUES(2000, 'en', 'w_name_2000_en', 'w_shortname_2000_en', 'w_desc_2000_en', 'w_lic_2000_en', 'w_licf_2000_en', 'w_lic_href_2000_en')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC} VALUES(2000, 'pl', 'w_name_2000_pl', 'w_shortname_2000_pl', 'w_desc_2000_pl', 'w_lic_2000_pl', 'w_licf_2000_pl', 'w_lic_href_2000_pl')"; + sqlite3 $WRT_DB "insert into LocalizedWidgetInfo(app_id, widget_locale) VALUES(2002, 'en')"; + sqlite3 $WRT_DB "insert into LocalizedWidgetInfo(app_id, widget_locale) VALUES(2003, 'en')"; + + sqlite3 $WRT_DB "${INS_ALL_WIDGET_ICONS} VALUES(2000, 'icon_src_2000', 50, 50)"; + sqlite3 $WRT_DB "insert into WidgetIcon(app_id, icon_src) VALUES(2002, 'icon_src_2002')"; + + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC_ICONS} VALUES(2000, 1, 'en')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC_ICONS} VALUES(2000, 1, 'pl')"; + + sqlite3 $WRT_DB "${INS_ALL_WIDGET_STARTFILE} VALUES(2000, 'start_file_2000')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_STARTFILE} VALUES(2001, 'start_file_2001')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_STARTFILE} VALUES(2002, 'start_file_2002')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_STARTFILE} VALUES(2003, 'start_file_2003')"; + + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC_STARTFILE} VALUES(2000, 1, 'en', '', '')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC_STARTFILE} VALUES(2001, 2, 'en', '', '')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC_STARTFILE} VALUES(2002, 3, 'en', '', '')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_LOC_STARTFILE} VALUES(2003, 4, 'en', '', '')"; + + #widget properties + sqlite3 $WRT_DB "${INS_ALL_WIDGET_PREF} VALUES(2000,'tizenid201', 'key1_for_2000', 'value_for_key1_2000', 0)"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_PREF} VALUES(2000,'tizenid201', 'key2_for_2000', 'value_for_key2_2000', 0)"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_PREF} VALUES(2001,'tizenid202', 'key1_for_2001', 'value1_for_key_2001', 1)"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_PREF} VALUES(2002,'tizenid203', 'key1_for_2002', 'value1_for_key_2002', 0)"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET_PREF} VALUES(2002,'tizenid203', 'key2_for_2002', 'value2_for_key_2002', 1)"; + + sqlite3 $WRT_DB "${INS_ALL_WIDGET_FEATURE} VALUES(1, 2001, 'feature_name', 0)"; + + #create if not exists and fix autoincrement value + sqlite3 $WRT_DB "INSERT INTO WidgetInfo(tizen_appid) VALUES('temp')"; + sqlite3 $WRT_DB "DELETE FROM WidgetInfo WHERE tizen_appid = 'temp'"; + sqlite3 $WRT_DB "UPDATE sqlite_sequence SET seq = 2004 WHERE name = 'WidgetInfo'"; + + mkdir "/opt/usr/apps/testWidget123" + mkdir "/opt/usr/apps/testWidget123/data" + mkdir "/opt/usr/apps/pkgid201" + mkdir "/opt/usr/apps/pkgid201/data" + + exit $? + +elif [ "x$1" == "xstop" ]; then + echo stop; + cp $WRT_DB_BCK $WRT_DB + rm -r "/opt/usr/apps/testWidget123" + rm -r "/opt/usr/apps/pkgid201" + + exit $? +else + exit 1 +fi diff --git a/tests/db/CMakeLists.txt b/tests/db/CMakeLists.txt new file mode 100644 index 0000000..837679e --- /dev/null +++ b/tests/db/CMakeLists.txt @@ -0,0 +1,49 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +# +# Test files +# +# Define all DPL tests sources. +# Runner is responsible for runnint it all and +# generating proper output files +# + +SET(TARGET_NAME "wrt-commons-tests-db") + +# Set DPL tests sources +SET(DPL_TESTS_DB_SOURCES + ${TESTS_DIR}/db/main.cpp + ${TESTS_DIR}/db/test_orm.cpp + ${TESTS_DIR}/db/test_sql_connection.cpp +) + +ADD_SUBDIRECTORY(orm) + +#include subdirectory +WRT_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/orm) +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_DPL_DB_EFL}) +WRT_TEST_BUILD(${TARGET_NAME} ${DPL_TESTS_DB_SOURCES}) +WRT_TEST_INSTALL(${TARGET_NAME}) + +INSTALL(FILES + ${TESTS_DIR}/db/orm/dpl_orm_test.db + DESTINATION /opt/share/wrt/wrt-commons/tests/db +) diff --git a/tests/db/main.cpp b/tests/db/main.cpp new file mode 100644 index 0000000..4ed6191 --- /dev/null +++ b/tests/db/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file main.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main. + */ + +#include + +int main(int argc, char *argv[]) +{ + return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); +} diff --git a/tests/db/orm/CMakeLists.txt b/tests/db/orm/CMakeLists.txt new file mode 100644 index 0000000..b7ebafb --- /dev/null +++ b/tests/db/orm/CMakeLists.txt @@ -0,0 +1,11 @@ +WRT_INTROSPECT_TARGET(db ${TARGET_DPL_DB_EFL}) +WRT_CONVERT_TO_GCC_LIST(db_INCLUDE_DIRS_GCC ${db_INCLUDE_DIRS}) + +ADD_CUSTOM_COMMAND( OUTPUT dpl_orm_test_db.sql + COMMAND rm -f ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test.db + COMMAND C_INCLUDE_PATH=${db_INCLUDE_DIRS_GCC} gcc -Wall -E ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test_db_sql_generator.h | grep --invert-match "^#" > ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test_db.sql + COMMAND sqlite3 ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test.db ".read ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test_db.sql" || rm -f ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test.db + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test_db_sql_generator.h ${CMAKE_CURRENT_SOURCE_DIR}/dpl_orm_test_db +) + +ADD_CUSTOM_TARGET( Sqlite3Db ALL DEPENDS dpl_orm_test_db.sql ) diff --git a/tests/db/orm/dpl_orm_test_db b/tests/db/orm/dpl_orm_test_db new file mode 100644 index 0000000..0d1963b --- /dev/null +++ b/tests/db/orm/dpl_orm_test_db @@ -0,0 +1,88 @@ + +CREATE_TABLE(TestTableInsert) + COLUMN(ColumnOptInt, INT,) + COLUMN(ColumnOptText, TEXT,) + COLUMN_NOT_NULL(ColumnInt, INT, DEFAULT 99) + COLUMN_NOT_NULL(ColumnInt2, INT,) + COLUMN_NOT_NULL(ColumnText, TEXT,) +CREATE_TABLE_END() + +CREATE_TABLE(TestTableDelete) + COLUMN(ColumnOptInt, INT,) + COLUMN(ColumnOptText, TEXT,) + COLUMN_NOT_NULL(ColumnInt, INT, DEFAULT 99) + COLUMN_NOT_NULL(ColumnInt2, INT,) + COLUMN_NOT_NULL(ColumnText, TEXT,) +CREATE_TABLE_END() + +SQL( + INSERT INTO TestTableDelete VALUES(1, "two", 3, 4, "five"); + INSERT INTO TestTableDelete VALUES(6, "seven", 8, 9, "ten"); + INSERT INTO TestTableDelete (ColumnInt2, ColumnText) VALUES(11, "twelve"); + INSERT INTO TestTableDelete (ColumnInt2, ColumnText) VALUES(13, "fourteen"); +) + +CREATE_TABLE(TestTable) + COLUMN(ColumnOptInt, INT,) + COLUMN(ColumnOptText, TEXT,) + COLUMN_NOT_NULL(ColumnInt, INT, DEFAULT 99) + COLUMN_NOT_NULL(ColumnInt2, INT,) + COLUMN_NOT_NULL(ColumnText, TEXT,) +CREATE_TABLE_END() + +SQL( + INSERT INTO TestTable VALUES(1, "two", 3, 4, "five"); + INSERT INTO TestTable VALUES(6, "seven", 8, 9, "ten"); + INSERT INTO TestTable (ColumnInt2, ColumnText) VALUES(11, "twelve"); + INSERT INTO TestTable (ColumnInt2, ColumnText) VALUES(13, "fourteen"); +) + +CREATE_TABLE(TestTableJoin1) + COLUMN_NOT_NULL(TestID, INT,) + COLUMN_NOT_NULL(TestText, TEXT,) + COLUMN(TestNumber, INT,) + TABLE_CONSTRAINTS( + PRIMARY KEY(TestID) + ) +CREATE_TABLE_END() + +CREATE_TABLE(TestTableJoin2) + COLUMN_NOT_NULL(TestID, INT,) + COLUMN_NOT_NULL(TestText1, TEXT,) + COLUMN_NOT_NULL(TestText2, TEXT,) + TABLE_CONSTRAINTS( + PRIMARY KEY(TestID) + ) +CREATE_TABLE_END() + +CREATE_TABLE(TestTableJoin3) + COLUMN_NOT_NULL(TestID, INT,) + COLUMN(Value3, INT,) + COLUMN(TestText33, TEXT,) + TABLE_CONSTRAINTS( + PRIMARY KEY(TestID) + ) +CREATE_TABLE_END() + +SQL( + INSERT INTO TestTableJoin1 VALUES(1, "text val 1", 111); + INSERT INTO TestTableJoin1 VALUES(2, "text val 2", 222); + INSERT INTO TestTableJoin1 VALUES(3, "text val 3", 333); + INSERT INTO TestTableJoin1 VALUES(4, "text val 4", 444); + INSERT INTO TestTableJoin1 VALUES(5, "text val 5", 555); + INSERT INTO TestTableJoin1 VALUES(6, "text val 6", 666); + + INSERT INTO TestTableJoin2 VALUES(1, "01", "text2 1"); + INSERT INTO TestTableJoin2 VALUES(2, "02", "text2 2"); + INSERT INTO TestTableJoin2 VALUES(3, "03", "text2 3"); + INSERT INTO TestTableJoin2 VALUES(4, " 4 ", "text2 4"); + INSERT INTO TestTableJoin2 VALUES(5, "*5*", "text2 5"); + INSERT INTO TestTableJoin2 VALUES(10, "6", "text2 6"); + + INSERT INTO TestTableJoin3 VALUES(1, 111, "test 1"); + INSERT INTO TestTableJoin3 VALUES(2, 111, "test 2"); + INSERT INTO TestTableJoin3 VALUES(3, 222, "test 3"); + INSERT INTO TestTableJoin3 VALUES(6, 222, "test 4"); + INSERT INTO TestTableJoin3 (TestID, TestText33) VALUES(7, "test 5"); + INSERT INTO TestTableJoin3 (TestID, TestText33) VALUES(10, "test 6"); +) diff --git a/tests/db/orm/dpl_orm_test_db_definitions b/tests/db/orm/dpl_orm_test_db_definitions new file mode 100644 index 0000000..da79427 --- /dev/null +++ b/tests/db/orm/dpl_orm_test_db_definitions @@ -0,0 +1,5 @@ +DATABASE_START(dpl_orm_test) + +#include "dpl_orm_test_db" + +DATABASE_END() diff --git a/tests/db/orm/dpl_orm_test_db_sql_generator.h b/tests/db/orm/dpl_orm_test_db_sql_generator.h new file mode 100644 index 0000000..cac41cc --- /dev/null +++ b/tests/db/orm/dpl_orm_test_db_sql_generator.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dpl_orm_test_db_sql_generator.h + * @author Lukasz Marek (l.marek@samsung.com) + * @version 1.0 + * @brief Macro definitions for generating the SQL input file from + * database definition. + */ + +//Do not include this file directly! It is used only for SQL code generation. + +#include + +#include "dpl_orm_test_db_definitions" diff --git a/tests/db/orm/dpl_orm_test_db_sql_generator.h.gch b/tests/db/orm/dpl_orm_test_db_sql_generator.h.gch new file mode 100644 index 0000000000000000000000000000000000000000..5bd675d819280b19af780a02d2739acb3bf9f0f0 GIT binary patch literal 6521 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 literal 0 HcmV?d00001 diff --git a/tests/db/orm/generator_dpl_orm_test.h b/tests/db/orm/generator_dpl_orm_test.h new file mode 100644 index 0000000..39bb1b7 --- /dev/null +++ b/tests/db/orm/generator_dpl_orm_test.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ORM_GENERATOR_DPL_ORM_TEST_H +#define ORM_GENERATOR_DPL_ORM_TEST_H + +#define ORM_GENERATOR_DATABASE_NAME dpl_orm_test_db_definitions +#include +#undef ORM_GENERATOR_DATABASE_NAME + +#endif diff --git a/tests/db/test_orm.cpp b/tests/db/test_orm.cpp new file mode 100644 index 0000000..c7c9ea9 --- /dev/null +++ b/tests/db/test_orm.cpp @@ -0,0 +1,1140 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +const char* PATH_DB = "/opt/share/wrt/wrt-commons/tests/db/dpl_orm_test.db"; + +//utils + +#define TEST_REPETITION 16 + +class SmartAttach +{ + public: + + SmartAttach(bool autoattach = true) : + m_interface(PATH_DB, + DPL::DB::SqlConnection::Flag::UseLucene), + m_autoattach(autoattach) + { + if (m_autoattach) { + m_interface.AttachToThread(DPL::DB::SqlConnection::Flag::RW); + } + } + + ~SmartAttach() + { + if (m_autoattach) { + m_interface.DetachFromThread(); + } + } + + DPL::DB::ThreadDatabaseSupport* get() + { + return &m_interface; + } + + private: + DPL::DB::ThreadDatabaseSupport m_interface; + bool m_autoattach; +}; + +template +bool ContainerContentsEqual(const ContainerType1& container1, + const ContainerType2& container2) +{ + using namespace DPL::DB::ORM::dpl_orm_test::TestTableInsert; + typedef std::set Set1; + typedef std::set Set2; + Set1 set1(container1.begin(), container1.end()); + Set2 set2(container2.begin(), container2.end()); + + for (typename Set1::iterator it = set1.begin(); + it != set1.end(); + it++) + { + LogDebug("Set1 element: " << *it); + } + + for (typename Set2::iterator it = set2.begin(); it != set2.end(); it++) { + LogDebug("Set2 element: " << *it); + } + + return set1 == set2; +} + +template +std::list makeList(const T& a, const T& b) +{ + std::list list; + list.push_back(a); + list.push_back(b); + return list; +} + +//tests + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: ORM_SelectSingleValue +Description: tests quering single value of single row from database +Expected: Values should match those which were prepared +*/ +RUNNER_TEST(ORM_SelectSingleValue) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + //Getting each column + { + TestTable::Select select(interface.get()); + select.Where(Equals(8)); + int result; + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue()) + == 6, "Got " << + result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(8)); + DPL::String result; + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue( + )) == L"seven", + "Got " << result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(8)); + int result; + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 8, "Got " << result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(8)); + int result; + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 9, "Got " << result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(8)); + DPL::String result; + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == L"ten", "Got " << result); + } + + //Where on each column + { + TestTable::Select select(interface.get()); + select.Where(Equals(6)); + int result; + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue()) + == 6, "Got " << + result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(DPL::String(L"seven"))); + DPL::String result; + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue( + )) == L"seven", + "Got " << result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(8)); + int result; + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 8, "Got " << result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(9)); + int result; + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 9, "Got " << result); + } + { + TestTable::Select select(interface.get()); + select.Where(Equals(L"ten")); + DPL::String result; + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == L"ten", "Got " << result); + } +} + +/* +Name: ORM_SelectSingleRow +Description: tests quering single row from database +Expected: Values should match those which were prepared +*/ +RUNNER_TEST(ORM_SelectSingleRow) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + { + TestTable::Select select(interface.get()); + select.Where(Equals(3)); + TestTable::Row result = select.GetSingleRow(); + TestTable::Row expected; + expected.Set_ColumnOptInt(1); + expected.Set_ColumnOptText(DPL::String(L"two")); + expected.Set_ColumnInt(3); + expected.Set_ColumnInt2(4); + expected.Set_ColumnText(L"five"); + RUNNER_ASSERT_MSG(result == expected, "Got " << result); + } + + { + TestTable::Select select(interface.get()); + select.Where(Equals(DPL::String(L"seven"))); + TestTable::Row result = select.GetSingleRow(); + TestTable::Row expected; + expected.Set_ColumnOptInt(6); + expected.Set_ColumnOptText(DPL::String(L"seven")); + expected.Set_ColumnInt(8); + expected.Set_ColumnInt2(9); + expected.Set_ColumnText(L"ten"); + RUNNER_ASSERT_MSG(result == expected, "Got " << result); + } +} + +/* +Name: ORM_SelectRowList +Description: tests quering multiple row from database +Expected: Values should match those which were prepared +*/ +RUNNER_TEST(ORM_SelectRowList) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + { + TestTable::Select select(interface.get()); + select.Where(Equals(3)); + std::list result = select.GetRowList(); + RUNNER_ASSERT_MSG(result.size() == 1, "Got " << result.size()); + + TestTable::Row expected; + expected.Set_ColumnOptInt(1); + expected.Set_ColumnOptText(DPL::String(L"two")); + expected.Set_ColumnInt(3); + expected.Set_ColumnInt2(4); + expected.Set_ColumnText(L"five"); + RUNNER_ASSERT_MSG(*(result.begin()) == expected, "Got " << + *(result.begin()) ); + } + + { + TestTable::Select select(interface.get()); + select.Where(Equals(DPL::String(L"seven"))); + std::list result = select.GetRowList(); + RUNNER_ASSERT_MSG(result.size() == 1, "Got " << result.size()); + + TestTable::Row expected; + expected.Set_ColumnOptInt(6); + expected.Set_ColumnOptText(DPL::String(L"seven")); + expected.Set_ColumnInt(8); + expected.Set_ColumnInt2(9); + expected.Set_ColumnText(L"ten"); + RUNNER_ASSERT_MSG(*(result.begin()) == expected, "Got " << + *(result.begin()) ); + } + + { + TestTable::Select select(interface.get()); + select.Where(Equals(99)); + std::list result = select.GetRowList(); + + TestTable::Row expected1; + expected1.Set_ColumnInt(99); + expected1.Set_ColumnInt2(11); + expected1.Set_ColumnText(L"twelve"); + + TestTable::Row expected2; + expected2.Set_ColumnInt(99); + expected2.Set_ColumnInt2(13); + expected2.Set_ColumnText(L"fourteen"); + + RUNNER_ASSERT(ContainerContentsEqual(makeList(expected1, + expected2), result)); + } +} + +/* +Name: ORM_SelectValueList +Description: tests quering single column from multiple row from database +Expected: Values should match those which were prepared +*/ +RUNNER_TEST(ORM_SelectValueList) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + //Getting each column + { + TestTable::Select select(interface.get()); + select.Where(Is(DPL::Optional::Null)); + RUNNER_ASSERT(ContainerContentsEqual(select.GetValueList(), + makeList(99, 99))); + } + { + TestTable::Select select(interface.get()); + select.Where(Is(DPL::Optional::Null)); + RUNNER_ASSERT(ContainerContentsEqual(select.GetValueList(), + makeList(11, 13))); + } + { + TestTable::Select select(interface.get()); + select.Where(Is(DPL::Optional::Null)); + RUNNER_ASSERT(ContainerContentsEqual(select.GetValueList(), + makeList(DPL::String(L"twelve"), + DPL::String(L"fourteen")))); + } + { + TestTable::Select select(interface.get()); + select.Where(Is(DPL::Optional::Null)); + RUNNER_ASSERT(ContainerContentsEqual(select.GetValueList(), + makeList(DPL::Optional + ::Null, + DPL::Optional + ::Null))); + } + + //Where on each column + { + TestTable::Select select(interface.get()); + select.Where(Is(DPL::Optional::Null)); + RUNNER_ASSERT(ContainerContentsEqual(select.GetValueList(), + makeList(11, 13))); + } + { + TestTable::Select select(interface.get()); + select.Where(Is(DPL::Optional:: + Null)); + RUNNER_ASSERT(ContainerContentsEqual(select.GetValueList(), + makeList(11, 13))); + } + { + TestTable::Select select(interface.get()); + select.Where(Is(99)); + RUNNER_ASSERT(ContainerContentsEqual(select.GetValueList(), + makeList(11, 13))); + } +} + +/* +Name: ORM_MultipleCalls +Description: tests sequnece of different queries +Expected: Values should match those which were prepared +*/ +RUNNER_TEST(ORM_MultipleCalls) +{ + for (int j = 0; j < TEST_REPETITION; j++) { + for (int i = 0; i < TEST_REPETITION; i++) { + ORM_SelectSingleValue(); + } + + for (int i = 0; i < TEST_REPETITION; i++) { + ORM_SelectSingleRow(); + } + + for (int i = 0; i < TEST_REPETITION; i++) { + ORM_SelectRowList(); + } + + for (int i = 0; i < TEST_REPETITION; i++) { + ORM_SelectValueList(); + } + } +} + +/* +Name: ORM_Insert +Description: tests insering rows into database +Expected: Values should be inserted +*/ +RUNNER_TEST(ORM_Insert) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + + TestTableInsert::Select select1(interface.get()); + std::list resultList = select1.GetValueList(); + RUNNER_ASSERT_MSG(resultList.empty(), + "Returned list has wrong size: " << resultList.size()); + + std::list list; + + TestTableInsert::Insert insert(interface.get()); + TestTableInsert::Row row; + row.Set_ColumnOptInt(1); + row.Set_ColumnInt2(2); + row.Set_ColumnText(L"three"); + insert.Values(row); + insert.Execute(); + + row.Set_ColumnInt(99); + list.push_back(row); + { + TestTableInsert::Select select2(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select2.GetRowList(), + list), "Returned list doesn't match."); + } + + TestTableInsert::Insert insert2(interface.get()); + TestTableInsert::Row row2; + row2.Set_ColumnInt(4); + row2.Set_ColumnInt2(5); + row2.Set_ColumnText(L"six"); + insert2.Values(row2); + insert2.Execute(); + + list.push_back(row2); + { + TestTableInsert::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + TestTableInsert::Insert insert3(interface.get()); + TestTableInsert::Row row3; + row3.Set_ColumnOptInt(1); + row3.Set_ColumnInt2(7); + row3.Set_ColumnText(L"eight"); + insert3.Values(row3); + insert3.Execute(); + + row3.Set_ColumnInt(99); + list.push_back(row3); + { + TestTableInsert::Select select3(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select3.GetRowList(), + list), "Returned list doesn't match."); + } + + TestTableInsert::Insert insert4(interface.get()); + TestTableInsert::Row row4; + row4.Set_ColumnOptInt(9); + row4.Set_ColumnInt2(10); + row4.Set_ColumnText(L"eleven"); + insert4.Values(row4); + insert4.Execute(); + + row4.Set_ColumnInt(99); + list.push_back(row4); + { + TestTableInsert::Select select4(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select4.GetRowList(), + list), "Returned list doesn't match."); + } + + // restore original table state + { + TestTableInsert::Delete del(interface.get()); + del.Execute(); + + TestTableInsert::Select select(interface.get()); + RUNNER_ASSERT(select.GetRowList().size() == 0); + } +} + +/* +Name: ORM_MultipleBindInsert +Description: repeats ORM_Insert test several times +Expected: Values should be inserted +*/ +RUNNER_TEST(ORM_MultipleBindInsert) +{ + for (int i = 0; i < TEST_REPETITION; i++) { + ORM_Insert(); + } +} + +/* +Name: ORM_Delete +Description: tests deleting rows from database +Expected: deleted rows should not exist +*/ +RUNNER_TEST(ORM_Delete) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + TestTableDelete::Select selectStart(interface.get()); + selectStart.OrderBy(DPL::TypeListDecl >()); + std::list list = selectStart.GetRowList(); + std::list originalList = list; + + std::vector vector(list.begin(), list.end()); + RUNNER_ASSERT_MSG( + list.size() == 4, "Returned list has wrong size: " << list.size()); + + typedef DPL::String S; + + //no-act deletes + { + TestTableDelete::Delete del(interface.get()); + del.Where(And(Equals(1), + Equals(S(L"seven")))); + del.Execute(); + + TestTableDelete::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + { + TestTableDelete::Delete del(interface.get()); + del.Where(And(Equals(6), + Equals(S(L"two")))); + del.Execute(); + + TestTableDelete::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + { + TestTableDelete::Delete del(interface.get()); + del.Where(Equals(10)); + del.Execute(); + + TestTableDelete::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + //act deletes + { + list.remove(vector[1]); + + TestTableDelete::Delete del(interface.get()); + del.Where(And(Equals(6), + Equals(L"ten"))); + del.Execute(); + + TestTableDelete::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + { + list.remove(vector[2]); + list.remove(vector[3]); + + TestTableDelete::Delete del(interface.get()); + del.Where(Is(DPL::Optional + ::Null)); + del.Execute(); + + TestTableDelete::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + { + TestTableDelete::Delete del(interface.get()); + del.Execute(); + + TestTableDelete::Select select(interface.get()); + RUNNER_ASSERT_MSG( + select.GetRowList().size() == 0, "Returned list is not empty"); + } + + // Restore original table state + // This also tests if multiple different binds for Insert are working + // properly + for (std::list::iterator i = originalList.begin(); + i != originalList.end(); + ++i) + { + TestTableDelete::Insert insert(interface.get()); + insert.Values(*i); + insert.Execute(); + } + + { + TestTableDelete::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + originalList), + "Returned list doesn't match."); + } +} + +/* +Name: ORM_MultipleBindDelete +Description: repeats ORM_Delete test several times +Expected: Values should be deleted +*/ +RUNNER_TEST(ORM_MultipleBindDelete) +{ + for (int i = 0; i < TEST_REPETITION; i++) { + ORM_Delete(); + } +} + +/* +Name: ORM_MultipleBindWhere +Description: tests if multiple bind of same query obejct works +Expected: Each bind and execution of query should be correct +*/ +RUNNER_TEST(ORM_MultipleBindWhere) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + { + TestTable::Select select(interface.get()); + int result; + select.Where(Equals(8)); + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue()) + == 6, "Got " << + result); + + select.Where(Equals(3)); + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue()) + == 1, "Got " << + result); + + select.Where(Equals(8)); + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue()) + == 6, "Got " << + result); + + select.Where(Equals(3)); + RUNNER_ASSERT_MSG((result = + *select.GetSingleValue()) + == 1, "Got " << + result); + } + + { + TestTable::Select select(interface.get()); + int result; + select.Where(And(Equals(99), + Equals(L"fourteen"))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 13, "Got " << result); + + select.Where(And(Equals(99), + Equals(L"twelve"))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 11, "Got " << result); + + select.Where(And(Equals(99), + Equals(L"fourteen"))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 13, "Got " << result); + + select.Where(And(Equals(99), + Equals(L"twelve"))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 11, "Got " << result); + } + + { + TestTable::Select select(interface.get()); + int result; + select.Where(And(Equals(L"fourteen"), + Equals(99))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 13, "Got " << result); + + select.Where(And(Equals(L"twelve"), + Equals(99))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 11, "Got " << result); + + select.Where(And(Equals(L"fourteen"), + Equals(99))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 13, "Got " << result); + + select.Where(And(Equals(L"twelve"), + Equals(99))); + RUNNER_ASSERT_MSG((result = select.GetSingleValue( + )) == 11, "Got " << result); + } +} + +/* +Name: ORM_Update +Description: tests rows update in database +Expected: Successful update +*/ +RUNNER_TEST(ORM_Update) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + + std::list list; + + TestTableInsert::Delete del(interface.get()); + del.Execute(); + + // INSERT + { + TestTableInsert::Insert insert(interface.get()); + TestTableInsert::Row row; + row.Set_ColumnOptInt(5); + row.Set_ColumnInt2(2); + row.Set_ColumnText(L"two"); + insert.Values(row); + insert.Execute(); + + row.Set_ColumnInt(99); + list.push_back(row); + } + { + TestTableInsert::Insert insert(interface.get()); + TestTableInsert::Row row; + row.Set_ColumnOptInt(1); + row.Set_ColumnInt2(2); + row.Set_ColumnText(L"three"); + insert.Values(row); + insert.Execute(); + + row.Set_ColumnInt(99); + list.push_back(row); + } + { + TestTableInsert::Insert insert(interface.get()); + TestTableInsert::Row row; + row.Set_ColumnOptInt(2); + row.Set_ColumnInt2(3); + row.Set_ColumnText(L"three"); + insert.Values(row); + insert.Execute(); + + row.Set_ColumnInt(99); + list.push_back(row); + + // CHECK + TestTableInsert::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + { + // UPDATE - no rows + TestTableInsert::Update update(interface.get()); + TestTableInsert::Row row; + row.Set_ColumnInt2(4); + row.Set_ColumnText(L"four"); + update.Values(row); + update.Where(Equals(12)); + update.Execute(); + + // CHECK + TestTableInsert::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + { + // UPDATE - one row + TestTableInsert::Update update(interface.get()); + TestTableInsert::Row row; + row.Set_ColumnInt2(2); + row.Set_ColumnText(L"four"); + update.Values(row); + update.Where(Equals(3)); + update.Execute(); + + list.back().Set_ColumnInt2(2); + list.back().Set_ColumnText(L"four"); + + // CHECK + TestTableInsert::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + { + // UPDATE - multiple rows + TestTableInsert::Update update(interface.get()); + TestTableInsert::Row row; + row.Set_ColumnText(L"dup"); + update.Values(row); + update.Where(Equals(2)); + update.Execute(); + + FOREACH(it, list) + { + it->Set_ColumnText(L"dup"); + } + + // CHECK + TestTableInsert::Select select(interface.get()); + RUNNER_ASSERT_MSG(ContainerContentsEqual( + select.GetRowList(), + list), "Returned list doesn't match."); + } + + // restore original table state + { + TestTableInsert::Delete del2(interface.get()); + del2.Execute(); + + TestTableInsert::Select select(interface.get()); + RUNNER_ASSERT(select.GetRowList().size() == 0); + } +} + +/* +Name: ORM_MultipleBindUpdate +Description: repeats ORM_Update severl times +Expected: Successful update +*/ +RUNNER_TEST(ORM_MultipleBindUpdate) +{ + for (int i = 0; i < TEST_REPETITION; i++) { + ORM_Update(); + } +} + +/* +Name: ORM_transactions +Description: checks creation of transation object +Expected: Successful creation of transaction object +*/ +RUNNER_TEST(ORM_transactions) +{ + SmartAttach interface; + DPL::DB::ORM::dpl_orm_test::ScopedTransaction transaction(interface.get()); +} + +/* +Name: ORM_MultiAttach +Description: checks correct behaviou in case of multiple tries to attach to database +Expected: Methods attaching/dettaching should be prepared for multiple calling +*/ +RUNNER_TEST(ORM_MultiAttach) +{ + SmartAttach interface(false); + RUNNER_ASSERT_MSG( + !interface.get()->IsAttached(), "Is attached, but shouldn't be."); + interface.get()->AttachToThread(); + RUNNER_ASSERT_MSG( + interface.get()->IsAttached(), "Isn't attached, but should be."); + interface.get()->AttachToThread(); + RUNNER_ASSERT_MSG( + interface.get()->IsAttached(), "Isn't attached, but should be."); + interface.get()->DetachFromThread(); + RUNNER_ASSERT_MSG( + interface.get()->IsAttached(), "Isn't attached, but should be."); + interface.get()->DetachFromThread(); + RUNNER_ASSERT_MSG( + !interface.get()->IsAttached(), "Is attached, but shouldn't be."); +} + +/* +Name: ORM_Join +Description: tests ORM's join operation +Expected: values should insist correct join operation +*/ +RUNNER_TEST(ORM_Join) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + + typedef DPL::TypeListDecl::Type JoinColumns; + + /* Test for correct join: + * 5 ids from first table matches 5 ids from second table thus join result + * contains 5 rows */ + TestTableJoin1::Select select(interface.get()); + select.Join(Equal()); + std::list > rowlist = + select.GetCustomRowList >(); + + RUNNER_ASSERT_MSG( + rowlist.size() == 5, "Invalid number of rows fetched: " << rowlist.size()); + + std::string text; + std::ostringstream oss; + int cnt = 0; + FOREACH(rowit, rowlist) + { + cnt++; + + text = + DPL::ToUTF8String((*rowit).GetColumnData()); + oss << "text val " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from first column: " + << text << " expected: " << oss.str()); + oss.str(std::string()); + + text = + DPL::ToUTF8String((*rowit).GetColumnData()); + oss << "text2 " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from second column: " + << text << " expected: " << oss.str()); + oss.str(std::string()); + } + /* Test for empty join: + * None of number values from first table matches ids from second table + * - join result should be empty */ + TestTableJoin1::Select select2(interface.get()); + select2.Join(Equal()); + rowlist = select2.GetCustomRowList >(); + + RUNNER_ASSERT_MSG(rowlist.empty(), "Result should be empty but it is not!"); + + /* Test for "converted" join: + * - join made with int column and text column as keys + * - expected 5 matching rows (one row of 6 should not be matched)*/ + TestTableJoin1::Select select3(interface.get()); + select3.Join(Equal()); + rowlist = select3.GetCustomRowList >(); + RUNNER_ASSERT_MSG( + rowlist.size() == 5, "Expected 5 rows while received: " << rowlist.size()); + cnt = 0; + FOREACH(rowit, rowlist) + { + cnt++; + // look at last two insertions into TestTableJoin2 + // for this skip understanding + if (cnt == 5) { + cnt = 6; + } + text = + DPL::ToUTF8String((*rowit).GetColumnData()); + oss << "text val " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from first column: " + << text << " expected: " << oss.str() << + " iteration: " << cnt); + oss.str(std::string()); + + text = + DPL::ToUTF8String((*rowit).GetColumnData()); + oss << "text2 " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from second column: " + << text << " expected: " << oss.str() << + " iteration: " << cnt); + oss.str(std::string()); + } + + /* Test for join with non-unique nullable columns given as keys*/ + typedef DPL::TypeListDecl::Type JoinTables2; + TestTableJoin1::Select select4(interface.get()); + select4.Join(Equal()); + std::list > rowlist2 = + select4.GetCustomRowList >(); + RUNNER_ASSERT_MSG( + rowlist2.size() == 4, "Expected 4 rows while received: " << + rowlist.size()); + cnt = 0; + DPL::Optional optext; + FOREACH(rowit, rowlist2) + { + cnt++; + + text = + DPL::ToUTF8String((*rowit).GetColumnData()); + // values expected in subsequent (1,2,3,4) iterations: 1 1 2 2 + oss << "text val " << (1 + (int)(cnt / 3)); + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from first column: " + << text << " expected: " << oss.str() << + " iteration: " << cnt); + oss.str(std::string()); + + optext = (*rowit).GetColumnData(); + text = DPL::ToUTF8String(*optext); + oss << "test " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from second column: " + << text << " expected: " << oss.str() << + " iteration: " << cnt); + oss.str(std::string()); + } + + /* Test for join made on three tables: + * - 3 text columns selected for join + * - Equal made for TestID of (table1 and table2) and (table1 and table3) */ + typedef DPL::TypeListDecl::Type Join3Tables; + TestTableJoin1::Select select5(interface.get()); + select5.Join(Equal()); + select5.Join(Equal()); + std::list > rowlist3tab = + select5.GetCustomRowList >(); + RUNNER_ASSERT_MSG( + rowlist3tab.size() == 3, "Expected 3 rows while received: " << + rowlist3tab.size()); + cnt = 0; + FOREACH(rowit, rowlist3tab) + { + cnt++; + + text = + DPL::ToUTF8String((*rowit).GetColumnData()); + oss << "text val " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from first column: " + << text << " expected: " << oss.str() << + " iteration: " << cnt); + oss.str(std::string()); + + text = + DPL::ToUTF8String((*rowit).GetColumnData()); + oss << "text2 " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from first column: " + << text << " expected: " << oss.str() << + " iteration: " << cnt); + oss.str(std::string()); + + optext = (*rowit).GetColumnData(); + text = DPL::ToUTF8String(*optext); + oss << "test " << cnt; + RUNNER_ASSERT_MSG(text.compare( + oss.str()) == 0, + "Invalid value from second column: " + << text << " expected: " << oss.str() << + " iteration: " << cnt); + oss.str(std::string()); + } +} + +RUNNER_TEST(ORM_SelectOrderByMultipleColumns) +{ + SmartAttach interface; + using namespace DPL::DB::ORM; + using namespace DPL::DB::ORM::dpl_orm_test; + { + TestTableJoin3::Select select(interface.get()); + + // testing: " ORDER BY Value3 ASC, TestID DESC, TestID ASC" + select.OrderBy(DPL::TypeListDecl, + OrderingDescending, + OrderingAscending >()); + + std::list result = select.GetRowList(); + std::list::const_iterator iter = result.begin(); + { //1 row + RUNNER_ASSERT_MSG(*iter->Get_TestText33() == + DPL::FromASCIIString( + "test 6"), "Wrong row 1 order"); + RUNNER_ASSERT_MSG(iter->Get_TestID() == 10, "Wrong row 1 order"); + ++iter; + } + { //2 row + RUNNER_ASSERT_MSG(*iter->Get_TestText33() == + DPL::FromASCIIString( + "test 5"), "Wrong row 2 order"); + RUNNER_ASSERT_MSG(iter->Get_TestID() == 7, "Wrong row 2 order"); + ++iter; + } + { //3 row + RUNNER_ASSERT_MSG(iter->Get_Value3() == 111, "Wrong row 3 order"); + RUNNER_ASSERT_MSG(*iter->Get_TestText33() == + DPL::FromASCIIString( + "test 2"), "Wrong row 3 order"); + RUNNER_ASSERT_MSG(iter->Get_TestID() == 2, "Wrong row 3 order"); + ++iter; + } + { //4 row + RUNNER_ASSERT_MSG(iter->Get_Value3() == 111, "Wrong row 4 order"); + RUNNER_ASSERT_MSG(*iter->Get_TestText33() == + DPL::FromASCIIString( + "test 1"), "Wrong row 4 order"); + RUNNER_ASSERT_MSG(iter->Get_TestID() == 1, "Wrong row 4 order"); + ++iter; + } + { //5 row + RUNNER_ASSERT_MSG(iter->Get_Value3() == 222, "Wrong row 5 order"); + RUNNER_ASSERT_MSG(*iter->Get_TestText33() == + DPL::FromASCIIString( + "test 4"), "Wrong row 5 order"); + RUNNER_ASSERT_MSG(iter->Get_TestID() == 6, "Wrong row 5 order"); + ++iter; + } + { //6 row + RUNNER_ASSERT_MSG(iter->Get_Value3() == 222, "Wrong row 6 order"); + RUNNER_ASSERT_MSG(*iter->Get_TestText33() == + DPL::FromASCIIString( + "test 3"), "Wrong row 6 order"); + RUNNER_ASSERT_MSG(iter->Get_TestID() == 3, "Wrong row 6 order"); + ++iter; + } + } +} diff --git a/tests/db/test_sql_connection.cpp b/tests/db/test_sql_connection.cpp new file mode 100644 index 0000000..20907fa --- /dev/null +++ b/tests/db/test_sql_connection.cpp @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_sql_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of sql connection tests + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern const char* PATH_DB; + +RUNNER_TEST_GROUP_INIT(DPL) + +class AbstractSynchronizationObjectGenerator +{ + public: + virtual ~AbstractSynchronizationObjectGenerator() {} + + virtual DPL::DB::SqlConnection::SynchronizationObject *Create() = 0; +}; + +class NaiveSynchronizationObjectGenerator : + public AbstractSynchronizationObjectGenerator +{ + public: + virtual DPL::DB::SqlConnection::SynchronizationObject *Create() + { + return new DPL::DB::NaiveSynchronizationObject(); + } +}; + +void MassiveReadWriteTest(AbstractSynchronizationObjectGenerator *generator); + +class StressGenerator : + public DPL::Thread +{ + private: + size_t m_prefix; + std::string m_dbFileName; + AbstractSynchronizationObjectGenerator *m_generator; + + protected: + virtual int ThreadEntry() + { + DPL::DB::SqlConnection connection( + m_dbFileName, + DPL::DB::SqlConnection::Flag::None, + DPL::DB::SqlConnection::Flag::RW, + m_generator->Create()); + + DPL::DB::SqlConnection::DataCommandAutoPtr countCommand = + connection.PrepareDataCommand( + "SELECT COUNT(*) FROM test WHERE value=?"); + + for (size_t i = 0; i < 10; ++i) { + std::ostringstream valueStream; + + valueStream << "value_"; + valueStream << static_cast(m_prefix); + valueStream << "_"; + valueStream << static_cast(i); + + std::string value = valueStream.str(); + + connection.ExecCommand( + "INSERT INTO test VALUES ('%s');", + value.c_str()); + + countCommand->BindString(1, value.c_str()); + + RUNNER_ASSERT(countCommand->Step()); + + RUNNER_ASSERT(countCommand->GetColumnString(0) == "1"); + + countCommand->Reset(); + } + + countCommand.reset(); + + return 0; + } + + public: + StressGenerator(size_t prefix, + const std::string &dbFileName, + AbstractSynchronizationObjectGenerator *generator) : + m_prefix(prefix), + m_dbFileName(dbFileName), + m_generator(generator) + {} +}; + +typedef std::shared_ptr ThreadPtr; + +void MassiveReadWriteTest(AbstractSynchronizationObjectGenerator *generator) +{ + DPL::DB::SqlConnection connection(PATH_DB, + DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE test(value TEXT);"); + + const size_t STRESS_GENERATOR_COUNT = 5; + ThreadPtr stressGenerators[STRESS_GENERATOR_COUNT]; + + for (size_t i = 0; i < STRESS_GENERATOR_COUNT; ++i) { + stressGenerators[i].reset( + new StressGenerator(i, PATH_DB, generator)); + + stressGenerators[i]->Run(); + } + + for (size_t i = 0; i < STRESS_GENERATOR_COUNT; ++i) { + stressGenerators[i]->Quit(); + } + + connection.ExecCommand("DROP TABLE test;"); +} + +/* +Name: SqlConnection_MassiveReadWrite_NaiveSynchronization +Description: tests massive multiple quiries from many threads +Expected: no ORM/db failures +*/ +RUNNER_TEST(SqlConnection_MassiveReadWrite_NaiveSynchronization) +{ + srand(time(NULL)); + + NaiveSynchronizationObjectGenerator m_generator; + MassiveReadWriteTest(&m_generator); +} + +/* +Name: SqlConnection_Not_Connected_Lucene +Description: tests connection to not existing database with Lucene option +Expected: exception throw +*/ +RUNNER_TEST(SqlConnection_Not_Connected_Lucene) +{ + Try { + DPL::DB::SqlConnection connection( + "/notexisitingdirectiory/foo", + DPL::DB::SqlConnection::Flag:: + UseLucene, + DPL::DB::SqlConnection::Flag::RW); + RUNNER_ASSERT_MSG(false, + "connection should throw on accessing " + "nonexistent file as a database"); + } + Catch(DPL::DB::SqlConnection::Exception::ConnectionBroken) + { + RUNNER_ASSERT(true); + } catch (DPL::Exception) { + RUNNER_ASSERT_MSG(false, "Wrong exception found"); + } +} + +/* +Name: SqlConnection_Not_Connected +Description: tests connection to not existing database without Lucene option +Expected: exception throw +*/ +RUNNER_TEST(SqlConnection_Not_Connected) +{ + Try { + DPL::DB::SqlConnection connection("/notexisitingdirectiory/foo", + DPL::DB::SqlConnection::Flag::None, + DPL::DB::SqlConnection::Flag::RW); + RUNNER_ASSERT_MSG(false, + "connection should throw on accessing " + "nonexistent file as a database"); + } + Catch(DPL::DB::SqlConnection::Exception::ConnectionBroken) + { + RUNNER_ASSERT(true); + } catch (DPL::Exception) { + RUNNER_ASSERT_MSG(false, "Wrong exception found"); + } +} + +/* +Name: SqlConnection_Null_Query +Description: tests resistance to passing NULL as query in ExecCommand +Expected: exception throw +*/ +RUNNER_TEST(SqlConnection_Null_Query) +{ + DPL::DB::SqlConnection connection(PATH_DB, + DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + Try + { + connection.ExecCommand(NULL); + RUNNER_ASSERT_MSG(false, + "Null pointer should not be accepted"); + } + Catch(DPL::DB::SqlConnection::Exception::SyntaxError) + { + RUNNER_ASSERT(true); + } catch (DPL::Exception) { + RUNNER_ASSERT_MSG(false, "Wrong exception found"); + } +} + +/* +Name: SqlConnection_Bad_Query +Description: tests resistance to passing trash as query in ExecCommand +Expected: exception throw +*/ +RUNNER_TEST(SqlConnection_Bad_Query) +{ + DPL::DB::SqlConnection connection(PATH_DB, + DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + Try + { + connection.ExecCommand("Some stupid string"); + RUNNER_ASSERT_MSG(false, "This string should not be accepted"); + } + Catch(DPL::DB::SqlConnection::Exception::SyntaxError) + { + RUNNER_ASSERT(true); + } catch (DPL::Exception) { + RUNNER_ASSERT_MSG(false, "Wrong exception found"); + } +} + +/* +Name: SqlConnection_IsNull +Description: tests IsColumnNull function +Expected: Function returns correct values +*/ +RUNNER_TEST(SqlConnection_IsNull) +{ + DPL::DB::SqlConnection connection(PATH_DB, DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE testNull(value INT8);"); + + connection.ExecCommand("INSERT INTO testNull VALUES (NULL);"); + connection.ExecCommand("INSERT INTO testNull VALUES (0);"); + + DPL::DB::SqlConnection::DataCommandAutoPtr selectCommand = connection.PrepareDataCommand( + "SELECT value FROM testNull"); + + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->IsColumnNull(0)); + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(!selectCommand->IsColumnNull(0)); + selectCommand->Reset(); + + connection.ExecCommand("DROP TABLE testNull;"); +} + +/* +Name: SqlConnection_Int8 +Description: tests bind and getColumn functions for Int8 +Expected: Functions returns correct values +*/ +RUNNER_TEST(SqlConnection_Int8) +{ + DPL::DB::SqlConnection connection(PATH_DB, DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE testInt8(value INT8);"); + + DPL::DB::SqlConnection::DataCommandAutoPtr insertCommand = connection.PrepareDataCommand( + "INSERT INTO testInt8 VALUES (?)"); + + DPL::DB::SqlConnection::DataCommandAutoPtr selectCommand = connection.PrepareDataCommand( + "SELECT value FROM testInt8"); + + insertCommand->BindInt8(1, 127); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + insertCommand->BindInt8(1, DPL::Optional(-127)); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnInt8(0) == 127); + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnOptionalInt8(0) == -127); + selectCommand->Reset(); + + connection.ExecCommand("DROP TABLE testInt8;"); +} + +/* +Name: SqlConnection_Int16 +Description: tests bind and getColumn functions for Int16 +Expected: Functions returns correct values +*/ +RUNNER_TEST(SqlConnection_Int16) +{ + DPL::DB::SqlConnection connection(PATH_DB, DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE testInt16(value INT16);"); + + DPL::DB::SqlConnection::DataCommandAutoPtr insertCommand = connection.PrepareDataCommand( + "INSERT INTO testInt16 VALUES (?)"); + + DPL::DB::SqlConnection::DataCommandAutoPtr selectCommand = connection.PrepareDataCommand( + "SELECT value FROM testInt16"); + + insertCommand->BindInt16(1, (int16_t)0xFFFF); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + insertCommand->BindInt16(1, DPL::Optional((int16_t)0x8000)); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnInt16(0) == (int16_t)0xFFFF); + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnOptionalInt16(0) == (int16_t)0x8000); + selectCommand->Reset(); + + connection.ExecCommand("DROP TABLE testInt16;"); +} + +/* +Name: SqlConnection_Int32 +Description: tests bind and getColumn functions for Int32 +Expected: Functions returns correct values +*/ +RUNNER_TEST(SqlConnection_Int32) +{ + DPL::DB::SqlConnection connection(PATH_DB, DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE testInt32(value INT32);"); + + DPL::DB::SqlConnection::DataCommandAutoPtr insertCommand = connection.PrepareDataCommand( + "INSERT INTO testInt32 VALUES (?)"); + + DPL::DB::SqlConnection::DataCommandAutoPtr selectCommand = connection.PrepareDataCommand( + "SELECT value FROM testInt32"); + + insertCommand->BindInt32(1, 0xFFFFFFFF); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + insertCommand->BindInt32(1, DPL::Optional(0x80000000)); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnInt32(0) == (int32_t)0xFFFFFFFF); + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnOptionalInt32(0) == 0x80000000); + selectCommand->Reset(); + + connection.ExecCommand("DROP TABLE testInt32;"); +} + +/* +Name: SqlConnection_Int64 +Description: tests bind and getColumn functions for Int64 +Expected: Functions returns correct values +*/ +RUNNER_TEST(SqlConnection_Int64) +{ + DPL::DB::SqlConnection connection(PATH_DB, DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE testInt64(value INT64);"); + + DPL::DB::SqlConnection::DataCommandAutoPtr insertCommand = connection.PrepareDataCommand( + "INSERT INTO testInt64 VALUES (?)"); + + DPL::DB::SqlConnection::DataCommandAutoPtr selectCommand = connection.PrepareDataCommand( + "SELECT value FROM testInt64"); + + insertCommand->BindInt64(1, 0xFFFFFFFFFFFFFFFF); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + insertCommand->BindInt64(1, DPL::Optional(0x8000000000000000)); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnInt64(0) == (int64_t)0xFFFFFFFFFFFFFFFF); + RUNNER_ASSERT(selectCommand->Step()); + RUNNER_ASSERT(selectCommand->GetColumnOptionalInt64(0) == 0x8000000000000000); + selectCommand->Reset(); + + connection.ExecCommand("DROP TABLE testInt64;"); +} + +/* +Name: SqlConnection_Float +Description: tests bind and getColumn functions for float +Expected: Functions returns correct values +*/ +RUNNER_TEST(SqlConnection_Float) +{ + DPL::DB::SqlConnection connection(PATH_DB, DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE testFloat(value FLOAT);"); + + DPL::DB::SqlConnection::DataCommandAutoPtr insertCommand = connection.PrepareDataCommand( + "INSERT INTO testFloat VALUES (?)"); + + DPL::DB::SqlConnection::DataCommandAutoPtr selectCommand = connection.PrepareDataCommand( + "SELECT value FROM testFloat"); + + insertCommand->BindFloat(1, 10.2545f); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + insertCommand->BindFloat(1, DPL::Optional(-90.6788f)); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + RUNNER_ASSERT(selectCommand->Step()); + float value = selectCommand->GetColumnFloat(0); + RUNNER_ASSERT(value > 10.2544 && value < 10.2546); + RUNNER_ASSERT(selectCommand->Step()); + value = *selectCommand->GetColumnOptionalFloat(0); + RUNNER_ASSERT(value > -90.6789 && value < -90.6787); + selectCommand->Reset(); + + connection.ExecCommand("DROP TABLE testFloat;"); +} + +/* +Name: SqlConnection_Double +Description: tests bind and getColumn functions for double +Expected: Functions returns correct values +*/ +RUNNER_TEST(SqlConnection_Double) +{ + DPL::DB::SqlConnection connection(PATH_DB, DPL::DB::SqlConnection::Flag::UseLucene, + DPL::DB::SqlConnection::Flag::RW); + + connection.ExecCommand("CREATE TABLE testDouble(value DOUBLE);"); + + DPL::DB::SqlConnection::DataCommandAutoPtr insertCommand = connection.PrepareDataCommand( + "INSERT INTO testDouble VALUES (?)"); + + DPL::DB::SqlConnection::DataCommandAutoPtr selectCommand = connection.PrepareDataCommand( + "SELECT value FROM testDouble"); + + insertCommand->BindDouble(1, 10.2545); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + insertCommand->BindDouble(1, DPL::Optional(-90.6788)); + RUNNER_ASSERT(!insertCommand->Step()); + insertCommand->Reset(); + + RUNNER_ASSERT(selectCommand->Step()); + double value = selectCommand->GetColumnDouble(0); + RUNNER_ASSERT(value > 10.2544 && value < 10.2546); + RUNNER_ASSERT(selectCommand->Step()); + value = *selectCommand->GetColumnOptionalDouble(0); + RUNNER_ASSERT(value > -90.6789 && value < -90.6787); + selectCommand->Reset(); + + connection.ExecCommand("DROP TABLE testDouble;"); +} diff --git a/tests/dbus/CMakeLists.txt b/tests/dbus/CMakeLists.txt new file mode 100644 index 0000000..4a1f338 --- /dev/null +++ b/tests/dbus/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) +# @version 1.0 +# @brief +# + +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(DEPENDENCIES gthread-2.0 REQUIRED) + +SET(TARGET_DBUS_TESTS "wrt-commons-tests-dbus") +SET(TARGET_DBUS_TEST_SERVICE "wrt-commons-tests-dbus-test-service") + +SET(DBUS_TESTS_SRCS + ${TESTS_DIR}/dbus/main.cpp + ${TESTS_DIR}/dbus/test_cases.cpp + ${TESTS_DIR}/dbus/dbus_test.cpp + ${TESTS_COMMON_DIR}/src/loop_control.cpp +) + +SET(DBUS_TEST_SERVICE_SRCS + ${TESTS_DIR}/dbus/test_service.cpp + ${TESTS_COMMON_DIR}/src/loop_control.cpp +) + +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_DBUS_TESTS} ${TARGET_DPL_DBUS_EFL}) +WRT_TEST_INCLUDE_DIRECTORIES(${TARGET_DBUS_TESTS} + ${TESTS_COMMON_DIR}/include + ${DEPENDENCIES_INCLUDE_DIRS} +) +WRT_TEST_LINK_DIRECTORIES(${TARGET_DBUS_TESTS} ${DEPENDENCIES_LIBRARY_DIRS}) +WRT_TEST_TARGET_LINK_LIBRARIES(${TARGET_DBUS_TESTS} ${DEPENDENCIES_LIBRARIES}) +WRT_TEST_BUILD(${TARGET_DBUS_TESTS} ${DBUS_TESTS_SRCS}) +WRT_TEST_INSTALL(${TARGET_DBUS_TESTS}) + +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_DBUS_TEST_SERVICE} ${TARGET_DPL_DBUS_EFL}) +WRT_TEST_INCLUDE_DIRECTORIES(${TARGET_DBUS_TEST_SERVICE} + ${TESTS_COMMON_DIR}/include + ${DEPENDENCIES_INCLUDE_DIRS} +) +WRT_TEST_LINK_DIRECTORIES(${TARGET_DBUS_TEST_SERVICE} ${DEPENDENCIES_LIBRARY_DIRS}) +WRT_TEST_TARGET_LINK_LIBRARIES(${TARGET_DBUS_TEST_SERVICE} ${DEPENDENCIES_LIBRARIES}) +WRT_TEST_BUILD(${TARGET_DBUS_TEST_SERVICE} ${DBUS_TEST_SERVICE_SRCS}) +WRT_TEST_INSTALL(${TARGET_DBUS_TEST_SERVICE}) + +INSTALL(FILES + ${TESTS_DIR}/dbus/data/org.tizen.DBusTestService.service + DESTINATION /usr/share/dbus-1/services +) diff --git a/tests/dbus/data/org.tizen.DBusTestService.service b/tests/dbus/data/org.tizen.DBusTestService.service new file mode 100644 index 0000000..94b3d67 --- /dev/null +++ b/tests/dbus/data/org.tizen.DBusTestService.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.tizen.DBusTestService +Exec=/usr/bin/wrt-commons-tests-dbus-test-service diff --git a/tests/dbus/dbus_test.cpp b/tests/dbus/dbus_test.cpp new file mode 100644 index 0000000..cabdf90 --- /dev/null +++ b/tests/dbus/dbus_test.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file dbus_test.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @brief Implementation file for DBusTest and DBusTestManager. + */ + +#include +#include "loop_control.h" +#include "dbus_test.h" + +DBusTest::DBusTest(const std::string& name) : + m_name(name), + m_status(Status::NONE) +{} + +void DBusTest::run(unsigned int timeout) +{ + DPL::Event::ControllerEventHandler::Touch(); + DPL::Event::ControllerEventHandler::Touch(); + + DPL::Event::ControllerEventHandler::PostTimedEvent( + TimeoutEvent(), timeout); + + LoopControl::wrt_start_loop(); + + switch (m_status) { + case Status::FAILED: + throw DPL::Test::TestRunner::TestFailed(m_name.c_str(), + __FILE__, + __LINE__, + m_message); + + case Status::SUCCESS: + case Status::NONE: + default: + break; + } +} + +void DBusTest::quit() +{ + DPL::Event::ControllerEventHandler::PostEvent(QuitEvent()); +} + +void DBusTest::setStatus(Status status) +{ + m_status = status; +} + +void DBusTest::setMessage(const std::string& message) +{ + m_message = message; +} + +void DBusTest::success() +{ + m_status = Status::SUCCESS; +} + +void DBusTest::fail(const std::string& message) +{ + m_status = Status::FAILED; + m_message = message; +} + +void DBusTest::OnEventReceived(const TimeoutEvent& /*event*/) +{ + fail("Test timed out."); + + // Saving one event dispatch since Quit and Timeout work on the same thread. + LoopControl::wrt_end_loop(); +} + +void DBusTest::OnEventReceived(const QuitEvent& /*event*/) +{ + LoopControl::wrt_end_loop(); +} + +DBusTestManager& DBusTestManager::getInstance() +{ + static DBusTestManager instance; + return instance; +} + +DBusTestManager::DBusTestManager() : m_test(NULL) { } + +DBusTest& DBusTestManager::getCurrentTest() const +{ + AssertMsg(NULL != m_test, "Test not set."); + + return *m_test; +} + +void DBusTestManager::setCurrentTest(DBusTest& test) +{ + m_test = &test; +} + +void DBusTestManager::clear() +{ + m_test = NULL; +} diff --git a/tests/dbus/dbus_test.h b/tests/dbus/dbus_test.h new file mode 100644 index 0000000..3c7ffe9 --- /dev/null +++ b/tests/dbus/dbus_test.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file dbus_test.h + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @brief Header file for DBusTest and DBusTestManager. + */ + +#ifndef WRT_TESTS_DBUS_TESTS_DBUS_TEST_H +#define WRT_TESTS_DBUS_TESTS_DBUS_TEST_H + +#include +#include +#include + +DECLARE_GENERIC_EVENT_0(QuitEvent) +DECLARE_GENERIC_EVENT_0(TimeoutEvent) + +class DBusTest : + private DPL::Event::Controller::Type> +{ + public: + enum class Status + { + NONE, + SUCCESS, + FAILED + }; + + explicit DBusTest(const std::string& name); + + void run(unsigned int timeout); + void quit(); + + void setStatus(Status status); + void setMessage(const std::string& message); + + void success(); + void fail(const std::string& message = std::string()); + + private: + void OnEventReceived(const TimeoutEvent& event); + void OnEventReceived(const QuitEvent& event); + + std::string m_name; + Status m_status; + std::string m_message; +}; + +class DBusTestManager : private DPL::Noncopyable +{ + public: + static DBusTestManager& getInstance(); + + DBusTest& getCurrentTest() const; + void setCurrentTest(DBusTest& test); + + void clear(); + + private: + DBusTestManager(); + + DBusTest* m_test; +}; + +#define DBUS_TEST(TestProc) \ + void DBus##TestProc(); \ + RUNNER_TEST(TestProc) \ + { \ + DBusTest test(#TestProc); \ + DBusTestManager::getInstance().setCurrentTest(test); \ + DBus##TestProc(); \ + DBusTestManager::getInstance().clear(); \ + } \ + void DBus##TestProc() + +#endif diff --git a/tests/dbus/main.cpp b/tests/dbus/main.cpp new file mode 100644 index 0000000..4dfd0b4 --- /dev/null +++ b/tests/dbus/main.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file main.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main. + */ + +#include "loop_control.h" +#include +#include + +int main(int argc, char *argv[]) +{ + LoopControl::init_loop(argc, argv); + + LogDebug("Running tests"); + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, + argv); + + return status; +} diff --git a/tests/dbus/test_cases.cpp b/tests/dbus/test_cases.cpp new file mode 100644 index 0000000..15a7153 --- /dev/null +++ b/tests/dbus/test_cases.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file TestCases.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief Implementation file for test cases for DBus internal tests. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "dbus_test.h" + +namespace { +const std::string dbusServiceName = "org.freedesktop.DBus"; +const std::string dbusObjectPath = "/"; +const std::string dbusInterfaceName = "org.freedesktop.DBus"; +const std::string dbusMethodGetId = "GetId"; + +const std::string serviceName = "org.tizen.DBusTestService"; +const std::string objectPath = "/org/tizen/DBusTestService"; +const std::string interfaceName = "org.tizen.DBusTestService"; +const std::string methodNameEcho = "echo"; +const std::string methodNameQuit = "quit"; +const std::string nodeInfo = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +const std::string challenge = "Hello world!"; + +const int DEFAULT_TIMEOUT = 2; // in seconds +} + +RUNNER_TEST_GROUP_INIT(DPL) + +/* +Name: AcquireSessionBus +Description: tests acquiring session bus +Expected: no exceptions +*/ +RUNNER_TEST(AcquireSessionBus) +{ + try { + DPL::DBus::Connection::sessionBus(); + } catch (const DPL::DBus::Exception& ex) { + RUNNER_ASSERT_MSG(false, ex.DumpToString()); + } +} + +/* +Name: AcquireSystemBus +Description: tests acquiring system bus +Expected: no exceptions +*/ +RUNNER_TEST(AcquireSystemBus) +{ + try { + DPL::DBus::Connection::systemBus(); + } catch (const DPL::DBus::Exception& ex) { + RUNNER_ASSERT_MSG(false, ex.DumpToString()); + } +} + +/* +Name: ServerCreateFail +Description: tests creating server with wrong address +Expected: exception should occur +*/ +RUNNER_TEST(ServerCreateFail) +{ + bool exceptionCaught = false; + try { + DPL::DBus::ServerPtr server = DPL::DBus::Server::create("wrong address"); + } catch (const DPL::Exception& ex) { + exceptionCaught = true; + } + RUNNER_ASSERT(exceptionCaught); +} + +/* +Name: ServerCreateAndConnection +Description: tests creating server and connecting to it +Expected: no exceptions +*/ +RUNNER_TEST(ServerCreateAndConnection) +{ + try { + DPL::DBus::ServerPtr server = DPL::DBus::Server::create("unix:abstract=/tmp/testAddresss"); + server->start(); + DPL::DBus::ConnectionPtr con = DPL::DBus::Connection::connectTo("unix:abstract=/tmp/testAddresss"); + RUNNER_ASSERT(con); + } catch (const DPL::DBus::Exception& ex) { + RUNNER_ASSERT_MSG(false, ex.DumpToString()); + } +} + +/* +Name: ConnectionFail +Description: tests creating connection when server is not running +Expected: exception should occur +*/ +RUNNER_TEST(ConnectionFail) +{ + bool exceptionCaught = false; + try { + DPL::DBus::ConnectionPtr con = DPL::DBus::Connection::connectTo("unix:abstract=/tmp/testAddresss"); + RUNNER_ASSERT(con); + } catch (const DPL::DBus::Exception& ex) { + exceptionCaught = true; + } + RUNNER_ASSERT(exceptionCaught); +} + +/* +Name: ConnectionFail2 +Description: tests creating connection when server is running on different address +Expected: exception should occur +*/ +RUNNER_TEST(ConnectionFail2) +{ + bool exceptionCaught = false; + try { + DPL::DBus::ServerPtr server = DPL::DBus::Server::create("unix:abstract=/tmp/testAddresssToFail"); + server->start(); + DPL::DBus::ConnectionPtr con = DPL::DBus::Connection::connectTo("unix:abstract=wrongAddress"); + RUNNER_ASSERT(con); + } catch (const DPL::DBus::Exception& ex) { + exceptionCaught = true; + } + RUNNER_ASSERT(exceptionCaught); +} + + + +/* +Name: ParseNodeInfo +Description: creates dbus interface from xml string +Expected: interface should be created correctly +*/ +RUNNER_TEST(ParseNodeInfo) +{ + try { + auto ifaces = DPL::DBus::Interface::fromXMLString(nodeInfo); + RUNNER_ASSERT(!ifaces.empty()); + + auto iface = ifaces.at(0); + RUNNER_ASSERT(NULL != iface->getVTable()); + RUNNER_ASSERT(NULL != iface->getInfo()); + } catch (const DPL::DBus::Exception& ex) { + RUNNER_ASSERT_MSG(false, ex.DumpToString()); + } +} + +/* +Name: InvokeRemoteMethod +Description: performs procedure call via dbus +Expected: call should return not empty id +*/ +RUNNER_TEST(InvokeRemoteMethod) +{ + try { + auto connection = DPL::DBus::Connection::systemBus(); + auto freedesktop = connection->createObjectProxy(dbusServiceName, + dbusObjectPath); + auto getId = freedesktop->createMethodProxy + (dbusInterfaceName, dbusMethodGetId); + RUNNER_ASSERT(!getId().empty()); + } catch (const DPL::DBus::Exception& ex) { + RUNNER_ASSERT_MSG(false, ex.DumpToString()); + } +} + +class RegisterServiceListener : + public DPL::Event::EventListener +{ + public: + void OnEventReceived( + const DPL::DBus::ConnectionEvents::ServiceNameAcquiredEvent& event) + { + DBusTest& test = DBusTestManager::getInstance().getCurrentTest(); + + auto name = event.GetArg0(); + if (serviceName == name) { + test.success(); + } else { + test.fail("Acquired service name: " + name); + } + test.quit(); + } +}; + +/* +Name: RegisterService +Description: tests event listener for AcquiredEvent in context of dbus +Expected: event should be received +*/ +DBUS_TEST(RegisterService) +{ + try { + RegisterServiceListener listener; + + auto connection = DPL::DBus::Connection::sessionBus(); + connection->DPL::Event::EventSupport:: + AddListener(&listener); + connection->registerService(serviceName); + + DBusTestManager::getInstance().getCurrentTest().run(DEFAULT_TIMEOUT); + + connection->unregisterService(serviceName); + + } catch (const DPL::DBus::Exception& ex) { + RUNNER_ASSERT_MSG(false, ex.DumpToString()); + } +} + +/** + * This test checks: + * - object registration (done on the wrt-dbus-test-service side) + * - service registration (done on the wrt-dbus-test-service side) + * - dispatching method calls (done on the wrt-dbus-test-service side) + * - launching dbus service on demand + * - invoking remote method(s) + */ +DBUS_TEST(InvokeTestService) +{ + try { + auto connection = DPL::DBus::Connection::sessionBus(); + auto testService = connection->createObjectProxy(serviceName, + objectPath); + auto echo = testService->createMethodProxy + (interfaceName, methodNameEcho); + auto response = echo(challenge); + + testService->createMethodProxy(interfaceName, methodNameQuit) (); + + RUNNER_ASSERT_MSG(response == challenge, + "[challenge = " << challenge << + ", response = " << response << "]"); + } catch (const DPL::DBus::Exception& ex) { + RUNNER_ASSERT_MSG(false, ex.DumpToString()); + } +} diff --git a/tests/dbus/test_service.cpp b/tests/dbus/test_service.cpp new file mode 100644 index 0000000..510e4c5 --- /dev/null +++ b/tests/dbus/test_service.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file test_service.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @brief Implementation file for wrt-dbus-test-service. + */ + +#include +#include +#include +#include +#include +#include + +namespace { +const std::string serviceName = "org.tizen.DBusTestService"; +const std::string objectPath = "/org/tizen/DBusTestService"; +const std::string interfaceName = "org.tizen.DBusTestService"; +const std::string methodNameEcho = "echo"; +const std::string methodNameQuit = "quit"; +const std::string nodeInfo = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + ""; +} + +class TestServiceDispatcher : public DPL::DBus::Dispatcher +{ + private: + void onMethodCall(GDBusConnection* /*connection*/, + const gchar* /*sender*/, + const gchar* /*objectPath*/, + const gchar* /*interfaceName*/, + const gchar* methodName, + GVariant* parameters, + GDBusMethodInvocation* invocation) + { + if (methodNameEcho == methodName) { + LogDebug("Echo"); + g_dbus_method_invocation_return_value(invocation, + parameters); + } else if (methodNameQuit == methodName) { + LogDebug("Quit"); + g_dbus_method_invocation_return_value(invocation, NULL); + LoopControl::wrt_end_loop(); + } + } +}; + +int main(int argc, char* argv[]) +{ + LoopControl::init_loop(argc, argv); + TestServiceDispatcher dispatcher; + + auto iface = DPL::DBus::Interface::fromXMLString(nodeInfo).at(0); + iface->setDispatcher(&dispatcher); + auto object = DPL::DBus::Object::create(objectPath, iface); + auto connection = DPL::DBus::Connection::sessionBus(); + connection->registerObject(object); + connection->registerService(serviceName); + LoopControl::wrt_start_loop(); + + return 0; +} diff --git a/tests/event/CMakeLists.txt b/tests/event/CMakeLists.txt new file mode 100644 index 0000000..08fa4fa --- /dev/null +++ b/tests/event/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) +# @version 1.0 +# @brief +# + +# +# Test files +# +# Define all DPL tests sources. +# Runner is responsible for runnint it all and +# generating proper output files +# + +SET(TARGET_NAME "wrt-commons-tests-event") + +# Set DPL tests sources +SET(DPL_TESTS_EVENT_SOURCES + ${TESTS_DIR}/event/main.cpp + ${TESTS_DIR}/event/test_controller.cpp + ${TESTS_DIR}/event/test_event_support.cpp + ${TESTS_DIR}/event/test_ic_delegate.cpp + ${TESTS_DIR}/event/test_property.cpp +) + +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_DPL_EVENT_EFL}) +WRT_TEST_BUILD(${TARGET_NAME} ${DPL_TESTS_EVENT_SOURCES}) +WRT_TEST_INSTALL(${TARGET_NAME}) \ No newline at end of file diff --git a/tests/event/main.cpp b/tests/event/main.cpp new file mode 100644 index 0000000..4ed6191 --- /dev/null +++ b/tests/event/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file main.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main. + */ + +#include + +int main(int argc, char *argv[]) +{ + return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); +} diff --git a/tests/event/test_controller.cpp b/tests/event/test_controller.cpp new file mode 100644 index 0000000..5308720 --- /dev/null +++ b/tests/event/test_controller.cpp @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_controller.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test controller + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +namespace { + unsigned int seed = time(NULL); +} + +class IntController : + public DPL::Event::Controller::Type> +{ + private: + int m_value; + + protected: + virtual void OnEventReceived(const int &event) + { + m_value = event; + } + + public: + IntController() : + m_value(-1) + {} + + int Value() const + { + return m_value; + } +}; + +DECLARE_GENERIC_EVENT_1(DoneSignalEvent, DPL::WaitableEvent *) + +class ThreadController : + public DPL::Event::Controller::Type> +{ + private: + DPL::Thread *m_value; + + protected: + virtual void OnEventReceived(const DoneSignalEvent &event) + { + m_value = DPL::Thread::GetCurrentThread(); + event.GetArg0()->Signal(); + } + + public: + ThreadController() : + m_value(NULL) + {} + + DPL::Thread *Value() const + { + return m_value; + } +}; + +struct StrangeStruct +{ + int a; + float b; + double c; +}; + +class StrangeController : + public DPL::Event::Controller::Type> +{ + protected: + virtual void OnEventReceived(const char &event) + { + (void)event; + } + virtual void OnEventReceived(const short &event) + { + (void)event; + } + virtual void OnEventReceived(const int &event) + { + (void)event; + } + virtual void OnEventReceived(const long &event) + { + (void)event; + } + virtual void OnEventReceived(const unsigned char &event) + { + (void)event; + } + virtual void OnEventReceived(const unsigned short &event) + { + (void)event; + } + virtual void OnEventReceived(const unsigned int &event) + { + (void)event; + } + virtual void OnEventReceived(const unsigned long &event) + { + (void)event; + } + virtual void OnEventReceived(const float &event) + { + (void)event; + } + virtual void OnEventReceived(const double &event) + { + (void)event; + } + virtual void OnEventReceived(const StrangeStruct &event) + { + (void)event; + } +}; + +/* +Name: Controller_InitSimple +Description: tests initialization of simple int controller +Expected: no exceptions +*/ +RUNNER_TEST(Controller_InitSimple) +{ + IntController controller; + controller.Touch(); + RUNNER_ASSERT(controller.Value() == -1); +} + +/* +Name: Controller_InitStrange +Description: tests initialization of struct controller +Expected: no exceptions +*/ +RUNNER_TEST(Controller_InitStrange) +{ + StrangeController controller; + controller.Touch(); +} + +/* +Name: Controller_PostEventToThread +Description: tests post events to other thread +Expected: thread id gathered in event handling method should match id of created thread +*/ +RUNNER_TEST(Controller_PostEventToThread) +{ + ThreadController controller; + controller.Touch(); + + DPL::Thread thread; + thread.Run(); + + controller.SwitchToThread(&thread); + + DPL::WaitableEvent waitHandle; + + controller.PostEvent(DoneSignalEvent(&waitHandle)); + + DPL::WaitForSingleHandle(waitHandle.GetHandle()); + + controller.SwitchToThread(NULL); + + RUNNER_ASSERT(controller.Value() == &thread); +} + +/* +Name: Controller_PostTimedEventToThread +Description: tests post events to other thread with time delay +Expected: thread id gathered in event handling method should match id of created thread +*/ +RUNNER_TEST(Controller_PostTimedEventToThread) +{ + ThreadController controller; + controller.Touch(); + + DPL::Thread thread; + thread.Run(); + + controller.SwitchToThread(&thread); + + DPL::WaitableEvent waitHandle; + + controller.PostTimedEvent(DoneSignalEvent(&waitHandle), 0.5); + + DPL::WaitForSingleHandle(waitHandle.GetHandle()); + + controller.SwitchToThread(NULL); + + RUNNER_ASSERT(controller.Value() == &thread); +} + +DECLARE_GENERIC_EVENT_2(TouchInThread, DPL::WaitableEvent *, DPL::Thread * *) +DECLARE_GENERIC_EVENT_2(TouchedControllerSignal, + DPL::WaitableEvent *, + DPL::Thread * *) + +class TouchInThreadController : + public DPL::Event::Controller::Type>, + private DPL::Event::Controller:: + Type> +{ + public: + typedef DPL::Event::Controller::Type> + PublicController; + typedef DPL::Event::Controller:: + Type> PrivateController; + + virtual void OnEventReceived(const TouchInThread &event) + { + // Touch controller in thread + PrivateController::Touch(); + + // Post signal + PrivateController::PostEvent(TouchedControllerSignal(event.GetArg0(), + event.GetArg1())); + } + + virtual void OnEventReceived(const TouchedControllerSignal &event) + { + // Return touched thread + *event.GetArg1() = DPL::Thread::GetCurrentThread(); + + // Signal waitable event + event.GetArg0()->Signal(); + } +}; + +/* +Name: Controller_TouchInThread +Description: tests ability to touch (initizilize / set destination thread) in creatd thread + other than thread were controlelr object was created +Expected: thread id gathered in event handling method should match id of created thread +*/ +RUNNER_TEST(Controller_TouchInThread) +{ + TouchInThreadController controller; + controller.PublicController::Touch(); + + DPL::Thread thread; + thread.Run(); + + controller.PublicController::SwitchToThread(&thread); + + DPL::WaitableEvent waitHandle; + DPL::Thread *touchedThread = NULL; + + controller.PublicController::PostEvent(TouchInThread(&waitHandle, + &touchedThread)); + + DPL::WaitForSingleHandle(waitHandle.GetHandle()); + + controller.PublicController::SwitchToThread(NULL); + + RUNNER_ASSERT(touchedThread == &thread); +} + +/* +Name: Controller_SynchronizedEvent +Description: tests ability to post synchronized events to ther thread +Expected: correct value should be saved when event was handled +*/ +RUNNER_TEST(Controller_SynchronizedEvent) +{ + IntController controller; + controller.Touch(); + + DPL::Thread thread; + thread.Run(); + + controller.SwitchToThread(&thread); + controller.PostSyncEvent(12345); + controller.SwitchToThread(NULL); + + RUNNER_ASSERT(controller.Value() == 12345); +} + +const int ControllersNumber = 5; +const int MaxEventsPerController = 1; +const int MaxEvents = ControllersNumber * MaxEventsPerController; +const int ControllersPerThread = 1; + +class TestController; //Forward Declaration + +typedef std::shared_ptr ControllerPtr; +typedef std::shared_ptr ThreadPtr; +typedef std::vector ControllerList; +typedef std::list ThreadList; + +DECLARE_GENERIC_EVENT_0(QuitEvent) +class QuitController : + public DPL::Event::Controller::Type>, + public DPL::ApplicationExt +{ + public: + explicit QuitController() : DPL::ApplicationExt(1, NULL, "test-app") + { + Touch(); + } + + protected: + virtual void OnEventReceived(const QuitEvent &) + { + Quit(); + } +}; + +struct TestContext +{ + ControllerList controllers; + ThreadList threads; + QuitController quitter; + DPL::Atomic g_ReceivedCounter; + DPL::Atomic g_SentCounter; +}; +typedef std::unique_ptr TestContextPtr; +TestContextPtr testContextPtr; + +DECLARE_GENERIC_EVENT_0(StartSendEvent) +DECLARE_GENERIC_EVENT_0(RandomEvent) +class TestController : + public DPL::Event::Controller::Type> +{ + public: + explicit TestController() + { + Touch(); + } + + protected: + virtual void OnEventReceived(const RandomEvent &) + { + ++testContextPtr->g_ReceivedCounter; + if (testContextPtr->g_ReceivedCounter == MaxEvents) { + testContextPtr->quitter.DPL::Event::ControllerEventHandler< + QuitEvent>::PostEvent(QuitEvent()); + return; + } + } + virtual void OnEventReceived(const StartSendEvent &) + { + for (int i = 0; i < MaxEventsPerController; ++i) { + if (testContextPtr->g_SentCounter > MaxEvents) { + return; + } + ++testContextPtr->g_SentCounter; + int id = rand_r(&seed) % static_cast(testContextPtr->controllers.size()); + testContextPtr->controllers.at(id)->DPL::Event:: + ControllerEventHandler::PostEvent(RandomEvent()); + } + } +}; + +/* +Name: Controllers_MultipleEvents +Description: tests controller coooperation. + This runs many controllers in many threads. Each controller sends + to other randomly chosen controller events. +Expected: Test is supposed to be ended when all limits of sent event will be reach + -> all scheduled event will be sent and received. +*/ +RUNNER_TEST(Controllers_MultipleEvents) +{ + srand(time(NULL) ); + + testContextPtr.reset(new TestContext()); + testContextPtr->controllers.reserve(ControllersNumber); + + for (int i = 0; i < ControllersNumber; ++i) { + if (testContextPtr->controllers.size() % ControllersPerThread == 0) { + ThreadPtr thread = ThreadPtr(new DPL::Thread()); + testContextPtr->threads.push_back(thread); + thread->Run(); + } + + ControllerPtr controller = ControllerPtr(new TestController()); + testContextPtr->controllers.push_back(controller); + if (testContextPtr->controllers.size() % 2 == 0) { + //This controller is being switched to thread (otherwise it is + // touched to main thread) + ThreadPtr thread = testContextPtr->threads.back(); + controller->SwitchToThread(thread.get()); + } + controller->DPL::Event::ControllerEventHandler:: + PostEvent(StartSendEvent()); + } + testContextPtr->quitter.Exec(); + RUNNER_ASSERT( + testContextPtr->g_SentCounter == testContextPtr->g_ReceivedCounter); + testContextPtr.reset(); +} diff --git a/tests/event/test_event_support.cpp b/tests/event/test_event_support.cpp new file mode 100644 index 0000000..d221fb9 --- /dev/null +++ b/tests/event/test_event_support.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_event_support.cpp + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file contains test for event support + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GENERIC_EVENT_0(TestEvent) + +class TestListener : public DPL::Event::EventListener +{ + public: + explicit TestListener() : m_dummyVar(0) { } + void OnEventReceived(const TestEvent &) + { + m_dummyVar = 1; + } + int GetDummyVar() const + { + return m_dummyVar; + } + void ZeroDummyVar() + { + m_dummyVar = 0; + } + + private: + int m_dummyVar; +}; + +class TestEventSupport : + public DPL::Event::EventSupport +{ + public: + void TestEmitEvent() + { + EmitEvent(TestEvent()); + } +}; + +DECLARE_GENERIC_EVENT_0(QuitEvent) + +class QuitController : + public DPL::Event::Controller::Type>, + public DPL::ApplicationExt +{ + public: + QuitController() : DPL::ApplicationExt(1, NULL, "test-app") + { + Touch(); + } + + protected: + virtual void OnEventReceived(const QuitEvent &) + { + Quit(); + } +}; + +/* +Name: EventSupport_DestroyBeforeProcessing +Description: tests if remoign listener is full successfull +Expected: dummy var should be affected by explicit call of ZeroDummyVar(), + but no by emitting event after removing listener +*/ +RUNNER_TEST(EventSupport_DestroyBeforeProcessing) +{ + QuitController quitter; + quitter.PostTimedEvent(QuitEvent(), 1.0); + + TestListener eventListener; + { + TestEventSupport eventSupport; + eventSupport.AddListener(&eventListener); + eventSupport.TestEmitEvent(); + eventSupport.RemoveListener(&eventListener); + } + eventListener.ZeroDummyVar(); + + quitter.Exec(); + RUNNER_ASSERT(eventListener.GetDummyVar() == 0); +} + +int g_delegateTest; + +void OnDelegateTest(const int &k); + +void OnDelegateTest(const int &k) +{ + LogDebug("Got delegate call"); + g_delegateTest = k; +} + +class DelegateTestSupport : + public DPL::Event::EventSupport +{ + public: + void Test() + { + EmitEvent(7); + } +}; + +/* +Name: EventSupport_BindDelegate +Description: tests if event support derived class successfully propagates + event to registered listener +Expected: value of event should be passed to listener +*/ +RUNNER_TEST(EventSupport_BindDelegate) +{ + g_delegateTest = 0; + + DelegateTestSupport support; + support.AddListener(&OnDelegateTest); + + QuitController quitter; + quitter.PostTimedEvent(QuitEvent(), 1.0); + + support.Test(); + + quitter.Exec(); + + support.RemoveListener(&OnDelegateTest); + + RUNNER_ASSERT(g_delegateTest == 7); +} diff --git a/tests/event/test_ic_delegate.cpp b/tests/event/test_ic_delegate.cpp new file mode 100644 index 0000000..460cfee --- /dev/null +++ b/tests/event/test_ic_delegate.cpp @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_ic_delegate.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of fast delegate tests. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +RUNNER_TEST_GROUP_INIT(DPL) + +const int IntVal = 123; +const std::string StringVal = "someString"; + +typedef DPL::Event::ICDelegate<> GetNothingDlpType; +typedef DPL::Event::ICDelegate GetIntDlgType; +typedef DPL::Event::ICDelegate GetIntAndStringDlgType; +DECLARE_GENERIC_EVENT_1(GetNothingEvent, GetNothingDlpType) +DECLARE_GENERIC_EVENT_1(GetIntEvent, GetIntDlgType) +DECLARE_GENERIC_EVENT_1(GetIntAndStringEvent, GetIntAndStringDlgType) + +class ICTestController : + public DPL::Event::Controller::Type> +{ + public: + ICTestController() { } + + protected: + virtual void OnEventReceived(const GetNothingEvent& event) + { + event.GetArg0() (); //calling intercontext delegate + } + virtual void OnEventReceived(const GetIntEvent& event) + { + event.GetArg0() (IntVal); //calling intercontext delegate + } + + virtual void OnEventReceived(const GetIntAndStringEvent& event) + { + event.GetArg0() (IntVal, StringVal); //calling intercontext delegate + } +}; + +struct TestResult +{ + TestResult() : + m_correctThread0(false), + m_correctThread1(false), + m_correctThread2(false), + m_int(-1), + m_int2(-1), + m_string("") + {} + + void TestEventsPassed() + { + RUNNER_ASSERT(m_correctThread0); + RUNNER_ASSERT(m_correctThread1); + RUNNER_ASSERT(m_int == IntVal); + RUNNER_ASSERT(m_correctThread2); + RUNNER_ASSERT(m_int2 == IntVal); + RUNNER_ASSERT(m_string == StringVal); + } + + void TestEventsDidNotPass() + { + RUNNER_ASSERT(!m_correctThread0); + RUNNER_ASSERT(!m_correctThread1); + RUNNER_ASSERT(m_int == -1); + RUNNER_ASSERT(!m_correctThread2); + RUNNER_ASSERT(m_int2 == -1); + RUNNER_ASSERT(m_string == ""); + } + + bool m_correctThread0; + bool m_correctThread1; + bool m_correctThread2; + int m_int; + int m_int2; + std::string m_string; +}; + +class TestContextFreeClass : + protected DPL::Thread, + public DPL::Event::ICDelegateSupport +{ + public: + TestContextFreeClass(ICTestController* controller, TestResult* result) : + Thread(), + m_testResult(result), + m_controller(controller) + { + LogDebug("Context thread id = " << this); + } + + void Run() + { + LogDebug("Running Context Free thread"); + Thread::Run(); + } + + void Quit() + { + LogDebug("Exiting Context Free thread"); + Thread::Quit(); + } + + void Wait() + { + LogDebug("Waiting for thread"); + DPL::WaitForSingleHandle(m_waitable.GetHandle()); + } + + protected: + void OnNothing() + { + LogDebug("Received nothing in thread = " << GetCurrentThread()); + m_testResult->m_correctThread0 = (GetCurrentThread() == this); + } + + void OnIntReceive(int val) + { + LogDebug("Received int in thread = " << GetCurrentThread()); + m_testResult->m_correctThread1 = (GetCurrentThread() == this); + m_testResult->m_int = val; + } + + void OnIntAndStringReceive(int val, std::string stringval) + { + LogDebug("Received int and string in thread = " << GetCurrentThread()); + m_testResult->m_correctThread2 = (GetCurrentThread() == this); + m_testResult->m_int2 = val; + m_testResult->m_string = stringval; + m_waitable.Signal(); + } + + virtual int ThreadEntry() + { + GetNothingEvent getNothingEvent( + makeICDelegate( + &TestContextFreeClass::OnNothing)); + m_controller->DPL::Event::ControllerEventHandler:: + PostEvent( + getNothingEvent); + + GetIntEvent getIntEvent( + makeICDelegate( + &TestContextFreeClass::OnIntReceive)); + m_controller->DPL::Event::ControllerEventHandler:: + PostEvent( + getIntEvent); + + GetIntAndStringEvent getIntAndStringEvent( + makeICDelegate( + &TestContextFreeClass::OnIntAndStringReceive)); + m_controller->DPL::Event::ControllerEventHandler + ::PostEvent( + getIntAndStringEvent); + + return Thread::ThreadEntry(); + } + + private: + TestResult* m_testResult; + DPL::WaitableEvent m_waitable; + ICTestController* m_controller; +}; + +/* +Name: ICDelegate_0 +Description: checks if delegetes are correctly called +Expected: delegates should be called from right context +*/ +RUNNER_TEST(ICDelegate_0) +{ + DPL::Thread thread; + thread.Run(); + LogDebug("Controller thread id = " << &thread); + + ICTestController testController; + testController.Touch(); + testController.SwitchToThread(&thread); + + TestResult result; + TestContextFreeClass* contextFree = + new TestContextFreeClass(&testController, &result); + result.TestEventsDidNotPass(); + + thread.Run(); + contextFree->Run(); + contextFree->Wait(); + contextFree->Quit(); + thread.Quit(); + + delete contextFree; + + result.TestEventsPassed(); +} + +/* +Name: ICDelegate_1 +Description: checks if delegetes are correctly called +Expected: delegates should be called from right context +*/ +RUNNER_TEST(ICDelegate_1) +{ + DPL::Thread thread; + LogDebug("Controller thread id = " << &thread); + + ICTestController testController; + testController.Touch(); + testController.SwitchToThread(&thread); + + TestResult result; + TestContextFreeClass* contextFree = + new TestContextFreeClass(&testController, &result); + result.TestEventsDidNotPass(); + + contextFree->Run(); + contextFree->Quit(); + delete contextFree; //deleting Delegates before actual Events are worked out + thread.Run(); + thread.Quit(); + + result.TestEventsDidNotPass(); +} + +class TestContextFree; +class TestRunnerInThread; + +namespace { +const int ControllersPerThread = 40; +const int ContextFreePerThread = 180; +const int TestsPerController = 110; +const int TestThreads = 23; +const int TestsPerThread = 100; +const int NumberOfEvents = 230; + +typedef std::shared_ptr ICTestControllerPtr; +typedef std::shared_ptr TestContextFreePtr; +typedef std::shared_ptr TestRunnerInThreadPtr; +typedef std::shared_ptr ThreadPtr; + +DPL::Mutex mutex; +std::list frees; +std::list ctrls; +std::list frees_threads; +std::list ctrls_threads; +} + +class TestContextFree : public DPL::Event::ICDelegateSupport +{ + public: + TestContextFree(ICTestController* controller, + int eventsCount) : + m_controller(controller), + m_eventsCount(eventsCount) + {} + + void Wait() + { + LogDebug("Waiting for thread"); + DPL::WaitForSingleHandle(m_waitable.GetHandle()); + } + + void OnNothing() + { + LogDebug("Got"); + m_eventsCount--; + if (m_eventsCount > 0) { + LogDebug("posting next event"); + GetIntAndStringEvent getIntAndStringEvent( + makeICDelegate( + &TestContextFree::OnIntAndStringReceive)); + LogDebug("posting next event ..."); + m_controller->DPL::Event::ControllerEventHandler< + GetIntAndStringEvent>::PostEvent( + getIntAndStringEvent); + LogDebug("posting next event done"); + } else { + LogDebug("test finished"); + m_waitable.Signal(); + } + } + + void OnIntReceive(int) + { + LogDebug("Got"); + m_eventsCount--; + if (m_eventsCount > 0) { + LogDebug("posting next event"); + GetNothingEvent getNothingEvent( + makeICDelegate( + &TestContextFree::OnNothing)); + LogDebug("posting next event ..."); + m_controller->DPL::Event::ControllerEventHandler:: + PostEvent( + getNothingEvent); + LogDebug("posting next event done"); + } else { + LogDebug("test finished"); + m_waitable.Signal(); + } + } + + void OnIntAndStringReceive(int, std::string) + { + LogDebug("Got"); + m_eventsCount--; + if (m_eventsCount > 0) { + LogDebug("posting next event"); + + GetIntEvent getIntEvent( + makeICDelegate( + &TestContextFree::OnIntReceive)); + LogDebug("posting next event ..."); + m_controller->DPL::Event::ControllerEventHandler:: + PostEvent( + getIntEvent); + LogDebug("posting next event done"); + } else { + LogDebug("test finished"); + m_waitable.Signal(); + } + } + + void StartTestOnNothing() + { + GetNothingEvent getNothingEvent( + makeICDelegate( + &TestContextFree::OnNothing)); + m_controller->DPL::Event::ControllerEventHandler:: + PostEvent( + getNothingEvent); + } + + void StartTestOnInt() + { + GetIntEvent getIntEvent( + makeICDelegate( + &TestContextFree::OnIntReceive)); + m_controller->DPL::Event::ControllerEventHandler:: + PostEvent( + getIntEvent); + } + + void StartTestOnIntAndString() + { + GetIntAndStringEvent getIntAndStringEvent( + makeICDelegate( + &TestContextFree::OnIntAndStringReceive)); + m_controller->DPL::Event::ControllerEventHandler + ::PostEvent( + getIntAndStringEvent); + } + + bool CheckTest() + { + LogDebug("Checking test result"); + return m_eventsCount == 0; + } + + private: + ICTestController* m_controller; + int m_eventsCount; + DPL::WaitableEvent m_waitable; +}; + +class TestRunnerInThread : public DPL::Thread +{ + public: + TestRunnerInThread(int events, int tests) : + m_eventsCount(events), + m_tests(tests) {} + + void WaitForInit() + { + LogDebug("Waiting for thread"); + DPL::WaitForSingleHandle(m_init.GetHandle()); + } + + protected: + virtual int ThreadEntry() + { + LogDebug("Thread starts"); + { + DPL::Mutex::ScopedLock lock(&mutex); + for (int i = 0; i < m_tests; ++i) { + if (i % TestsPerController == 0) { + if (ctrls.size() % ControllersPerThread == 0) { + ThreadPtr thread(new DPL::Thread()); + thread->Run(); + ctrls_threads.push_back(thread); + } + ICTestControllerPtr ptr(new ICTestController()); + ptr->Touch(); + ptr->SwitchToThread(ctrls_threads.back().get()); + ctrls.push_back(ptr); + + TestContextFreePtr t(new TestContextFree(ctrls.back().get(), + m_eventsCount)); + t->StartTestOnNothing(); + LogDebug(""); + frees.push_back(t); + } + } + } + m_init.Signal(); + LogDebug("Thread starts loop"); + return DPL::Thread::ThreadEntry(); + } + + private: + DPL::WaitableEvent m_init; + int m_eventsCount; + int m_tests; +}; + +/* +Name: ICDelegate_2 +Description: checks if delegetes are correctly called +Expected: delegates should be called from right context +*/ +RUNNER_TEST(ICDelegate_2) +{ + LogDebug("Creating test threads"); + for (int i = 0; i < TestThreads; ++i) { + TestRunnerInThreadPtr ptr( + new TestRunnerInThread(NumberOfEvents, TestsPerThread)); + frees_threads.push_back(ptr); + frees_threads.back()->Run(); + } + + FOREACH(it, frees_threads) { + (*it)->WaitForInit(); + } + LogDebug("Creating test threads done"); + + FOREACH(it, frees) { + LogDebug("..."); + (*it)->Wait(); + } + + FOREACH(it, frees) { + RUNNER_ASSERT((*it)->CheckTest()); + } + + frees.clear(); + + FOREACH(it, frees_threads) { + (*it)->Quit(); + } + + frees_threads.clear(); + + FOREACH(it, ctrls) { + (*it)->SwitchToThread(NULL); + } + + FOREACH(it, ctrls_threads) { + (*it)->Quit(); + } + + ctrls.clear(); + ctrls_threads.clear(); +} + +namespace ReuseCheck { +const int ReuseCount = 5; +typedef DPL::Event::ICDelegate<> GetNothingDlpType; +DECLARE_GENERIC_EVENT_1(ReuseCountEvent, GetNothingDlpType) + +class ICReuseTestController : + public DPL::Event::Controller::Type> +{ + public: + ICReuseTestController() + { + m_reuseCount = 0; + } + + protected: + virtual void OnEventReceived(const ReuseCountEvent& event) + { + event.GetArg0() (); //calling intercontext delegate + if (++m_reuseCount < ReuseCount) { + LogDebug("[Send] Reuse: " << m_reuseCount); + DPL::Event::ControllerEventHandler::PostEvent( + event); + } + } + + int m_reuseCount; +}; + +class ReuseTestContextFreeClass : + protected DPL::Thread, + public DPL::Event::ICDelegateSupport +{ + public: + ReuseTestContextFreeClass(ICReuseTestController* controller) : + Thread(), + m_controller(controller), + m_reuseCount(0) + { } + + void Run() + { + Thread::Run(); + } + void Quit() + { + Thread::Quit(); + } + void Wait() + { + DPL::WaitForSingleHandle(m_waitable.GetHandle()); + } + + protected: + void OnReuseReceive() + { + LogDebug("[Received] : " << ++m_reuseCount); + if (m_reuseCount == ReuseCount) { + m_waitable.Signal(); + } + } + + virtual int ThreadEntry() + { + ReuseCountEvent reuseEvent( + makeICDelegate( + &ReuseTestContextFreeClass::OnReuseReceive, + DPL::Event::ICD::Reuse::Yes)); + m_controller->DPL::Event::ControllerEventHandler:: + PostEvent( + reuseEvent); + + return Thread::ThreadEntry(); + } + + private: + DPL::WaitableEvent m_waitable; + ICReuseTestController* m_controller; + int m_reuseCount; +}; + +/* +Name: ICDelegate_3 +Description: checks if delegetes are correctly called +Expected: delegates should be called from right context +*/ +RUNNER_TEST(ICDelegate_3) +{ + DPL::Thread thread; + thread.Run(); + LogDebug("Controller thread id = " << &thread); + + ICReuseTestController testController; + testController.Touch(); + testController.SwitchToThread(&thread); + + ReuseTestContextFreeClass* contextFree = + new ReuseTestContextFreeClass(&testController); + + thread.Run(); + contextFree->Run(); + contextFree->Wait(); + contextFree->Quit(); + thread.Quit(); + + delete contextFree; + + RUNNER_ASSERT(true); +} +} //namespace ReuseCheck diff --git a/tests/event/test_property.cpp b/tests/event/test_property.cpp new file mode 100644 index 0000000..2760932 --- /dev/null +++ b/tests/event/test_property.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_property.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test property + */ +#include +#include +#include +#include + +namespace { +const int PROPERTY_VALUE_INT = 2; +const std::string PROPERTY_VALUE_STRING = "aaa"; +} + +int ReadSomething2(DPL::Event::Model */*model*/); +int ReadSomething2(DPL::Event::Model */*model*/) +{ + return PROPERTY_VALUE_INT; +} + +std::string ReadSomething(DPL::Event::Model */*model*/); +std::string ReadSomething(DPL::Event::Model */*model*/) +{ + return PROPERTY_VALUE_STRING; +} + +void WriteSomething(const std::string & /*value*/, DPL::Event::Model */*model*/); +void WriteSomething(const std::string & /*value*/, DPL::Event::Model */*model*/) +{} + +class MyModel : + public DPL::Event::Model +{ + public: + ~MyModel() {} + + DPL::Event::Property + Caption; + + DPL::Event::Property + Testproperty0; + + DPL::Event::Property + Testproperty1; + + DPL::Event::Property + Testproperty2; + + DPL::Event::Property Testproperty3; + + DPL::Event::Property Testproperty4; + + DPL::Event::Property + Testproperty5; + + MyModel() : + Caption(this, std::string("Foo caption")), + Testproperty0(this, std::string(""), &ReadSomething), + Testproperty1(this), + Testproperty2(this), + Testproperty3(this), + Testproperty4(this, std::string("test"), &ReadSomething, &WriteSomething), + Testproperty5(this, &ReadSomething2) + {} +}; + +std::string g_caption; + +void OnNameChanged(const DPL::Event::PropertyEvent &event); +void OnNameChanged(const DPL::Event::PropertyEvent &event) +{ + g_caption = event.value; +} + +/* +Name: Model_Test +Description: tests accessing and changing models properties +Expected: listener should get changed value +*/ +RUNNER_TEST(Model_Test) +{ + MyModel model; + + g_caption = "It is a bad caption"; + + model.Caption.AddListener(&OnNameChanged); + model.Caption.Set("Test name"); + + RUNNER_ASSERT(model.Testproperty4.Get() == PROPERTY_VALUE_STRING); + RUNNER_ASSERT(PROPERTY_VALUE_INT == model.Testproperty5.Get()); + RUNNER_ASSERT(g_caption == "Test name"); + RUNNER_ASSERT(model.Caption.Get() == "Test name"); + + model.Caption.RemoveListener(&OnNameChanged); +} diff --git a/tests/files_localization/CMakeLists.txt b/tests/files_localization/CMakeLists.txt new file mode 100644 index 0000000..3fdd256 --- /dev/null +++ b/tests/files_localization/CMakeLists.txt @@ -0,0 +1,43 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) +# @version 1.0 +# @brief +# + +# +# Test files +# +# Define all DPL tests sources. +# Runner is responsible for runnint it all and +# generating proper output files +# + +SET(TARGET_LOC "wrt-commons-tests-loc") + +SET(LOC_TESTS_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/test_localization.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_suite01.cpp +) + +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_LOC} ${TARGET_WRT_DAO_RW_LIB} ${TARGET_CUSTOM_HANDLER_DAO_RW_LIB}) +WRT_TEST_BUILD(${TARGET_LOC} ${LOC_TESTS_SOURCES}) +WRT_TEST_INSTALL(${TARGET_LOC}) + +ADD_SUBDIRECTORY(files) + +INSTALL(PROGRAMS "${CMAKE_CURRENT_SOURCE_DIR}/wrt_db_localization_prepare.sh" + DESTINATION bin) diff --git a/tests/files_localization/files/CMakeLists.txt b/tests/files_localization/files/CMakeLists.txt new file mode 100644 index 0000000..be10866 --- /dev/null +++ b/tests/files_localization/files/CMakeLists.txt @@ -0,0 +1,31 @@ +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/one + DESTINATION + /opt/share/widget/tests/localization/widget1/res/wgt/locales/pl-en + ) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/one + ${CMAKE_CURRENT_SOURCE_DIR}/two.html + DESTINATION + /opt/share/widget/tests/localization/widget2/res/wgt/locales/pl-en + ) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/two.html + DESTINATION + /opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en + ) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/icon + DESTINATION + /opt/share/widget/tests/localization/widget1/res/wgt/locales/pl-en + ) + +INSTALL(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/icon2 + DESTINATION + /opt/share/widget/tests/localization/widget1/res/wgt/locales/pl-en + ) + diff --git a/tests/files_localization/files/icon b/tests/files_localization/files/icon new file mode 100644 index 0000000..e69de29 diff --git a/tests/files_localization/files/icon2 b/tests/files_localization/files/icon2 new file mode 100644 index 0000000..e69de29 diff --git a/tests/files_localization/files/one b/tests/files_localization/files/one new file mode 100644 index 0000000..e69de29 diff --git a/tests/files_localization/files/two.html b/tests/files_localization/files/two.html new file mode 100644 index 0000000..e69de29 diff --git a/tests/files_localization/test_localization.cpp b/tests/files_localization/test_localization.cpp new file mode 100644 index 0000000..ae4925a --- /dev/null +++ b/tests/files_localization/test_localization.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main + */ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + + int ret = system("/usr/bin/wrt_db_localization_prepare.sh start"); + if (ret != 0) { + LogError("Preparation script has return error: " << ret + << ". Quitting"); + return -1; + } + + WrtDB::WrtDatabase::attachToThreadRW(); + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); + WrtDB::WrtDatabase::detachFromThread(); + + ret = system("/usr/bin/wrt_db_localization_prepare.sh stop"); + if (ret != 0) { + LogError("Preparation script has return error: " << ret + << ". Quitting"); + return -1; + } + return status; +} + diff --git a/tests/files_localization/test_suite01.cpp b/tests/files_localization/test_suite01.cpp new file mode 100644 index 0000000..d163d1d --- /dev/null +++ b/tests/files_localization/test_suite01.cpp @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * This file contains the declaration of widget dao class. + * + * @file test_suite01.cpp + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief + */ + +#include +#include +#include +#include +#include +#include + +namespace { + +STATIC_BLOCK +{ + WrtDB::LanguageTagList tags; + tags.push_back(L"pl-pl"); + tags.push_back(L"en-en"); + tags.push_back(L"pl-en"); + LanguageTagsProviderSingleton::Instance().setLanguageTags(tags); +} + +static const DPL::String widget1Path = + L"/opt/share/widget/tests/localization/widget1/"; +static const DPL::String widget2Path = + L"/opt/share/widget/tests/localization/widget2/"; + + +const std::string appId1("tizenid201"); +const std::string appId2("tizenid202"); + +} // anonymous namespace + +RUNNER_TEST(test01_getFilePathInWidgetPackageFromUrl){ + WrtDB::TizenAppId name = L"tizenid201"; //no difference if it is valid or invalid appId/pkgId, we fill database which has no intergrity constrainst + WrtDB::WidgetDAOReadOnly dao(name); + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"widget://one")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget1/res/wgt/locales/pl-en/one"); +} + +RUNNER_TEST(test02_getFilePathInWidgetPackageFromUrl){ + WrtDB::TizenAppId name = L"tizenid202"; + WrtDB::WidgetDAOReadOnly dao(name); + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"widget://one")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/pl-en/one"); +} + +RUNNER_TEST(test03_getFilePathInWidgetPackageFromUrl){ + WrtDB::TizenAppId name = L"tizenid202"; + WrtDB::WidgetDAOReadOnly dao(name); + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"widget://two.html")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test04_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"widget://two.html?a=1#b")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html?a=1#b"); +} + +RUNNER_TEST(test05_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"widget://two.html#a?b")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html#a?b"); +} + +RUNNER_TEST(test06_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"file://two.html")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test07_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"file:///opt/share/widget/tests/localization/widget2/res/wgt/two.html")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test08_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"file:///opt/share/widget/tests/localization/widget2/res/wgt/locales/pl-en/two.html")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test09_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"app://two.html")); + + RUNNER_ASSERT(result.IsNull()); +} + +RUNNER_TEST(test10_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"app://tizenid202/two.html")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT( + *result == + L"/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test11_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"dummy")); + + RUNNER_ASSERT(result.IsNull()); +} + +RUNNER_TEST(test12_getFilePathInWidgetPackageFromUrl) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl( + name, + DPL::String(L"app://tizenid202/notExisingFIle")); + + RUNNER_ASSERT(result.IsNull()); +} + +RUNNER_TEST(test13_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId1, "widget://one"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget1/res/wgt/locales/pl-en/one"); +} + +RUNNER_TEST(test14_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "widget://one"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/pl-en/one"); +} + +RUNNER_TEST(test15_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "widget://two.html"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test16_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "widget://two.html?a=1#b"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html?a=1#b"); +} + +RUNNER_TEST(test17_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "widget://two.html#a?b"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html#a?b"); +} + +RUNNER_TEST(test18_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "file://two.html"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test19_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, + "file:///opt/share/widget/tests/localization/widget2/res/wgt/two.html"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test20_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, + "file:///opt/share/widget/tests/localization/widget2/res/wgt/locales/pl-en/two.html"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test21_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "app://two.html"); + + RUNNER_ASSERT(result.empty()); +} + +RUNNER_TEST(test22_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "app://tizenid202/two.html"); + + RUNNER_ASSERT_MSG(!result.empty(), "No result"); + RUNNER_ASSERT(result == "/opt/share/widget/tests/localization/widget2/res/wgt/locales/en-en/two.html"); +} + +RUNNER_TEST(test23_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, "dummy"); + + RUNNER_ASSERT(result.empty()); +} + +RUNNER_TEST(test24_getFilePathInWidgetPackageFromUrl2) +{ + std::string result = W3CFileLocalization::getFilePathInWidgetPackageFromUrl(appId2, + "app://tizenid202/notExisingFIle"); + + RUNNER_ASSERT(result.empty()); +} + +RUNNER_TEST(test25_getFilePathInWidgetPackage) +{ + WrtDB::TizenAppId name = L"tizenid201"; + WrtDB::WidgetDAOReadOnly dao(name); + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackage( + name, + DPL::String(L"one")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT(*result == L"locales/pl-en/one"); +} + +RUNNER_TEST(test26_getFilePathInWidgetPackage) +{ + WrtDB::TizenAppId name = L"tizenid202"; + WrtDB::WidgetDAOReadOnly dao(name); + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackage( + name, + DPL::String(L"two.html")); + + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT(*result == L"locales/en-en/two.html"); +} + +RUNNER_TEST(test27_getFilePathInWidgetPackage) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + DPL::Optional result = W3CFileLocalization::getFilePathInWidgetPackage(name, L""); + RUNNER_ASSERT(result.IsNull()); + + result = W3CFileLocalization::getFilePathInWidgetPackage(name, L"/"); + RUNNER_ASSERT(result.IsNull()); + + result = W3CFileLocalization::getFilePathInWidgetPackage(name, L"//"); + RUNNER_ASSERT(result.IsNull()); + + result = W3CFileLocalization::getFilePathInWidgetPackage(name, L"dummy"); + RUNNER_ASSERT(result.IsNull()); + + result = W3CFileLocalization::getFilePathInWidgetPackage(name, L"/two.html/"); + RUNNER_ASSERT_MSG(!!result, "No result"); + RUNNER_ASSERT(*result == L"locales/en-en/two.html"); +} + +RUNNER_TEST(test28_getValidIconsList) +{ + WrtDB::TizenAppId name = L"not existing"; + + bool exceptionCaught = false; + + try { + W3CFileLocalization::WidgetIconList result = W3CFileLocalization::getValidIconsList(name); + } catch (WrtDB::WidgetDAOReadOnly::Exception::WidgetNotExist&) { + exceptionCaught = true; + } + RUNNER_ASSERT(exceptionCaught); +} + +RUNNER_TEST(test29_getValidIconsList) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + W3CFileLocalization::WidgetIconList result = W3CFileLocalization::getValidIconsList(name); + RUNNER_ASSERT(result.empty()); +} + + +RUNNER_TEST(test30_getValidIconsList) +{ + WrtDB::TizenAppId name = L"tizenid201"; + + W3CFileLocalization::WidgetIconList result = W3CFileLocalization::getValidIconsList(name); + RUNNER_ASSERT(result.size() == 2); + W3CFileLocalization::WidgetIconList::iterator iter = result.begin(); + RUNNER_ASSERT(iter->src == L"icon"); + RUNNER_ASSERT(iter->height == 250); + RUNNER_ASSERT(iter->width == 251); + iter++; + RUNNER_ASSERT(iter->src == L"icon2"); + RUNNER_ASSERT(iter->height == 252); + RUNNER_ASSERT(iter->width == 253); +} + +RUNNER_TEST(test31_getStartFileInfo) +{ + WrtDB::TizenAppId name = L"not existing"; + + bool exceptionCaught = false; + + try { + OptionalWidgetStartFileInfo result = W3CFileLocalization::getStartFileInfo(name); + } catch (WrtDB::WidgetDAOReadOnly::Exception::WidgetNotExist&) { + exceptionCaught = true; + } + RUNNER_ASSERT(exceptionCaught); +} + +RUNNER_TEST(test32_getStartFileInfo) +{ + WrtDB::TizenAppId name = L"tizenid202"; + + OptionalWidgetStartFileInfo result = W3CFileLocalization::getStartFileInfo(name); + RUNNER_ASSERT(result.IsNull()); +} + + +RUNNER_TEST(test33_getStartFileInfo) +{ + WrtDB::TizenAppId name = L"tizenid201"; + + OptionalWidgetStartFileInfo result = W3CFileLocalization::getStartFileInfo(name); + RUNNER_ASSERT(!result.IsNull()); + RUNNER_ASSERT(result->file == L"start_file"); + RUNNER_ASSERT(result->localizedPath == L"locales/en-en/start_file"); +} diff --git a/tests/files_localization/wrt_db_localization_prepare.sh b/tests/files_localization/wrt_db_localization_prepare.sh new file mode 100644 index 0000000..29c3806 --- /dev/null +++ b/tests/files_localization/wrt_db_localization_prepare.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +set -e + +trap 'echo "Script failed"; exit 1' ERR + +WRT_DB=/opt/dbspace/.wrt.db +WRT_DB_BCK=/tmp/wrt.db_backup +WIDGET_INSTALL_PATH=/opt/usr/apps + +case $1 in + start) + echo "start" + cp $WRT_DB $WRT_DB_BCK + wrt_commons_create_clean_db.sh + + #Widgets + INS_ALL_WIDGETEXT="insert into WidgetExtendedInfo(app_id, installed_path)" + INS_ALL_WIDGET="insert into WidgetInfo(app_id, tizen_appid)" + INS_ALL_ICON="insert into WidgetIcon(icon_id, app_id, icon_src, icon_width, icon_height)" + INS_ALL_LOCALIZED_START_FILE="insert into WidgetLocalizedStartFile(app_id, start_file_id, widget_locale, type, encoding)" + INS_ALL_START_FILE="insert into WidgetStartFile(start_file_id, app_id, src)" + + sqlite3 $WRT_DB "${INS_ALL_WIDGET} VALUES(1, 'tizenid201')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGET} VALUES(2, 'tizenid202')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGETEXT} VALUES(1, '/opt/share/widget/tests/localization/widget1')"; + sqlite3 $WRT_DB "${INS_ALL_WIDGETEXT} VALUES(2, '/opt/share/widget/tests/localization/widget2')"; + sqlite3 $WRT_DB "${INS_ALL_ICON} VALUES(1,1,'icon',251,250)"; + sqlite3 $WRT_DB "${INS_ALL_ICON} VALUES(2,1,'icon2',253,252)"; + sqlite3 $WRT_DB "${INS_ALL_LOCALIZED_START_FILE} VALUES(1,2,'en-en','test','test')"; + sqlite3 $WRT_DB "${INS_ALL_START_FILE} VALUES(2,1,'start_file')"; + exit 0 + ;; + stop) + echo "stop"; + cp $WRT_DB_BCK $WRT_DB + exit 0 + ;; + *) + echo "nothing to do" + exit 1 + ;; +esac diff --git a/tests/i18n/CMakeLists.txt b/tests/i18n/CMakeLists.txt new file mode 100644 index 0000000..9a90b43 --- /dev/null +++ b/tests/i18n/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) +# @version 1.0 +# @brief +# + +# +# Test files +# +# Define all DPL tests sources. +# Runner is responsible for runnint it all and +# generating proper output files +# + +SET(TARGET_NAME "wrt-commons-tests-i18n") + +# Set DPL tests sources +SET(DPL_TESTS_I18N_SOURCES + ${TESTS_DIR}/i18n/main.cpp + ${TESTS_DIR}/i18n/test_i18n_dao_read_only.cpp +) + +#include subdirectory +WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_I18N_DAO_RO_LIB}) +WRT_TEST_BUILD(${TARGET_NAME} ${DPL_TESTS_I18N_SOURCES}) +WRT_TEST_INSTALL(${TARGET_NAME}) diff --git a/tests/i18n/main.cpp b/tests/i18n/main.cpp new file mode 100644 index 0000000..4ed6191 --- /dev/null +++ b/tests/i18n/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file main.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main. + */ + +#include + +int main(int argc, char *argv[]) +{ + return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); +} diff --git a/tests/i18n/test_i18n_dao_read_only.cpp b/tests/i18n/test_i18n_dao_read_only.cpp new file mode 100644 index 0000000..57dfe2d --- /dev/null +++ b/tests/i18n/test_i18n_dao_read_only.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_i18n_dao_read_only.cpp + * @author Zbigniew Kostrzewa (z.kostrzewa@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of i18n dao tests + */ +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(I18N) + +/* +Name: I18nDAOReadOnly_IsValidSubTag_True +Description: Test valid IANA subtag presence +Expected: Subtag found +*/ +RUNNER_TEST(I18nDAOReadOnly_IsValidSubTag_True) +{ + I18n::DB::Interface::attachDatabaseRO(); + bool result = I18n::DB::I18nDAOReadOnly::IsValidSubTag(L"aa", 0); + I18n::DB::Interface::detachDatabase(); + RUNNER_ASSERT_MSG(result, "Subtag not found"); +} + +/* +Name: I18nDAOReadOnly_IsValidSubTag_False +Description: Test invalid IANA subtag presence +Expected: Subtag not found +*/ +RUNNER_TEST(I18nDAOReadOnly_IsValidSubTag_False) +{ + I18n::DB::Interface::attachDatabaseRO(); + bool result = I18n::DB::I18nDAOReadOnly::IsValidSubTag(L"xxx000xxx", -1); + I18n::DB::Interface::detachDatabase(); + RUNNER_ASSERT_MSG(!result, "Subtag found"); +} diff --git a/tests/localizationTagsProvider/CMakeLists.txt b/tests/localizationTagsProvider/CMakeLists.txt new file mode 100644 index 0000000..fb3fee7 --- /dev/null +++ b/tests/localizationTagsProvider/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Marcin Kaminski (marcin.ka@samsung.com) +# @author Karol Pawlowski (k.pawlowski@samsung.com) +# @version 1.0 +# @brief +# + +SET(LOCALIZATION_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +PKG_CHECK_MODULES(TEST_PKGS + vconf + REQUIRED + ) + +WRT_INCLUDE_DIRECTORIES( + ${TEST_PKGS_INCLUDE_DIRS} + ${PROJECT_SOURCE_DIR}/modules/localization/include + ) + +WRT_LINK_DIRECTORIES(${TEST_PKGS_LIBRARY_DIRS}) +WRT_TARGET_LINK_LIBRARIES(${TEST_PKGS_LIBRARIES}) + +FILE(GLOB LOCALIZATION_TESTS_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*testcases.cpp") + +SET(TARGET_LOCALIZATION_TEST "wrt-commons-tests-localization") +WRT_TEST_BUILD(${TARGET_LOCALIZATION_TEST} ${LOCALIZATION_TESTS_SOURCES} tests_miscunit.cpp) +WRT_TEST_INSTALL(${TARGET_LOCALIZATION_TEST}) + diff --git a/tests/localizationTagsProvider/Localization_testcases.cpp b/tests/localizationTagsProvider/Localization_testcases.cpp new file mode 100644 index 0000000..295ca7c --- /dev/null +++ b/tests/localizationTagsProvider/Localization_testcases.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file Localization_testcases.cpp + * @author Marcin Kaminski (marcin.ka@samsung.com) + * @version 1.0 + * @brief This file contains tests for localization related code. + */ + +#include +#include +#include + +#include + +RUNNER_TEST_GROUP_INIT(LanguageTagsProvider) + +RUNNER_TEST(tagsFromSystemLocales) +{ + LogDebug("Generating tags from system locales"); + + char* currlocals = vconf_get_str(VCONFKEY_LANGSET); + LogDebug("Locales fetched from system settings: " << currlocals); + RUNNER_ASSERT_MSG(!!currlocals, "NULL locales received from system"); + int result = vconf_set_str(VCONFKEY_LANGSET, "en_US.UTF-8"); + LogDebug("Returned vconf set execution status: " << result); + RUNNER_ASSERT_MSG(result == 0, "Invalid value returned by vconf_set_str on setting locales"); + + /* Ensure that system locales where fetched */ + LanguageTagsProviderSingleton::Instance().resetLanguageTags(); + LogDebug("Language tags set based on current system locales"); + + LanguageTags ltlist = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + RUNNER_ASSERT_MSG(!ltlist.empty(), "Empty tag list returned"); + + /* Correct list generated from given locales should contain: "en-US", "en" and "" */ + LanguageTags correct; + correct.push_back(L"en-US"); + correct.push_back(L"en"); + correct.push_back(L""); + + RUNNER_ASSERT_MSG( correct==ltlist, "Received and expected language tags lists differ"); + + /* Restore system locales */ + result = vconf_set_str(VCONFKEY_LANGSET, currlocals); + RUNNER_ASSERT_MSG(result == 0, "Invalid value returned by vconf_set_str on restoring locales"); + LogDebug("System locales restored"); +} + +RUNNER_TEST(tagsFromGivenLocales) +{ + LogDebug("Generating tags from given locales"); + + const char *locales1 = "it_IT.UTF-8", *locales2="en_GB"; + + LogDebug("Using locales with codepage: " << locales1); + LanguageTagsProviderSingleton::Instance().setLanguageTagsFromLocales(locales1); + LanguageTags ltlist = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + /* Correct list generated from given locales should contain: "it-IT", "it" and + * two default values: "en" and "" */ + LanguageTags correct; + correct.push_back(L"it-IT"); + correct.push_back(L"it"); + correct.push_back(L""); + RUNNER_ASSERT_MSG(correct==ltlist, "Received and expected language tags lists differ"); + + LogDebug("Using locales without codepage: " << locales2); + LanguageTagsProviderSingleton::Instance().setLanguageTagsFromLocales(locales2); + ltlist = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + correct.clear(); + correct.push_back(L"en-GB"); + correct.push_back(L"en"); + correct.push_back(L""); + RUNNER_ASSERT_MSG(correct==ltlist, "Received and expected language tags lists differ"); +} + +RUNNER_TEST(tagsFromNullLocales) +{ + LogDebug("Generating tags when NULL locales given"); + + LanguageTagsProviderSingleton::Instance().setLanguageTagsFromLocales(NULL); + LanguageTags ltlist = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + /* List with two values "en" and "" should be returned */ + LanguageTags correct; + correct.push_back(L""); + RUNNER_ASSERT_MSG(correct==ltlist, "Received and expected language tags lists differ"); +} + + +RUNNER_TEST(tagsFromGivenTagList) +{ + LogDebug("Copying given tags list"); + + LogDebug("Correct full list (with default values)"); + LanguageTags correct; + correct.push_back(L"de-DE"); + correct.push_back(L"de"); + correct.push_back(L""); + LanguageTagsProviderSingleton::Instance().setLanguageTags(correct); + LanguageTags result = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + RUNNER_ASSERT_MSG(correct==result, "Received and expected language tags lists differ"); + + LogDebug("Tags list without default values)"); + LanguageTags nondef; + nondef.push_back(L"de-DE"); + nondef.push_back(L"de"); + LanguageTagsProviderSingleton::Instance().setLanguageTags(correct); + result = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + + /* Received list should contains elements from input list with default + * values added (as "correct" list has) */ + RUNNER_ASSERT_MSG(!result.empty(), "Empty tags list should never be returned"); + RUNNER_ASSERT_MSG(nondef!=result, "Received list is same as given incomplete one"); + RUNNER_ASSERT_MSG(correct==result, "Received and expected language tags lists differ"); +} + +RUNNER_TEST(tagsFromEmptyList) +{ + LogDebug("Generating tags when empty tag list given"); + + LanguageTags input; + LanguageTagsProviderSingleton::Instance().setLanguageTags(input); + LanguageTags result = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + RUNNER_ASSERT_MSG(!result.empty(), "Empty tags list should never be returned"); +} + +RUNNER_TEST(defaultWidgetLocale) +{ + LogDebug("Adding default widget locales to language tags list"); + + LanguageTags input; + input.push_back(L"de-DE"); + input.push_back(L"de"); + input.push_back(L""); + LanguageTagsProviderSingleton::Instance().setLanguageTags(input); + LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(L"it"); + LanguageTags result = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + RUNNER_ASSERT_MSG(result.size() == 4, "4 different language tags expected"); + LanguageTags reference; + reference.push_back(L"de-DE"); + reference.push_back(L"de"); + reference.push_back(L"it"); + reference.push_back(L""); + RUNNER_ASSERT_MSG(result == reference, "Received and expected language tags lists differ"); + LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(L"it"); + LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(L"de-DE"); + result = LanguageTagsProviderSingleton::Instance().getLanguageTags(); + RUNNER_ASSERT_MSG(result == reference, "Adding already included tag should not change tags list"); +} diff --git a/tests/localizationTagsProvider/README b/tests/localizationTagsProvider/README new file mode 100644 index 0000000..366e961 --- /dev/null +++ b/tests/localizationTagsProvider/README @@ -0,0 +1,13 @@ +Miscellaneous test suite +Unit tests (manifest files, wrt-api). Internal tests for new features in wrt. + +Binary file: wrt-tests-misc. Uses our test framework. Allows to use different +types of output. Text output shows results on console - green passed. +To run: +1. Install wrt-extra on target +2. Run wrt-tests-localization --output=text + +Automatic: YES +Included in Daily Build: NO +Included in Gerrit Builds: NO +Number of test cases: 75 \ No newline at end of file diff --git a/tests/localizationTagsProvider/tests_miscunit.cpp b/tests/localizationTagsProvider/tests_miscunit.cpp new file mode 100644 index 0000000..430cccf --- /dev/null +++ b/tests/localizationTagsProvider/tests_miscunit.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file tests_miscunit.cpp + * @author Marcin Kaminski (marcin.ka@samsung.com) + * @version 1.0 + * @brief This is main file for miscellaneous unit tests (tests of different + * classes, namespaces and functions). + */ + +#include +#include + +int main (int argc, char *argv[]) +{ + LogDebug("Starting miscellaneous unit tests"); + int status = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); + + return status; +} diff --git a/tests/test/CMakeLists.txt b/tests/test/CMakeLists.txt new file mode 100644 index 0000000..ece6879 --- /dev/null +++ b/tests/test/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) +# @version 1.0 +# @brief +# + +SET(TARGET_NAME "wrt-commons-tests-test") + +# Set DPL tests sources +SET(DPL_TESTS_UTIL_SOURCES + ${TESTS_DIR}/test/main.cpp + ${TESTS_DIR}/test/runner_multiprocess.cpp + ${TESTS_DIR}/test/runner_child.cpp + ${TESTS_DIR}/test/test_process_pipe.cpp + ${TESTS_DIR}/test/test_abstract_input_reader.cpp + ${TESTS_DIR}/test/test_value_separated_reader.cpp +) + +#WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_DPL_UTILS_EFL}) +WRT_TEST_BUILD(${TARGET_NAME} ${DPL_TESTS_UTIL_SOURCES}) +WRT_TEST_INSTALL(${TARGET_NAME}) diff --git a/tests/test/main.cpp b/tests/test/main.cpp new file mode 100644 index 0000000..42ffe3a --- /dev/null +++ b/tests/test/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main + */ +#include + +int main(int argc, char *argv[]) +{ + return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); +} + diff --git a/tests/test/runner_child.cpp b/tests/test/runner_child.cpp new file mode 100644 index 0000000..6dfc30d --- /dev/null +++ b/tests/test/runner_child.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file widget_version.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief Implementation file for test cases for engine internal tests + */ +#include +#include +#include +#include +#include +#include + + +namespace { +enum class TestResult +{ + PASS, + FAIL, + IGNORED, + TIMEOUT, + UNKNOWN +}; +} + +#define RUNNER_CHILD_TEST_EXPECT(name, result, message) \ + static void testExpectFunction##name(); \ + RUNNER_TEST(name) \ + { \ + TestResult eResult = result; \ + TestResult rResult = TestResult::UNKNOWN; \ + std::string eMessage = message; \ + Try \ + { \ + DPL::Test::RunChildProc(&testExpectFunction##name); \ + } \ + Catch(DPL::Test::TestRunner::TestFailed) \ + { \ + std::string rMessage = _rethrown_exception.GetMessage(); \ + size_t pos = rMessage.find(")"); \ + if(pos != std::string::npos && pos+2 <= rMessage.length()) \ + { \ + rMessage = rMessage.substr(pos+2); \ + } \ + if(rMessage == "Timeout") \ + { \ + rResult = TestResult::TIMEOUT; \ + } \ + else if(rMessage == "Ignored") \ + { \ + rResult = TestResult::IGNORED; \ + } \ + else if(rMessage == eMessage) \ + { \ + rResult = TestResult::FAIL; \ + } \ + else \ + { \ + RUNNER_ASSERT_MSG(false, "Fail message do not matches"); \ + } \ + } \ + if(rResult == TestResult::UNKNOWN) \ + { \ + rResult = TestResult::PASS; \ + } \ + RUNNER_ASSERT_MSG(eResult == rResult, "Expected other result"); \ + } \ + void testExpectFunction##name() \ + + +RUNNER_TEST_GROUP_INIT(DPL_TESTS_TEST_CHILD) + +RUNNER_CHILD_TEST_EXPECT(t00_pass, TestResult::PASS, "") +{ + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_CHILD_TEST_EXPECT(t01_pass, TestResult::PASS, "") +{ + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_CHILD_TEST_EXPECT(t02_fail, TestResult::FAIL, "This test should fail") +{ + RUNNER_ASSERT_MSG(0, "This test should fail"); +} + +RUNNER_CHILD_TEST_EXPECT(t03_fail_timeout, TestResult::TIMEOUT, "") +{ + sleep(20); + RUNNER_ASSERT_MSG(1, "This test should fail"); +} + +RUNNER_CHILD_TEST_EXPECT(t04_fail, TestResult::FAIL, "This test should fail") +{ + RUNNER_ASSERT_MSG(1, "This test should fail"); + RUNNER_ASSERT_MSG(1, "This test should fail"); + RUNNER_ASSERT_MSG(1, "This test should fail"); + RUNNER_ASSERT_MSG(1, "This test should fail"); + RUNNER_ASSERT_MSG(0, "This test should fail"); +} + +RUNNER_CHILD_TEST_EXPECT(t05_fail_child_died, TestResult::FAIL, "Reading pipe error") +{ + kill(getpid(), SIGKILL); + RUNNER_ASSERT_MSG(1, "This test should fail"); +} + +RUNNER_CHILD_TEST_EXPECT(t06_pass_8_second_test, TestResult::PASS, "") +{ + sleep(8); + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_CHILD_TEST_EXPECT(t07_fail_unknown_exception, TestResult::FAIL, "unhandled exeception") +{ + throw("hello"); +} + +RUNNER_CHILD_TEST_EXPECT(t08_fail_unknown_exception, TestResult::FAIL, "unhandled exeception") +{ + throw(1); +} + +RUNNER_CHILD_TEST_EXPECT(t09_fail_you_should_see_text_normal_assert, TestResult::FAIL, "Normal assert") +{ + RUNNER_ASSERT_MSG(0, "Normal assert"); +} + +RUNNER_CHILD_TEST_EXPECT(t10_pass, TestResult::PASS, "") +{ + RUNNER_ASSERT_MSG(1, "Normal assert"); +} + +RUNNER_CHILD_TEST_EXPECT(t11_ignore, TestResult::IGNORED, "Test ignored") +{ + RUNNER_IGNORED_MSG("Test ignored"); +} + + diff --git a/tests/test/runner_multiprocess.cpp b/tests/test/runner_multiprocess.cpp new file mode 100644 index 0000000..fcac88e --- /dev/null +++ b/tests/test/runner_multiprocess.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file runner_multiprocess.cpp + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief Implementation file for test cases for engine internal tests + */ + +#include +#include +#include +#include + +namespace { +std::list split_string(std::string str, std::string delimiter) +{ + size_t pos = 0; + std::string token; + std::list stringList; + while ((pos = str.find(delimiter)) != std::string::npos) { + token = str.substr(0, pos); + stringList.push_back(token); + str.erase(0, pos + delimiter.length()); + } + if(str.length() != 0){ + stringList.push_back(token); + } + return stringList; +} +} + +#define RUNNER_MULTIPROCESS_TEST_EXPECT(name, messages) \ + static void testExpectFunction##name(); \ + RUNNER_TEST(name) \ + { \ + Try \ + { \ + DPL::Test::RunMultiProc(&testExpectFunction##name); \ + } \ + Catch(DPL::Test::TestRunner::TestFailed) \ + { \ + std::string eMsg = messages; \ + std::list eMessages = split_string(eMsg, "|"); \ + std::string rMessage = _rethrown_exception.GetMessage(); \ + if(eMsg.length() == 0 && rMessage.length() != 0) { \ + RUNNER_ASSERT_MSG(false, rMessage); \ + } \ + bool failedFound = false; \ + for(std::list::iterator it = eMessages.begin(); \ + it != eMessages.end(); \ + ++it) \ + { \ + if (!(*it).compare("TEST_FAILED")) { \ + failedFound = true; \ + continue; \ + } \ + RUNNER_ASSERT_MSG(rMessage.find(*it)!=std::string::npos, \ + "Key word " << *it << " not found in " << rMessage); \ + } \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Reading pipe error")==std::string::npos, \ + "Reading pipe error"); \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Timeout error")==std::string::npos, \ + "Timeout error"); \ + RUNNER_ASSERT_MSG(failedFound, "No TEST_FAILED found"); \ + } \ + Catch(DPL::Test::TestRunner::Ignored) \ + { \ + std::string eMsg = messages; \ + std::list eMessages = split_string(eMsg, "|"); \ + std::string rMessage = _rethrown_exception.GetMessage(); \ + if(eMsg.length() == 0 && rMessage.length() != 0) { \ + RUNNER_ASSERT_MSG(false, rMessage); \ + } \ + bool ignoredFound = false; \ + for(std::list::iterator it = eMessages.begin(); \ + it != eMessages.end(); \ + ++it) \ + { \ + if (!(*it).compare("TEST_IGNORED")) { \ + ignoredFound = true; \ + continue; \ + } \ + RUNNER_ASSERT_MSG(rMessage.find(*it)!=std::string::npos, \ + "Key word " << *it << " not found in " << rMessage); \ + } \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Reading pipe error")==std::string::npos, \ + "Reading pipe error"); \ + RUNNER_ASSERT_MSG( \ + rMessage.find("Timeout error")==std::string::npos, \ + "Timeout error"); \ + RUNNER_ASSERT_MSG(ignoredFound, "No TEST_IGNORED found"); \ + } \ + } \ + void testExpectFunction##name() \ + +RUNNER_TEST_GROUP_INIT(DPL_TESTS_TEST_MULTIPROCESS) + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm00_pass, "") +{ + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm01_pass, "") +{ + pid_t pid = fork(); + if(pid){ + sleep(2); + RUNNER_ASSERT_MSG(1, "This test should pass"); + } else { + RUNNER_ASSERT_MSG(1, "This test should pass"); + } + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm02_pass, "") +{ + pid_t pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(1, "This test should pass"); + } else { + sleep(2); + RUNNER_ASSERT_MSG(1, "This test should pass"); + } + RUNNER_ASSERT_MSG(1, "This test should pass"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm03_pass, "") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + sleep(1); + } else { + sleep(2); + } + } else { + if(pid){ + sleep(2); + } else { + sleep(1); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm04_fail, "TEST_FAILED|" + "This test should fail") +{ + RUNNER_ASSERT_MSG(0, "This test should fail"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm05_fail,"TEST_FAILED|" + "Test failed 1|" + "Test failed 2|" + "Test failed 3|" + "Test failed 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 2"); + } + } else { + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 3"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm06_fail, "TEST_FAILED|" + "Test failed 1|" + "Test failed 2|" + "Test failed 3|" + "Test failed 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + sleep(2); + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 2"); + } + } else { + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 3"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm07_fail, "TEST_FAILED|" + "Test failed 1|" + "Test failed 2|" + "Test failed 3|" + "Test failed 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 2"); + } + } else { + pid = fork(); + if(pid){ + sleep(2); + RUNNER_ASSERT_MSG(0, "Test failed 3"); + } else { + RUNNER_ASSERT_MSG(0, "Test failed 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm08_fail_unknown_exception, "TEST_FAILED|" + "unknown exception") +{ + throw("hello"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm09_fail_unknown_exception, "TEST_FAILED|" + "unknown exception") +{ + throw(1); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm10_ignore, "TEST_IGNORED|" + "Test ignored") +{ + RUNNER_IGNORED_MSG("Test ignored"); +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm11_ignore, "TEST_IGNORED|" + "Test ignored 1|" + "Test ignored 2|" + "Test ignored 3|" + "Test ignored 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_IGNORED_MSG("Test ignored 1"); + } else { + RUNNER_IGNORED_MSG("Test ignored 2"); + } + } else { + pid = fork(); + if(pid){ + sleep(2); + RUNNER_IGNORED_MSG("Test ignored 3"); + } else { + RUNNER_IGNORED_MSG("Test ignored 4"); + } + } +} + +RUNNER_MULTIPROCESS_TEST_EXPECT(tm12_fail, "TEST_FAILED|" + "Test failed 1|" + "Test ignored 2|" + "Test ignored 3|" + "Test ignored 4") +{ + pid_t pid = fork(); + if(pid){ + pid = fork(); + if(pid){ + RUNNER_ASSERT_MSG(0, "Test failed 1"); + } else { + RUNNER_IGNORED_MSG("Test ignored 2"); + } + } else { + pid = fork(); + if(pid){ + sleep(2); + RUNNER_IGNORED_MSG("Test ignored 3"); + } else { + RUNNER_IGNORED_MSG("Test ignored 4"); + } + } +} diff --git a/tests/test/test_abstract_input_reader.cpp b/tests/test/test_abstract_input_reader.cpp new file mode 100644 index 0000000..8e74faa --- /dev/null +++ b/tests/test/test_abstract_input_reader.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_abstract_input_reader.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief tests for AbstractInputReader + */ + +#include +#include + +#include +#include +#include +#include +#include + +using namespace DPL; + +namespace { + +// TOKENIZER + +class DigitTokenizer : public AbstractInputTokenizer +{ +public: + DigitTokenizer() : m_valid(true) {} + + std::unique_ptr GetNextToken() + { + typedef AbstractInputTokenizer::Exception::TokenizerError TokenizerError; + + std::unique_ptr token; + + char buffer; + BinaryQueueAutoPtr baptr = m_input->Read(1); //not effective but it's test... + if(baptr.get() == NULL) + { + ThrowMsg(TokenizerError, "Input reading failed"); + } + if(baptr->Empty()) //end of source + { + return token; + } + baptr->FlattenConsume(&buffer,1); + if(!isdigit(buffer)) + { + ThrowMsg(TokenizerError, "Input source contains no digit characters/bytes"); + } + token.reset(new int(static_cast(buffer))); + return token; + } + + void Reset(std::shared_ptr ia) + { + AbstractInputTokenizer::Reset(ia); + m_valid = true; + } + + bool IsStateValid() + { + return true; + } + +private: + bool m_valid; +}; + +// PARSER + +class SumatorParser : public AbstractInputParser +{ +public: + SumatorParser() : m_sum(0) {} + + void ConsumeToken(std::unique_ptr && token) + { + m_sum += (*token - '0'); + } + + bool IsStateValid() + { + return true; + } + + int GetResult() const + { + return m_sum; + } + +private: + int m_sum; +}; + +// READER + +class Sumator : public AbstractInputReader +{ +public: + Sumator(std::shared_ptr ia) + : AbstractInputReader(ia, + std::unique_ptr(new SumatorParser()), + std::unique_ptr(new DigitTokenizer())) + {} +}; + +} + +RUNNER_TEST_GROUP_INIT(AbstractInputReader) + +RUNNER_TEST(AbstractInputReader_ByteSumatorInstance_Sum) +{ + const std::string data("1234567890"); + std::shared_ptr mem(new BinaryQueue()); + dynamic_cast(mem.get())->AppendCopy(data.c_str(), data.size()); + Sumator sum(mem); + int result = sum.ReadInput(); + RUNNER_ASSERT_MSG(result == 45, "Sum is invalid"); +} + +RUNNER_TEST(AbstractInputReader_ByteSumatorInstance_Exception) +{ + const std::string data("12345string90"); + std::shared_ptr mem(new BinaryQueue()); + dynamic_cast(mem.get())->AppendCopy(data.c_str(), data.size()); + Sumator sum(mem); + Try + { + sum.ReadInput(); + } + Catch(Sumator::Exception::TokenizerError) + { + return; + } + RUNNER_ASSERT_MSG(false, "Tokenizer exception should be thrown"); +} diff --git a/tests/test/test_process_pipe.cpp b/tests/test/test_process_pipe.cpp new file mode 100644 index 0000000..46405f9 --- /dev/null +++ b/tests/test/test_process_pipe.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_process_pipe.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of ProcessPipe tests + */ + +#include +#include +#include +#include + +#include + +using namespace DPL; + +RUNNER_TEST_GROUP_INIT(DPL) + +namespace { +void readAll(ProcessPipe & npp, BinaryQueue & result) +{ + do + { + BinaryQueueAutoPtr dataptr = npp.Read(4096); + + RUNNER_ASSERT_MSG(dataptr.get() != NULL, "Cannot read from pipe subprocess"); + + LogDebug("Size: " << dataptr->Size()); + + if(dataptr->Empty()) break; + result.AppendMoveFrom(*dataptr); + } + while(true); +} +} + +RUNNER_TEST(ProcessPipe_echo) +{ + ProcessPipe npp; + npp.Open("echo -e \"Test echo text\\nAnd new line\""); + BinaryQueue result; + readAll(npp, result); + npp.Close(); + + char buffer[100] = ""; + result.FlattenConsume(buffer, std::min(result.Size(), sizeof(buffer))); + + RUNNER_ASSERT_MSG(strcmp(buffer, "Test echo text\nAnd new line\n") == 0, "Echoed text in not equal"); +} + +RUNNER_TEST(ProcessPipe_double_open) +{ + ProcessPipe npp; + npp.Open("echo \"Test \""); + Try + { + npp.Open("echo \"Test\""); + } + Catch(DPL::ProcessPipe::Exception::DoubleOpen) + { + npp.Close(); + return; + } + npp.Close(); + RUNNER_ASSERT_MSG(false, "DoubleOpen not thrown"); +} + +RUNNER_TEST(ProcessPipe_double_close) +{ + ProcessPipe npp; + npp.Open("echo \"Test invalid\""); + npp.Close(); + Try + { + npp.Close(); + } + Catch(DPL::Exception) + { + RUNNER_ASSERT_MSG(false, "Second Close throws exception"); + } +} + +RUNNER_TEST(ProcessPipe_pipeerror_off) +{ + ProcessPipe npp(ProcessPipe::PipeErrorPolicy::OFF); + npp.Open("ls /nonexistingdirectory"); + BinaryQueue result; + readAll(npp, result); //TODO: fix this test + npp.Close(); +} + +RUNNER_TEST(ProcessPipe_pipeerror_pipe) +{ + //ls output dependent... + ProcessPipe npp(ProcessPipe::PipeErrorPolicy::PIPE); + npp.Open("ls /nonexistingdirectory"); + BinaryQueue result; + readAll(npp, result); + npp.Close(); + char buffer[100] = ""; + result.FlattenConsume(buffer, std::min(result.Size(), sizeof(buffer))); + + RUNNER_ASSERT_MSG(strcmp(buffer, "ls: cannot access /nonexistingdirectory: No such file or directory\n") == 0, "Ls error text in not equal"); +} diff --git a/tests/test/test_value_separated_reader.cpp b/tests/test/test_value_separated_reader.cpp new file mode 100644 index 0000000..af17c2a --- /dev/null +++ b/tests/test/test_value_separated_reader.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_value_separated_reader.cpp + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @brief tests for VSReader + */ + +#include +#include +#include + +#include + +using namespace DPL; + +RUNNER_TEST_GROUP_INIT(ValueSeparatedReader) + +RUNNER_TEST(ValueSeparatedReader_readValidCSV) +{ + std::string data; + data += "1-1,1-2,1-3,1-4\n"; + data += "2-1,2-2,2-3,2-4\n"; + data += "3-1,3-2,3-3,3-4\n"; + data += "4-1,4-2,4-3,4-4\n"; + std::shared_ptr mem(new BinaryQueue()); + dynamic_cast(mem.get())->AppendCopy(data.data(), data.size()); + CSVReader csv(mem); + VSResultPtr result = csv.ReadInput(); + RUNNER_ASSERT_MSG((*result)[0][0] == "1-1", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[0][1] == "1-2", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[0][2] == "1-3", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[0][3] == "1-4", "Wrong value"); + + RUNNER_ASSERT_MSG((*result)[1][0] == "2-1", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[1][1] == "2-2", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[1][2] == "2-3", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[1][3] == "2-4", "Wrong value"); + + RUNNER_ASSERT_MSG((*result)[2][0] == "3-1", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[2][1] == "3-2", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[2][2] == "3-3", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[2][3] == "3-4", "Wrong value"); + + RUNNER_ASSERT_MSG((*result)[3][0] == "4-1", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[3][1] == "4-2", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[3][2] == "4-3", "Wrong value"); + RUNNER_ASSERT_MSG((*result)[3][3] == "4-4", "Wrong value"); +} + +RUNNER_TEST(ValueSeparatedReader_readInvalidCSV) +{ + Try + { + std::string data; + data += "1-1,1-2,1-3,1-4\n"; + data += "2-1,2-2,2-3,2-4\n"; + data += "3-1,3-2,3-3\n"; + data += "4-1,4-2,4-3,4-4\n"; + std::shared_ptr mem(new BinaryQueue()); + dynamic_cast(mem.get())->AppendCopy(data.data(), data.size()); + CSVReader csv(mem); + VSResultPtr result = csv.ReadInput(); + } + Catch(CSVReader::Exception::ParserError) + { + return; + } + RUNNER_ASSERT_MSG(false, "Should throw parser error"); +} diff --git a/tests/unused/test_caller.cpp b/tests/unused/test_caller.cpp new file mode 100644 index 0000000..6f1a1ff --- /dev/null +++ b/tests/unused/test_caller.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_address.cpp + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of caller tests + */ + +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +// test stream class +class BinaryStream : public DPL::IStream +{ + public: + virtual void Read(size_t num, void * bytes) + { + for (unsigned i = 0; i < num; ++i) { + ((unsigned char*)bytes)[i] = data[i + readPosition]; + } + readPosition += num; + } + virtual void Write(size_t num, const void * bytes) + { + for (unsigned i = 0; i < num; ++i) { + data.push_back(((unsigned char*)bytes)[i]); + } + } + BinaryStream() + { + readPosition = 0; + } + virtual ~BinaryStream(){} + + private: + std::vector data; + unsigned readPosition; +}; + +static int return_func(int a, bool b) +{ + if (b) { + return a; + } else { + return 0; + } +} + +static int called = 0; + +static void void_func(int a) +{ + called = a; +} + +static struct VoidDelegate +{ + void operator()(int a) + { + called = a; + } +} voidDelegate; + +static struct ReturnDelegate +{ + int operator()(int a) + { + return a; + } +} returnDelegate; + +RUNNER_TEST(Caller_function_void) +{ + int a = 23; + BinaryStream stream; + DPL::Serialization::Serialize(stream, a); + called = 0; + DPL::Caller::Call(stream, void_func); + RUNNER_ASSERT(called == a); +} + +RUNNER_TEST(Caller_function_return) +{ + int a = 23; + bool b = true; + BinaryStream stream; + DPL::Serialization::Serialize(stream, a); + DPL::Serialization::Serialize(stream, b); + int result = DPL::Caller::Call(stream, return_func); + RUNNER_ASSERT(result == a); +} + +RUNNER_TEST(Caller_delegate_void) +{ + int a = 23; + BinaryStream stream; + called = 0; + DPL::Serialization::Serialize(stream, a); + DPL::Caller::CallDelegate(stream, voidDelegate); + RUNNER_ASSERT(called == a); +} + +RUNNER_TEST(Caller_delegate_return) +{ + int a = 23; + BinaryStream stream; + called = 0; + DPL::Serialization::Serialize(stream, a); + int result = 0; + DPL::Caller::CallDelegate(stream, returnDelegate, result); + RUNNER_ASSERT(result == a); +} diff --git a/tests/unused/test_crypto_hash.cpp b/tests/unused/test_crypto_hash.cpp new file mode 100644 index 0000000..dd208b6 --- /dev/null +++ b/tests/unused/test_crypto_hash.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_crypto_hash.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test crypto hash + */ +#include +#include +RUNNER_TEST_GROUP_INIT(DPL) + +#define TEST_CRYPTO_HASH(Class, Input, Output) \ + Class crypto; \ + crypto.Append(Input); \ + crypto.Finish(); \ + RUNNER_ASSERT(crypto.ToString() == Output); + +RUNNER_TEST(CryptoHash_MD2) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::MD2, + "sample_input_string", + "c9f26439c9882cccc98467dbdf07b1fc"); +} + +RUNNER_TEST(CryptoHash_MD4) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::MD4, + "sample_input_string", + "8cd0720f7ec98c8e5f008afb54054677"); +} + +RUNNER_TEST(CryptoHash_MD5) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::MD5, + "sample_input_string", + "eb7ae4f28fecbd1fd777d9b7495fc8ec"); +} + +RUNNER_TEST(CryptoHash_SHA) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::SHA, + "sample_input_string", + "0a5725f3586616a4049730f3ba14c8aeda79ab21"); +} + +RUNNER_TEST(CryptoHash_SHA1) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::SHA1, + "sample_input_string", + "be0ed9040af0c2b772b2dd0776f6966b5f4d1206"); +} + +RUNNER_TEST(CryptoHash_DSS) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::DSS, + "sample_input_string", + "be0ed9040af0c2b772b2dd0776f6966b5f4d1206"); +} + +RUNNER_TEST(CryptoHash_DSS1) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::DSS1, + "sample_input_string", + "be0ed9040af0c2b772b2dd0776f6966b5f4d1206"); +} + +RUNNER_TEST(CryptoHash_ECDSA) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::ECDSA, + "sample_input_string", + "be0ed9040af0c2b772b2dd0776f6966b5f4d1206"); +} + +RUNNER_TEST(CryptoHash_SHA224) +{ + TEST_CRYPTO_HASH(DPL::Crypto::Hash::SHA224, + "sample_input_string", + "d4dde2370eb869f6e790133b94d58e45417392b9d899af883a274011"); +} + +RUNNER_TEST(CryptoHash_SHA256) +{ + TEST_CRYPTO_HASH( + DPL::Crypto::Hash::SHA256, + "sample_input_string", + "a470ec7c783ac51f9eb1772132e6bde1a053bbc81650719dd0ac62ecd93caf12"); +} + +RUNNER_TEST(CryptoHash_SHA384) +{ + TEST_CRYPTO_HASH( + DPL::Crypto::Hash::SHA384, + "sample_input_string", + "63d8bfa95c95c6906d1816965431c065278a655c60f786c9b246c1f73ba7ac557007f5064ba54ebd3a1988e6f37baa97"); +} + +RUNNER_TEST(CryptoHash_SHA512) +{ + TEST_CRYPTO_HASH( + DPL::Crypto::Hash::SHA512, + "sample_input_string", + "799317a140741937d9e5d8dbf9d3045d2c220de5ac33b3d5897acf873291ed14379eb15ef406d2284313d40edb0e01affac8efeb01cb47c2042e3e62a4a83d7d"); +} diff --git a/tests/unused/test_message_queue.cpp b/tests/unused/test_message_queue.cpp new file mode 100644 index 0000000..09990b7 --- /dev/null +++ b/tests/unused/test_message_queue.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_message_queue.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of message queue tests + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GENERIC_EVENT_0(QuitEvent) + +class QuitController : + public DPL::Controller::Type>, + public DPL::ApplicationExt +{ + public: + QuitController() : DPL::ApplicationExt(1, NULL, "test-app") + { + Touch(); + } + + protected: + virtual void OnEventReceived(const QuitEvent &) + { + Quit(); + } +}; + +RUNNER_TEST_GROUP_INIT(DPL) + +class CopyThread : + public DPL::Thread +{ + private: + bool m_success; + DPL::AbstractWaitableInput *m_input; + DPL::AbstractWaitableOutput *m_output; + std::size_t m_dataSize; + + public: + CopyThread(DPL::AbstractWaitableInput *input, + DPL::AbstractWaitableOutput *output, + std::size_t dataSize) : + m_success(true), + m_input(input), + m_output(output), + m_dataSize(dataSize) + { + LogDebug("Thread created"); + } + + protected: + virtual int ThreadEntry() + { + LogDebug("Entering copy thread"); + + Try + { + DPL::Copy(m_input, m_output, m_dataSize); + } + Catch(DPL::CopyFailed) + { + m_success = false; + + LogWarning("Copy failed!"); + return 0; + } + + LogDebug("Copy finished"); + return 0; + } +}; + +inline std::string BinaryQueueToString(const DPL::BinaryQueue &queue) +{ + char *buffer = new char[queue.Size()]; + queue.Flatten(buffer, queue.Size()); + std::string result = std::string(buffer, buffer + queue.Size()); + delete[] buffer; + return result; +} + +RUNNER_TEST(MessageQueue_DoubleCopy) +{ + DPL::BinaryQueue dataA; + DPL::MessageQueue dataB("/test_mqueue_dataB", true, false, 0660, true); + DPL::MessageQueue dataC("/test_mqueue_dataC", true, false, 0660, true); + DPL::BinaryQueue dataD; + + DPL::AbstractWaitableInputAdapter dataAdapterA(&dataA); + DPL::AbstractWaitableOutputAdapter dataAdapterD(&dataD); + + const std::string testData = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + "Cras elementum venenatis velit, sit amet vehicula odio gravida a." + "Curabitur id nibh id ante adipiscing sollicitudin." + "Maecenas in tellus vel augue vehicula pharetra hendrerit cursus est." + "" + "Ut malesuada quam porttitor dui euismod lacinia." + "Phasellus quis lectus sed lectus dictum tincidunt et vitae leo." + "Fusce id est massa, condimentum bibendum urna." + "Donec venenatis quam eget sapien vulputate egestas." + "Maecenas scelerisque lorem a neque molestie a varius erat condimentum." + "Maecenas varius hendrerit ligula, sed iaculis justo pretium id." + "Nunc sit amet nisl vitae justo tristique suscipit id eget tortor." + "" + "Pellentesque sollicitudin nulla at metus dapibus tincidunt." + "Integer consequat justo eget dui imperdiet iaculis." + "Sed vestibulum ipsum vitae libero accumsan non molestie metus adipiscing." + "" + "Vivamus quis dui enim, in blandit urna." + "In imperdiet lacus at orci elementum a scelerisque dui blandit." + "Donec vulputate enim metus, eget convallis ante." + "Etiam mollis enim eget eros pulvinar nec sagittis justo fermentum." + "" + "Vestibulum sed nunc eu leo lobortis ultrices." + "Nullam placerat nulla et est blandit nec interdum nunc pulvinar." + "Vivamus a lectus eget dui fermentum hendrerit."; + + QuitController quitter; + quitter.PostTimedEvent(QuitEvent(), 1.0); + + CopyThread threadA(&dataAdapterA, &dataB, testData.size()); + CopyThread threadB(&dataB, &dataC, testData.size()); + CopyThread threadC(&dataC, &dataAdapterD, testData.size()); + + dataA.AppendCopy(testData.c_str(), testData.size()); + + threadA.Run(); + threadB.Run(); + threadC.Run(); + + quitter.Exec(); + + threadA.Quit(); + threadB.Quit(); + threadC.Quit(); + + // Now, test data should be in dataD + RUNNER_ASSERT(BinaryQueueToString(dataD) == testData); +} diff --git a/tests/unused/test_shm.cpp b/tests/unused/test_shm.cpp new file mode 100644 index 0000000..20eed04 --- /dev/null +++ b/tests/unused/test_shm.cpp @@ -0,0 +1,1660 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_shm.h + * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) + * @version 1.0 + * @brief Implementation file for test cases for shared data framework + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +using namespace DPL; + +namespace { +const SharedMemory::Key SHM_KEY = 12345; +const char* SEM_NAME = "/wrt_engine_shared_object_semaphore"; +const size_t VERSION = 1; + +const size_t MAX_THREADS = 10; +const size_t TEST_AND_SET_REPEATS = 100; + +const size_t SHARED_PROP_REPEATS = 3; + +const size_t SINGLETON_TEST_REPEATS = 3; + +// maximum random delay in singleton listener addition/removal +const size_t MAX_SINGLETON_LISTENER_DELAY = 50; + +const int SINGLE_PROCESS_REPEATS = 50; + +/* + * 5 seconds expected timeout for waitable events + * 30 seconds unexpected timeout for waitable events + * We don't want to block tests + */ +const size_t EXPECTED_WAITABLE_TIMEOUT = 5 * 1000; +const size_t UNEXPECTED_WAITABLE_TIMEOUT = 30 * 1000; + +bool g_enumTestCorrect = false; +bool g_enumTestIncorrect = false; +size_t g_delegateCalls = 0; + +void Wait(DPL::WaitableEvent& event, bool expectedTimeout = false) +{ + LogDebug("WaitForSingleHandle..."); + DPL::WaitableHandleIndexList list = DPL::WaitForSingleHandle( + event.GetHandle(), + expectedTimeout ? + EXPECTED_WAITABLE_TIMEOUT : UNEXPECTED_WAITABLE_TIMEOUT); + if (list.size() == 0) { + LogDebug("...timeout."); + } else { + LogDebug("...signaled."); + event.Reset(); + } + + if (expectedTimeout) { + RUNNER_ASSERT(list.size() == 0); + } else { + RUNNER_ASSERT(list.size() == 1); + } +} + +void RemoveIpcs() +{ + Try { + SharedMemory::Remove(SHM_KEY); + } + Catch(SharedMemory::Exception::RemoveFailed) { + // ignore + } + + Try { + DPL::Semaphore::Remove(SEM_NAME); + } + Catch(DPL::Semaphore::Exception::RemoveFailed) { + // ignore + } +} + +typedef DPL::TypeListDecl::Type TestTypeList; +typedef DPL::TypeListDecl::Type TestTypeList2; +typedef DPL::TypeListDecl::Type TestTypeList3; + +typedef SharedObject TestSharedObject; +typedef SharedObject TestSharedObject2; +typedef SharedObject TestSharedObject3; + +typedef std::shared_ptr TestSharedObjectPtr; + +const int INIT_EVENT = 0; +const int DESTROY_EVENT = 1; + +int g_values[TestTypeList::Size]; + +/* + * helper listening controller + */ +template +class ListeningController : + public DPL::Controller::Type> +{ + public: + explicit ListeningController(DPL::WaitableEvent* waitable); + ~ListeningController(); + + virtual void OnEventReceived(const int &event); + + virtual void OnEvent(const int /*event*/) {} + + protected: + std::shared_ptr m_so; + DPL::Thread m_thread; + DPL::WaitableEvent* m_waitable; +}; + +template +ListeningController::ListeningController( + DPL::WaitableEvent* waitable) : + m_waitable(waitable) +{ + Touch(); + m_thread.Run(); + SwitchToThread(&m_thread); + PostEvent(INIT_EVENT); +} + +template +ListeningController::~ListeningController() +{ + m_thread.Quit(); +} + +template +void ListeningController::OnEventReceived(const int& event) +{ + if (event == INIT_EVENT) { + m_so = SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + OnEvent(event); + m_waitable->Signal(); + } else if (event == DESTROY_EVENT) { + LogDebug("Destroying shared object"); + OnEvent(event); + + // deregister, destroy ad notify main thread + m_so.Reset(); + LogDebug("4"); + m_waitable->Signal(); + LogDebug("5"); + } else { + OnEvent(event); + } +} + +typedef DPL::TypeListDecl::Type SharedTypeList; + +class TestSharedObject4; +typedef std::shared_ptr TestSharedObject4Ptr; + +class TestSharedObject4 : public SharedObject +{ + public: + enum + { + SIZE_T, + BOOLEAN + }; + + static TestSharedObject4Ptr Create() + { + return SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + } + + ~TestSharedObject4() + { + LogDebug("dtor"); + } + + protected: + explicit TestSharedObject4(const std::string& semaphore) : + SharedObject(semaphore) + {} + + private: + void Init() + { + SetPropertyInternal(false); + } + friend class SharedObjectFactory; +}; +} // anonymus namespace + +////////////////////////////////////////////// + +RUNNER_TEST(SharedMemory_002_AccessByType) +{ + RemoveIpcs(); + + SharedData str; + + // access by type + str.Embedded<0, int>::value = 4; + str.Embedded<1, int>::value = 5; + str.Embedded<2, char>::value = 'd'; + str.Embedded<3, int[64]>::value[0] = 1; + str.Embedded<3, int[64]>::value[1] = 20; + + RUNNER_ASSERT((str.Embedded<0, int>::value) == 4); + RUNNER_ASSERT((str.Embedded<1, int>::value) == 5); + RUNNER_ASSERT((str.Embedded<2, char>::value) == 'd'); + RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 1); + RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 20); +} + +////////////////////////////////////////////// + +RUNNER_TEST(SharedMemory_003_AccessByIndex) +{ + RemoveIpcs(); + + SharedData str; + // access by enum + str.Embedded<0, TestTypeList::Element<0>::Type>::value = 4; + str.Embedded<1, TestTypeList::Element<1>::Type>::value = 5; + str.Embedded<2, TestTypeList::Element<2>::Type>::value = 'd'; + str.Embedded<3, TestTypeList::Element<3>::Type>::value[0] = 1; + str.Embedded<3, TestTypeList::Element<3>::Type>::value[1] = 20; + + RUNNER_ASSERT( + (str.Embedded<0, TestTypeList::Element<0>::Type>::value) == 4); + RUNNER_ASSERT( + (str.Embedded<1, TestTypeList::Element<1>::Type>::value) == 5); + RUNNER_ASSERT( + (str.Embedded<2, TestTypeList::Element<2>::Type>::value) == 'd'); + RUNNER_ASSERT( + (str.Embedded<3, TestTypeList::Element<3>::Type>::value[0]) == 1); + RUNNER_ASSERT( + (str.Embedded<3, TestTypeList::Element<3>::Type>::value[1]) == 20); +} + +////////////////////////////////////////////// + +RUNNER_TEST(SharedMemory_004_SimplifiedAccess) +{ + RemoveIpcs(); + + SharedData str; + + // access via PropertyRef + str.PropertyRef<1>() = 3; + RUNNER_ASSERT(str.PropertyRef<1>() == 3); + + int (&array)[64] = str.PropertyRef<3>(); + array[0] = 2; + RUNNER_ASSERT(str.PropertyRef<3>()[0] == 2); + + str.PropertyRef<3>()[1] = 19; + RUNNER_ASSERT(str.PropertyRef<3>()[1] == 19); + + // access via macro + str.SHARED_PROPERTY(0) = 2; + RUNNER_ASSERT(str.SHARED_PROPERTY(0) == 2); + + str.SHARED_PROPERTY(2) = 'c'; + RUNNER_ASSERT(str.SHARED_PROPERTY(2) == 'c'); + + str.SHARED_PROPERTY(3)[2] = 10; + RUNNER_ASSERT(str.SHARED_PROPERTY(3)[2] == 10); + + // old style check + RUNNER_ASSERT((str.Embedded<0, int>::value) == 2); + RUNNER_ASSERT((str.Embedded<1, int>::value) == 3); + RUNNER_ASSERT((str.Embedded<2, char>::value) == 'c'); + RUNNER_ASSERT((str.Embedded<3, int[64]>::value[0]) == 2); + RUNNER_ASSERT((str.Embedded<3, int[64]>::value[1]) == 19); + RUNNER_ASSERT((str.Embedded<3, int[64]>::value[2]) == 10); +} + +////////////////////////////////////////////// + +struct SharedStruct +{ + int a; + int b; + char c; + int d[64]; +}; + +typedef std::shared_ptr > SharedStructPtr; + +RUNNER_TEST(SharedMemory_010_BaseShmTest) +{ + RemoveIpcs(); + + typedef std::unique_ptr SharedMemoryPtr; + + // write + SharedMemoryPtr shm; + Try { + shm.Reset(SharedMemory::Create(SHM_KEY, false)); + } + Catch(SharedMemory::Exception::NotFound) { + shm.Reset(SharedMemory::Create(SHM_KEY, true, true)); + } + + SharedStructPtr str = shm->Attach(); + + str->Data()->a = 1; + str->Data()->b = 2; + str->Data()->c = '3'; + str->Data()->d[0] = 4; + str->Data()->d[1] = 5; + + // read + SharedMemoryPtr shm2; + Try { + shm2.Reset(SharedMemory::Create(SHM_KEY, false)); + } + Catch(SharedMemory::Exception::NotFound) { + shm2.Reset(SharedMemory::Create(SHM_KEY, true, true)); + } + + SharedStructPtr str2 = shm2->Attach(); + SharedStructPtr str3 = shm2->Attach(); + + RUNNER_ASSERT(str2->Data()->a == 1); + RUNNER_ASSERT(str2->Data()->b == 2); + RUNNER_ASSERT(str2->Data()->c == '3'); + RUNNER_ASSERT(str2->Data()->d[0] == 4); + RUNNER_ASSERT(str2->Data()->d[1] == 5); + + RUNNER_ASSERT(str3->Data()->a == 1); + RUNNER_ASSERT(str3->Data()->b == 2); + RUNNER_ASSERT(str3->Data()->c == '3'); + RUNNER_ASSERT(str3->Data()->d[0] == 4); + RUNNER_ASSERT(str3->Data()->d[1] == 5); + + str2->Data()->b = 4; + str2->Data()->c = 'c'; + str2->Data()->d[0] = 0; + RUNNER_ASSERT(str3->Data()->a == 1); + RUNNER_ASSERT(str3->Data()->b == 4); + RUNNER_ASSERT(str3->Data()->c == 'c'); + RUNNER_ASSERT(str3->Data()->d[0] == 0); + RUNNER_ASSERT(str3->Data()->d[1] == 5); +} + +////////////////////////////////////////////// + +RUNNER_TEST(SharedMemory_020_SharedObjectTest) +{ + RemoveIpcs(); + + typedef SharedObject MySharedObj; + + MySharedObj::Ptr so = + SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 0); + so->SetProperty<0, size_t>(4); + RUNNER_ASSERT((so->GetProperty<0, size_t>()) == 4); +} + +////////////////////////////////////////////// + +class InitTestSharedObject : public TestSharedObject +{ + protected: + explicit InitTestSharedObject(const std::string& semaphore) : + TestSharedObject(semaphore) {} + + virtual void Init(); // from SharedObject + + private: + friend class SharedObjectFactory; +}; + +void InitTestSharedObject::Init() +{ + SetPropertyInternal<0>(1); + SetPropertyInternal<1>(2); + SetPropertyInternal<2>('c'); +} + +RUNNER_TEST(SharedMemory_021_InitTest) +{ + RemoveIpcs(); // we need non existing shm + + std::shared_ptr sho = + SharedObjectFactory::Create( + SHM_KEY, SEM_NAME); + RUNNER_ASSERT((sho->GetProperty<0, int>()) == 1); + RUNNER_ASSERT((sho->GetProperty<1, int>()) == 2); + RUNNER_ASSERT((sho->GetProperty<2, char>()) == 'c'); +} + +////////////////////////////////////////////// + +class VersionTestSO1 : public TestSharedObject +{ + protected: + explicit VersionTestSO1(const std::string& semaphore) : + TestSharedObject(semaphore) {} + + virtual SizeType GetVersion() const + { + return 1; + } // from SharedObject + + private: + friend class SharedObjectFactory; +}; + +class VersionTestSO2 : public TestSharedObject +{ + protected: + explicit VersionTestSO2(const std::string& semaphore) : + TestSharedObject(semaphore) {} + + virtual SizeType GetVersion() const + { + return 2; + } // from SharedObject + + private: + friend class SharedObjectFactory; +}; + +RUNNER_TEST(SharedMemory_022_InvalidVersionTest) +{ + RemoveIpcs(); // we need non existing shm + + std::shared_ptr sho = + SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + Try { + std::shared_ptr sho2 = + SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + RUNNER_ASSERT_MSG(false, "Invalid shm version has been accepted"); + } + Catch(SharedObjectBase::Exception::InvalidVersion) { + RUNNER_ASSERT(true); + } +} + +////////////////////////////////////////////// + +RUNNER_TEST(SharedMemory_023_InvalidSizeTest) +{ + RemoveIpcs(); // we need non existing shm + + typedef SharedObject SO1; + typedef SharedObject SO2; + + SO1::Ptr sho = SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + Try { + SO2::Ptr sho2 = SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + RUNNER_ASSERT_MSG(false, "Invalid shm size has been accepted"); + } + Catch(SharedObjectBase::Exception::InvalidSize) { + RUNNER_ASSERT(true); + } +} + +////////////////////////////////////////////// + +class MagicTestSO1 : public TestSharedObject +{ + protected: + explicit MagicTestSO1(const std::string& semaphore) : + TestSharedObject(semaphore) {} + + // from SharedObject + virtual MagicType GetMagicNumber() const + { + return 661; + } + + private: + friend class SharedObjectFactory; +}; + +class MagicTestSO2 : public TestSharedObject +{ + protected: + explicit MagicTestSO2(const std::string& semaphore) : + TestSharedObject(semaphore) {} + + // from SharedObject + virtual MagicType GetMagicNumber() const + { + return 662; + } + + private: + friend class SharedObjectFactory; +}; + +RUNNER_TEST(SharedMemory_024_InvalidMagicTest) +{ + RemoveIpcs(); // we need non existing shm + + std::shared_ptr sho = + SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + Try { + std::shared_ptr sho2 = + SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + RUNNER_ASSERT_MSG(false, "Invalid shm magic number has been accepted"); + } + Catch(SharedObjectBase::Exception::InvalidMagicNumber) { + RUNNER_ASSERT(true); + } +} + +////////////////////////////////////////////// + +/* + * Listening shared object + */ +class EnumTestSO1 : public TestSharedObject +{ + public: + void SetWaitable(DPL::WaitableEvent* waitable) + { + m_waitable = waitable; + } + + protected: + explicit EnumTestSO1(const std::string& semaphore) : + TestSharedObject(semaphore), + m_waitable(NULL) + {} + + + virtual void PropertyChanged(size_t propertyEnum); + + private: + friend class SharedObjectFactory; + + DPL::WaitableEvent* m_waitable; +}; + +void EnumTestSO1::PropertyChanged(size_t propertyEnum) +{ + if (propertyEnum == 1) { + LogDebug("Property enum " << propertyEnum << " correctly set"); + g_enumTestCorrect = true; + } + if (propertyEnum == 4) { + // This is bad. We only have 4 types + LogError("Property enum " << propertyEnum << " should be skipped"); + g_enumTestIncorrect = true; + } + // confirm property change notification + m_waitable->Signal(); +} + +class EnumController : public ListeningController +{ + public: + explicit EnumController(DPL::WaitableEvent* waitable) : + ListeningController(waitable) {} + + virtual void OnEvent(const int event); +}; + +void EnumController::OnEvent(const int event) +{ + if (event == INIT_EVENT) { + m_so->SetWaitable(m_waitable); + } +} + +/* + * Writing shared object with correct size but different number of types + */ +class EnumTestSO2 : public TestSharedObject3 +{ + protected: + explicit EnumTestSO2(const std::string& semaphore) : + TestSharedObject3(semaphore) {} + + private: + friend class SharedObjectFactory; +}; + +RUNNER_TEST(SharedMemory_025_InvalidEnumTest) +{ + RemoveIpcs(); // we need non existing shm + + g_enumTestCorrect = false; + g_enumTestIncorrect = false; + + DPL::WaitableEvent waitable; + + // create listening controller and wait until it registers + EnumController controller(&waitable); + Wait(waitable); + LogDebug("Listening controller created"); + + // create writing shared object + std::shared_ptr sho2 = + SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + DPL::WaitableHandleIndexList list; + + // write property and wait for confirmation + sho2->SetProperty<1>(2); + Wait(waitable); + + // write incorrect property and wait for confirmation + // we expect timeout + sho2->SetProperty<4>(2); + Wait(waitable, true); + + // schedule listener deregistration and wait for confirmation + controller.PostEvent(DESTROY_EVENT); + Wait(waitable); + + // check results + RUNNER_ASSERT(g_enumTestCorrect == true); + RUNNER_ASSERT(g_enumTestIncorrect == false); +} + +////////////////////////////////////////////// + +class MultiThreadSO : public TestSharedObject +{ + public: + void TestAndSetProperty(); + + protected: + explicit MultiThreadSO(const std::string& semaphore) : + TestSharedObject(semaphore) {} + + private: + friend class SharedObjectFactory; +}; + +void MultiThreadSO::TestAndSetProperty() +{ + ScopedFlaggedLock lock(*this); + + int value = PropertyRef<0, int>(); + DPL::Thread::MicroSleep(100); + SetPropertyInternal<0>(value + 1); +} + +class ShmController : public ListeningController +{ + public: + explicit ShmController(DPL::WaitableEvent* event) : + ListeningController(event), m_counter(0) + {} + + virtual void OnEventReceived(const int& event); + + private: + size_t m_counter; +}; + +void ShmController::OnEventReceived(const int& event) +{ + if (event == INIT_EVENT) { + m_so = SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + PostEvent(2); + } else if (event == DESTROY_EVENT) { + LogDebug("Destroying shared object"); + // deregister, destroy ad notify main thread + m_so.Reset(); + m_waitable->Signal(); + } else if (event == 2) { + m_so->TestAndSetProperty(); + m_counter++; + if (m_counter >= TEST_AND_SET_REPEATS) { + LogDebug("Max tests reached. Finishing thread"); + PostEvent(DESTROY_EVENT); + return; + } + PostEvent(2); + } +} + +RUNNER_TEST(SharedMemory_030_MultithreadTest) +{ + RemoveIpcs(); // we need non existing shm + + typedef SharedObject SHO; + SHO::Ptr sho = SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + + ShmController* controller[MAX_THREADS]; + DPL::WaitableEvent finalEvent[MAX_THREADS]; + + for (size_t i = 0; i < MAX_THREADS; ++i) { + controller[i] = new ShmController(&finalEvent[i]); + } + + for (size_t i = 0; i < MAX_THREADS; ++i) { + Wait(finalEvent[i]); + } + + for (size_t i = 0; i < MAX_THREADS; ++i) { + delete controller[i]; + controller[i] = NULL; + } + + int value = sho->GetProperty<0, int>(); + LogDebug("Final value is " << value << ", expected " << + MAX_THREADS * TEST_AND_SET_REPEATS); + RUNNER_ASSERT(value == MAX_THREADS * TEST_AND_SET_REPEATS); +} + +////////////////////////////////////////////// + +class MyModel10 : public DPL::Model +{ + public: + explicit MyModel10(const TestSharedObject4Ptr& shared_object) : + DPL::Model(), boolValue(this, shared_object) {} + + SharedProperty + boolValue; +}; + +/* + * Listening controller + */ +class ShmController3 : public ListeningController +{ + public: + explicit ShmController3(DPL::WaitableEvent* event) : + ListeningController(event) + {} + + virtual void OnEvent(const int event); + + void OnValueChanged(const DPL::PropertyEvent& event); + + private: + typedef std::unique_ptr MyModelPtr; + + // model with property bound to shared object + MyModelPtr m_model; +}; + +void ShmController3::OnEvent(const int event) +{ + if (event == INIT_EVENT) { + m_model.Reset(new MyModel10(m_so)); + m_model->boolValue.AddListener( + std::bind(&ShmController3::OnValueChanged, this)); + } else if (event == DESTROY_EVENT) { + m_model->boolValue.RemoveListener( + std::bind(&ShmController3::OnValueChanged, this)); + m_model.Reset(); + } +} + +void ShmController3::OnValueChanged(const DPL::PropertyEvent& event) +{ + if (event.value) { + // change back + m_model->boolValue.Set(false); + } else { + LogError("Expected value = true, got false"); + } + + m_waitable->Signal(); +} + +RUNNER_TEST(SharedMemory_050_SharedProperty) +{ + RemoveIpcs(); + + bool result = true; + DPL::WaitableEvent waitable; + // listener controller + ShmController3 controller(&waitable); + Wait(waitable); + + TestSharedObject4Ptr sharedObject = TestSharedObject4::Create(); + + for (size_t i = 0; i < SHARED_PROP_REPEATS; ++i) { + sharedObject->SetProperty(true); + Wait(waitable); + result = sharedObject->GetProperty(); + RUNNER_ASSERT(result == false); + } + controller.PostEvent(DESTROY_EVENT); + Wait(waitable); +} + +////////////////////////////////////////////// + +class MyModel2 : public DPL::Model +{ + public: + explicit MyModel2(const TestSharedObjectPtr& shared_object) : + counter(this, shared_object) {} + + SharedProperty counter; +}; + +class SPController : public ListeningController +{ + public: + explicit SPController(DPL::WaitableEvent* event) : + ListeningController(event), m_repeats(1) {} + + virtual void OnEvent(const int event); + + void OnValueChanged1(const DPL::PropertyEvent& event); + void OnValueChanged2(const DPL::PropertyEvent& event); + + private: + std::unique_ptr m_model1; + std::unique_ptr m_model2; + + int m_repeats; + std::shared_ptr m_so2; +}; + +void SPController::OnEvent(const int event) +{ + if (event == INIT_EVENT) { + m_so2 = SharedObjectFactory::Create(SHM_KEY, + SEM_NAME); + + // create and register 2 models sharing the same property + m_model1.Reset(new MyModel2(m_so)); + m_model2.Reset(new MyModel2(m_so2)); + m_model1->counter.AddListener( + std::bind(&SPController::OnValueChanged1, this)); + m_model2->counter.AddListener( + std::bind(&SPController::OnValueChanged2, this)); + m_model1->counter.Set(1); + } else if (event == DESTROY_EVENT) { + m_model1->counter.RemoveListener( + std::bind(&SPController::OnValueChanged1, this)); + m_model2->counter.RemoveListener( + std::bind(&SPController::OnValueChanged2, this)); + + m_model1.Reset(); + m_model2.Reset(); + m_so2.Reset(); + } +} + +void SPController::OnValueChanged1(const DPL::PropertyEvent& event) +{ + if (m_repeats >= SINGLE_PROCESS_REPEATS) { + PostEvent(DESTROY_EVENT); + return; + } + + LogDebug("[1] Value changed to " << event.value); + m_repeats++; + m_model1->counter.Set(event.value + 1); +} + +void SPController::OnValueChanged2(const DPL::PropertyEvent& event) +{ + if (m_repeats >= SINGLE_PROCESS_REPEATS) { + PostEvent(DESTROY_EVENT); + return; + } + + LogDebug("[2] Value changed to " << event.value); + m_repeats++; + m_model2->counter.Set(event.value + 1); +} + +RUNNER_TEST(SharedMemory_060_SingleProcess) +{ + RemoveIpcs(); + + DPL::WaitableEvent waitable; + SPController controller(&waitable); + TestSharedObjectPtr sho = SharedObjectFactory::Create( + SHM_KEY, + SEM_NAME); + + // wait for creation + Wait(waitable); + + // wait for destruction + Wait(waitable); + + int value = sho->GetProperty<0, int>(); + + LogDebug("final value: " << value); + + // check value + RUNNER_ASSERT(value == SINGLE_PROCESS_REPEATS); +} + +////////////////////////////////////////////// + +class ListenerTestController : public ListeningController, + public ISharedObjectListener<0, int>, + public ISharedObjectListener<1, int>, + public ISharedObjectListener<2, char>, + public ISharedObjectListener<3, int[64]> +{ + public: + explicit ListenerTestController(DPL::WaitableEvent* event) : + ListeningController(event) {} + + ~ListenerTestController(); + + virtual void OnEvent(const int event); + + virtual void ValueChanged(size_t propertyEnum, + const int& value, + const void* info = NULL); + virtual void ValueChanged(size_t propertyEnum, + const char& value, + const void* info = NULL); + virtual void ValueChanged(size_t propertyEnum, + const int(&value)[64], + const void* info = NULL); +}; + +ListenerTestController::~ListenerTestController() +{} + +void ListenerTestController::OnEvent(const int event) +{ + if (event == INIT_EVENT) { + // add self as a listener to shared object + m_so->AddListener<0, int>(this); + m_so->AddListener<1, int>(this); + m_so->AddListener<2, char>(this); + m_so->AddListener<3, int[64]>(this); + } else if (event == DESTROY_EVENT) { + // remove self from listener list + m_so->RemoveListener<0, int>(this); + m_so->RemoveListener<1, int>(this); + m_so->RemoveListener<2, char>(this); + m_so->RemoveListener<3, int[64]>(this); + } +} + +void ListenerTestController::ValueChanged(size_t propertyEnum, + const int& value, + const void* /*info*/) +{ + LogDebug("ValueChanged(int) " << propertyEnum << " " << value); + if ((propertyEnum == 0 && + value == 1) || (propertyEnum == 1 && value == 2)) + { + g_values[propertyEnum]++; + if (g_values[propertyEnum] == 3) { + m_waitable->Signal(); + } + } +} + +void ListenerTestController::ValueChanged(size_t propertyEnum, + const char& value, + const void* /*info*/) +{ + LogDebug("ValueChanged(char) " << propertyEnum << " " << value); + if (propertyEnum == 2 && value == 'c') { + g_values[propertyEnum]++; + if (g_values[propertyEnum] == 3) { + m_waitable->Signal(); + } + } +} + +void ListenerTestController::ValueChanged(size_t propertyEnum, + const int(&value)[64], + const void* /*info*/) +{ + LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]); + if (propertyEnum == 3 && value[5] == 5) { + g_values[propertyEnum]++; + if (g_values[propertyEnum] == 3) { + m_waitable->Signal(); + } + } +} + +RUNNER_TEST(SharedMemory_070_SharedObjectListeners) +{ + RemoveIpcs(); + + // setup global flags + for (size_t i = 0; i < TestTypeList::Size; ++i) { + g_values[i] = 0; + } + + // create shared object + TestSharedObjectPtr sho = SharedObjectFactory::Create( + SHM_KEY, SEM_NAME); + + // create 1st listener and wait for it + DPL::WaitableEvent waitable; + ListenerTestController c1(&waitable); + Wait(waitable); + + // create 2nd listener and wait for it + ListenerTestController c2(&waitable); + Wait(waitable); + + // create 3rd listener and wait for it + ListenerTestController c3(&waitable); + Wait(waitable); + + // set properties and wait for result + sho->SetProperty<0, int>(1); + Wait(waitable); + + RUNNER_ASSERT(g_values[0] == 3); + + sho->SetProperty<1, int>(2); + Wait(waitable); + + RUNNER_ASSERT(g_values[1] == 3); + + sho->SetProperty<2, char>('c'); + Wait(waitable); + + RUNNER_ASSERT(g_values[2] == 3); + + int array[64]; + memset(array, 0, 64 * sizeof(array[0])); + array[5] = 5; + sho->SetProperty<3, int[64]>(array); + Wait(waitable); + + RUNNER_ASSERT(g_values[3] == 3); + + // finalize listeners + c1.PostEvent(DESTROY_EVENT); + Wait(waitable); + + c2.PostEvent(DESTROY_EVENT); + Wait(waitable); + + c3.PostEvent(DESTROY_EVENT); + Wait(waitable); +} + +////////////////////////////////////////////// + +/* + * class simulating DB access + */ +class DAO : public DPL::Noncopyable +{ + public: + DAO() : m_boolValue(false) {} + + void SetBoolValue(const bool& value) + { + m_boolValue = value; + } + + bool GetBoolValue() const + { + return m_boolValue; + } + + private: + bool m_boolValue; +}; + +/* + * Model with property having set delegate defined + */ +class MyModel3 : public DPL::Model +{ + public: + typedef SharedPropertyEx PropertyType; + + MyModel3(const TestSharedObject4Ptr& shared_object, DAO* dao) : + boolValue(this, + shared_object, + PropertyType::SetDelegate(dao, &DAO::SetBoolValue)) + {} + + PropertyType boolValue; +}; + +RUNNER_TEST(SharedMemory_090_SetPropertyDelegate) +{ + RemoveIpcs(); + + // dao object + DAO dao; + + // create shared object + TestSharedObject4Ptr sho = TestSharedObject4::Create(); + + // set property but call dao delegate within semaphore + sho->SetProperty( + true, + MyModel3::PropertyType::SetDelegate(&dao, &DAO::SetBoolValue)); + + // check dao value + RUNNER_ASSERT(dao.GetBoolValue() == true); + + // check shared object value + bool shoValue = sho->GetProperty(); + RUNNER_ASSERT(shoValue == true); + + // try the same with shared property + MyModel3 model(sho, &dao); + + // set property + model.boolValue.Set(false); + + // check dao value + RUNNER_ASSERT(dao.GetBoolValue() == false); + + // check sho value + shoValue = sho->GetProperty(); + RUNNER_ASSERT(shoValue == false); + + // check property value + RUNNER_ASSERT(model.boolValue.Get() == false); +} + +////////////////////////////////////////////// + +/* + * Lazy initialization test shared object + */ +class LazySharedObject : public SharedObject +{ + private: + LazySharedObject() : + m_read(false) + {} + + public: + explicit LazySharedObject(const std::string& semaphore) : + SharedObject(semaphore) + , m_read(false) + {} + + void Init(); + + bool IsRead() const + { + return m_read; + } + + private: + friend class SharedObjectFactory; + + bool m_read; +}; + +void LazySharedObject::Init() +{ + SetPropertyInternal<0>(42); + m_read = true; +} + +RUNNER_TEST(SharedMemory_100_LazyInit) +{ + RemoveIpcs(); + + typedef std::shared_ptr LazySharedObjectPtr; + + // create shared object + LazySharedObjectPtr sho = SharedObjectFactory::Create( + SHM_KEY, SEM_NAME); + + RUNNER_ASSERT(sho->IsRead() == false); + + // get property causing lazy init + int value = sho->GetProperty<0, int>(); + + RUNNER_ASSERT(sho->IsRead() == true); + RUNNER_ASSERT(value == 42); + + // create another object + LazySharedObjectPtr sho2 = SharedObjectFactory::Create( + SHM_KEY, SEM_NAME); + + RUNNER_ASSERT(sho2->IsRead() == false); + + // get property NOT causing lazy init + value = sho2->GetProperty<0, int>(); + + RUNNER_ASSERT(sho2->IsRead() == false); + RUNNER_ASSERT(value == 42); + + // destroy both objects + sho.Reset(); + sho2.Reset(); + + // create shared object + LazySharedObjectPtr sho3 = SharedObjectFactory::Create( + SHM_KEY, SEM_NAME); + + RUNNER_ASSERT(sho3->IsRead() == false); + + // set property causing lazy init + sho3->SetProperty<0>(43); + value = sho3->GetProperty<0, int>(); + + RUNNER_ASSERT(sho3->IsRead() == true); + RUNNER_ASSERT(value == 43); +} + +////////////////////////////////////////////// + +bool SetCondition(const int& readValue, int& setValue); +bool SetCondition(const int& readValue, int& setValue) +{ + LogDebug("Condition delegate called with read value = " << readValue << + " and set value = " << setValue); + + if (readValue > 3) { + LogDebug("Condition is false"); + return false; + } + + LogDebug("Condition is true"); + if (4 == setValue) { + setValue = 10; + LogDebug("Changing set value to " << setValue); + } + return true; +} + +void SetDelegate(const int& readValue); +void SetDelegate(const int& readValue) +{ + LogDebug("Set delegate called " << readValue); + g_delegateCalls++; +} + +RUNNER_TEST(SharedMemory_120_ConditionalSet) +{ + RemoveIpcs(); + + TestSharedObjectPtr sho = SharedObjectFactory::Create( + SHM_KEY, + SEM_NAME); + + g_delegateCalls = 0; + + RUNNER_ASSERT(0 == (sho->GetProperty<0, int>())); + + std::function condition = SetCondition; + std::function delegate = SetDelegate; + + bool succeeded = false; + + succeeded = sho->ConditionalSetProperty<0>(-2, condition); + + RUNNER_ASSERT(succeeded); + RUNNER_ASSERT(-2 == (sho->GetProperty<0, int>())); + + succeeded = sho->ConditionalSetProperty<0>(4, condition, delegate); + + RUNNER_ASSERT(succeeded); + RUNNER_ASSERT(10 == (sho->GetProperty<0, int>())); + RUNNER_ASSERT(1 == g_delegateCalls); + + succeeded = sho->ConditionalSetProperty<0>(5, condition); + + RUNNER_ASSERT(!succeeded); + RUNNER_ASSERT(10 == (sho->GetProperty<0, int>())); + + succeeded = sho->ConditionalSetProperty<0>(666, condition, delegate); + + RUNNER_ASSERT(!succeeded); + RUNNER_ASSERT(10 == (sho->GetProperty<0, int>())); + RUNNER_ASSERT(1 == g_delegateCalls); +} + +////////////////////////////////////////////// + +/* + * Shared object used by multiple threads as a singleton. + */ +class MTSharedObject : public SharedObject +{ + public: + explicit MTSharedObject(const std::string& semaphore) : + SharedObject(semaphore) + {} + + void Clear(); + + private: + friend class SharedObjectFactory; +}; + +typedef std::shared_ptr MTSharedObjectPtr; + +void MTSharedObject::Clear() +{ + int array[64] = {}; + SetProperty<0>(0); + SetProperty<1>(0); + SetProperty<2>(static_cast(0)); + SetProperty<3>(array); +} + +/* + * Shared object singleton + */ +class SharedObjectSingleton +{ + public: + static MTSharedObjectPtr Instance(); + static void Destroy(); + + private: + static MTSharedObjectPtr m_sho; + static DPL::Mutex m_mutex; +}; + +MTSharedObjectPtr SharedObjectSingleton::m_sho; +DPL::Mutex SharedObjectSingleton::m_mutex; + +MTSharedObjectPtr SharedObjectSingleton::Instance() +{ + DPL::Mutex::ScopedLock lock(&m_mutex); + if (!m_sho) { + m_sho = SharedObjectFactory::Create(SHM_KEY, SEM_NAME); + } + return m_sho; +} + +void SharedObjectSingleton::Destroy() +{ + DPL::Mutex::ScopedLock lock(&m_mutex); + m_sho.Reset(); +} + +/* + * Listening controller + */ +class ShmController4 : public ListeningController, + public ISharedObjectListener<0, int>, + public ISharedObjectListener<1, int>, + public ISharedObjectListener<2, char>, + public ISharedObjectListener<3, int[64]> +{ + public: + enum { + ADD_LISTENERS = 2, + REMOVE_LISTENERS = 3, + DESTROY_SINGLETON = 4 + }; + + explicit ShmController4(DPL::WaitableEvent* event) : + ListeningController(event), + m_counter(0) + {} + + virtual void OnEventReceived(const int& event); + + virtual void ValueChanged(size_t propertyEnum, + const int& value, + const void* info = NULL); + virtual void ValueChanged(size_t propertyEnum, + const char& value, + const void* info = NULL); + virtual void ValueChanged(size_t propertyEnum, + const int(&value)[64], + const void* info = NULL); + + bool NotRegistered(); + + private: + void Sleep(); + + size_t m_counter; + static unsigned int seed = time(NULL); +}; + +void ShmController4::ValueChanged(size_t propertyEnum, + const int& value, + const void* /*info*/) +{ + LogDebug("ValueChanged(int) " << propertyEnum << " " << value); + if ((propertyEnum == 0 && value == 1) || + (propertyEnum == 1 && value == 11)) + { + m_waitable->Signal(); + } +} + +void ShmController4::ValueChanged(size_t propertyEnum, + const char& value, + const void* /*info*/) +{ + LogDebug("ValueChanged(char) " << propertyEnum << " " << value); + if (propertyEnum == 2 && value == 'a') { + m_waitable->Signal(); + } +} + +void ShmController4::ValueChanged(size_t propertyEnum, + const int(&value)[64], + const void* /*info*/) +{ + LogDebug("ValueChanged(int[64]) " << propertyEnum << " " << value[5]); + if (propertyEnum == 3 && value[0] == 0 && value[1] == 1 && value[2] == 2) { + m_waitable->Signal(); + } +} + +void ShmController4::Sleep() +{ + DPL::Thread::GetCurrentThread()->MiliSleep( + rand_r(&seed) % MAX_SINGLETON_LISTENER_DELAY); +} + +void ShmController4::OnEventReceived(const int& event) +{ + switch (event) { + case INIT_EVENT: + m_so = SharedObjectSingleton::Instance(); + m_waitable->Signal(); + break; + + case DESTROY_EVENT: + LogDebug("Destroying shared object"); + // deregister, destroy and notify main thread + m_so.Reset(); + m_waitable->Signal(); + break; + + case ADD_LISTENERS: + // add listener and notify + m_so->AddListener<0, int>(this); + Sleep(); + m_so->AddListener<1, int>(this); + Sleep(); + m_so->AddListener<2, char>(this); + Sleep(); + m_so->AddListener<3, int[64]>(this); + Sleep(); + m_waitable->Signal(); + break; + + case REMOVE_LISTENERS: + // remove listener and notify + m_so->RemoveListener<0, int>(this); + Sleep(); + m_so->RemoveListener<1, int>(this); + Sleep(); + m_so->RemoveListener<2, char>(this); + Sleep(); + m_so->RemoveListener<3, int[64]>(this); + Sleep(); + m_waitable->Signal(); + break; + + case DESTROY_SINGLETON: + SharedObjectSingleton::Destroy(); + m_waitable->Signal(); + break; + + default: + LogError("Unsupported event received: " << event); + } +} + +void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS]); +void MultipleWait(DPL::WaitableEvent(&event)[MAX_THREADS]) +{ + for (size_t i = 0; i < MAX_THREADS; ++i) { + Wait(event[i]); + } +} + +/* + * Try to remove property listener. If there's no such listener an exception + * should be thrown. + */ +#define LISTENER_ASSERT(property) \ + Try { \ + singleton->RemoveListener<(property)>(controller[i]); \ + LogError("Controller " << i << " is still listening for property " \ + << #property); \ + RUNNER_ASSERT_MSG(false, "No listeners expected"); \ + } \ + Catch(MTSharedObject::Exception::ListenerNotFound) { \ + RUNNER_ASSERT(true); \ + } \ + +// test +RUNNER_TEST(SharedMemory_130_SharedObjectSingleton) +{ + RemoveIpcs(); // we need non existing shm + + // writer shared object + TestSharedObjectPtr sho = SharedObjectFactory::Create( + SHM_KEY, SEM_NAME); + + ShmController4* controller[MAX_THREADS]; + DPL::WaitableEvent waitable[MAX_THREADS]; + + const int array[64] = { 0, 1, 2 }; + + // Create and wait for notification. Make sure that the thread/controller 0 + // is created first + LogDebug("Creating controllers"); + for (size_t i = 0; i < MAX_THREADS; ++i) { + controller[i] = new ShmController4(&waitable[i]); + Wait(waitable[i]); + } + + // singleton will be created by thread/controller 0 by now + MTSharedObjectPtr singleton = SharedObjectSingleton::Instance(); + + for (size_t repeats = 0; repeats < SINGLETON_TEST_REPEATS; ++repeats) { + LogDebug("%%%%%%%%%%%%%%%%%%%%%"); + LogDebug("Iteration " << repeats + 1 << " of " << SINGLETON_TEST_REPEATS); + singleton->Clear(); + + // add listeners + LogDebug("Adding listeners"); + for (size_t i = 0; i < MAX_THREADS; ++i) { + controller[i]->PostEvent(ShmController4::ADD_LISTENERS); + } + // wait for listeners + MultipleWait(waitable); + + RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 0); + RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 0); + RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 0); + + int checkArray[64] = {}; + singleton->GetProperty<3>(checkArray); + RUNNER_ASSERT(checkArray[0] == 0); + RUNNER_ASSERT(checkArray[1] == 0); + RUNNER_ASSERT(checkArray[2] == 0); + + // change + LogDebug("Setting property 0"); + sho->SetProperty<0>(1); + // wait for confirmations + MultipleWait(waitable); + + // change + LogDebug("Setting property 1"); + sho->SetProperty<1>(11); + // wait for confirmations + MultipleWait(waitable); + + // change + LogDebug("Setting property 2"); + sho->SetProperty<2>('a'); + // wait for confirmations + MultipleWait(waitable); + + // change + LogDebug("Setting property 3"); + sho->SetProperty<3>(array); + // wait for confirmations + MultipleWait(waitable); + + // remove listeners + LogDebug("Removing listeners"); + for (size_t i = 0; i < MAX_THREADS; ++i) { + controller[i]->PostEvent(ShmController4::REMOVE_LISTENERS); + } + // wait for listeners + MultipleWait(waitable); + + // check if listeners array is empty + LogDebug("Checking listeners"); + for (size_t i = 0; i < MAX_THREADS; ++i) { + LISTENER_ASSERT(0); + LISTENER_ASSERT(1); + LISTENER_ASSERT(2); + LISTENER_ASSERT(3); + } + + RUNNER_ASSERT((singleton->GetProperty<0, int>()) == 1); + RUNNER_ASSERT((singleton->GetProperty<1, int>()) == 11); + RUNNER_ASSERT((singleton->GetProperty<2, char>()) == 'a'); + singleton->GetProperty<3>(checkArray); + RUNNER_ASSERT(checkArray[0] == 0); + RUNNER_ASSERT(checkArray[1] == 1); + RUNNER_ASSERT(checkArray[2] == 2); + } + + singleton.Reset(); + + // Destroy controllers and wait for confirmation. Make sure that + // thread/controller 0 is destroyed in the end + LogDebug("Destroying controllers"); + for (int i = MAX_THREADS - 1; i >= 0; --i) { + controller[i]->PostEvent(DESTROY_EVENT); + Wait(waitable[i]); + if (i == 0) { + /* + * Destroy singleton before thread that created it finishes. + * This is to properly close all waitable handles opened by + * SharedObject in thread 0. + */ + LogDebug("Destroying singleton"); + controller[i]->PostEvent(ShmController4::DESTROY_SINGLETON); + Wait(waitable[i]); + } + delete controller[i]; + } +} + +#undef LISTENER_ASSERT + +/* + * test preconditions & postconditions: + * - no existing shared memory with given SHM_KEY + * - no existing semaphore of given SEM_NAME + */ +RUNNER_TEST(SharedMemory_001_Preconditions) { + RemoveIpcs(); +} + +RUNNER_TEST(SharedMemory_999_Postconditions) { + RemoveIpcs(); +} diff --git a/tests/unused/test_sql_connection.cpp b/tests/unused/test_sql_connection.cpp new file mode 100644 index 0000000..bc2b7e0 --- /dev/null +++ b/tests/unused/test_sql_connection.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_sql_connection.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of sql connection tests + */ + +/* + * + * This test has been saved from original test_sql_connection.cpp in wrt-commons + * project. + * + */ + +#include + +RUNNER_TEST(SqlConnection_MassiveReadWrite_SemaphoreSynchronization) +{ + std::ostringstream dbSemaporeFileNameStream; + unsigned int seed = time(NULL); + + dbSemaporeFileNameStream << "dpl_tests_dbso_sem_"; + dbSemaporeFileNameStream << rand_r(&seed) << ".sem"; + + std::string dbSemaphoreFileName = dbSemaporeFileNameStream.str(); + + SemaphoreSynchronizationObjectGenerator m_generator(dbSemaphoreFileName); + MassiveReadWriteTest(&m_generator); +} diff --git a/tests/unused/test_task.cpp b/tests/unused/test_task.cpp new file mode 100644 index 0000000..a885dcd --- /dev/null +++ b/tests/unused/test_task.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_task.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of task tests + */ +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL) + +class MySingleTask : + public DPL::TaskDecl +{ + protected: + void StepOne() + {} + + public: + MySingleTask() : + DPL::TaskDecl(this) + { + AddStep(&MySingleTask::StepOne); + } +}; + +class MyMultiTask : + public DPL::MultiTaskDecl +{ + protected: + typedef DPL::MultiTaskDecl BaseType; + + void StepOne() + { + LogDebug("Step one"); + } + + void StepTwo() + { + LogDebug("Step two"); + } + + void StepThree() + { + LogDebug("Step three"); + } + + public: + MyMultiTask() : + BaseType(this, 2) + { + BaseType::StepList depListStepThree; + depListStepThree.push_back(&MyMultiTask::StepOne); + depListStepThree.push_back(&MyMultiTask::StepTwo); + AddStep(&MyMultiTask::StepThree, depListStepThree); + + BaseType::StepList depListStepTwo; + depListStepTwo.push_back(&MyMultiTask::StepOne); + AddStep(&MyMultiTask::StepTwo, depListStepTwo); + + BaseType::StepList depListStepOne; + AddStep(&MyMultiTask::StepOne, depListStepOne); + } +}; + +RUNNER_TEST(Task_SingleTask) +{ + MySingleTask task; + while (task.NextStep()) {} +} + +RUNNER_TEST(Task_MultiTask) +{ + MyMultiTask task; + while (task.NextStep()) {} +} diff --git a/tests/utils/CMakeLists.txt b/tests/utils/CMakeLists.txt new file mode 100644 index 0000000..f17421b --- /dev/null +++ b/tests/utils/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# @file CMakeLists.txt +# @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com) +# @version 1.0 +# @brief +# + +SET(TARGET_NAME "wrt-commons-tests-utils") + +# Set DPL tests sources +SET(DPL_TESTS_UTIL_SOURCES + ${TESTS_DIR}/utils/main.cpp + ${TESTS_DIR}/utils/widget_version.cpp + ${TESTS_DIR}/utils/bash_utils.cpp + ${TESTS_DIR}/utils/wrt_utility.cpp + ${TESTS_DIR}/utils/path_tests.cpp +) + +#WRT_TEST_ADD_INTERNAL_DEPENDENCIES(${TARGET_NAME} ${TARGET_DPL_UTILS_EFL}) +WRT_TEST_BUILD(${TARGET_NAME} ${DPL_TESTS_UTIL_SOURCES}) +WRT_TEST_INSTALL(${TARGET_NAME}) diff --git a/tests/utils/bash_utils.cpp b/tests/utils/bash_utils.cpp new file mode 100644 index 0000000..7dac1fc --- /dev/null +++ b/tests/utils/bash_utils.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file bash_utils.cpp + * @author Iwanek Tomasz + * @version 1.0 + */ +#include +#include +#include + +using namespace BashUtils; + +RUNNER_TEST_GROUP_INIT(DPL_BASH_UTILS) + +/* +Name: Bash_Utils_escape_arg +Description:tests ecaping bash special characters for command arguments +Expected: matching string +*/ +RUNNER_TEST(Bash_Utils_escape_arg) +{ + RUNNER_ASSERT_MSG(escape_arg(std::string( + "valid")) == "\"valid\"", + "Valid argument failed"); + LogDebug("\"val\\!d\"" << " " << escape_arg(std::string("val!d"))); + RUNNER_ASSERT_MSG(escape_arg(std::string( + "val!d")) == "\"val\\!d\"", + "Single escaped character in argument failed"); + LogDebug("\"v\\$l\\$\\$\"" << " " << escape_arg(std::string("v$l$$"))); + RUNNER_ASSERT_MSG(escape_arg(std::string( + "v$l$$")) == "\"v\\$l\\$\\$\"", + "Multiple occurences of single special character in argument failed"); + LogDebug("\"v\\`\\$\\\"\\!d\\`\"" << " " << + escape_arg(std::string("v`$\"!d`"))); + RUNNER_ASSERT_MSG(escape_arg(std::string( + "v`$\"!d`")) == "\"v\\`\\$\\\"\\!d\\`\"", + "Multiple occurences of multiple special character in argument failed"); +} diff --git a/tests/utils/main.cpp b/tests/utils/main.cpp new file mode 100644 index 0000000..42ffe3a --- /dev/null +++ b/tests/utils/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file main.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of main + */ +#include + +int main(int argc, char *argv[]) +{ + return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv); +} + diff --git a/tests/utils/path_tests.cpp b/tests/utils/path_tests.cpp new file mode 100644 index 0000000..e612ad7 --- /dev/null +++ b/tests/utils/path_tests.cpp @@ -0,0 +1,958 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file path.h + * @author Tomasz Iwanek (t.iwanek@samsung.com) + * @version 1.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace DPL::Utils; + +namespace { +//do not used path here we test it +std::string rootTest = "/tmp/wrttest/"; +} + +#define ROOTGUARD_TESTMETHOD(FUNC) \ +{ \ + bool catched = false; \ + Try { \ + FUNC; \ + } Catch(Path::RootDirectoryError) { \ + catched = true; \ + } \ + RUNNER_ASSERT_MSG(catched, "Use of method should be protected against root diretory"); \ +} \ + +RUNNER_TEST_GROUP_INIT(DPL_Path) + +/* +Name: path_touch +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_mkfile) +{ + DPL::ScopedDir sd(rootTest); + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + Path path = Path(rootTest) / "touch.txt"; + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) != 0, "File should not be created"); + RUNNER_ASSERT(!path.Exists()); + MakeEmptyFile(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "File should be created"); + RUNNER_ASSERT(path.Exists()); + RUNNER_ASSERT(path.IsFile()); + RUNNER_ASSERT(!path.IsDir()); + RUNNER_ASSERT(!path.IsSymlink()); +} + +/* +Name: path_touch +Description: tries to craete file when it exists +Expected: failure +*/ +RUNNER_TEST(path_mkfile_exists) +{ + DPL::ScopedDir sd(rootTest); + + Path path = Path(rootTest) / "touch.txt"; + MakeEmptyFile(path); + RUNNER_ASSERT(path.Exists()); + bool cannotCreate2ndTime = false; + Try + { + MakeEmptyFile(path); + } + Catch(Path::AlreadyExists) + { + cannotCreate2ndTime = true; + } + RUNNER_ASSERT_MSG(cannotCreate2ndTime, "File created should not be able to be created second time"); +} + +/* +Name: path_exists_and_is_file_or_dir +Description: test for checking for existence of directory or file +Expected: success +*/ +RUNNER_TEST(path_exists_and_is_file_or_dir) +{ + DPL::ScopedDir sd(rootTest); + + Path file = Path(rootTest) / "testfile.txt"; + MakeEmptyFile(file); + RUNNER_ASSERT_MSG(file.ExistsAndIsFile(), "File should exist"); + RUNNER_ASSERT_MSG(!file.ExistsAndIsDir(), "It should not be a directory"); + + Path dir = Path(rootTest) / "testdir"; + MakeDir(dir); + RUNNER_ASSERT_MSG(dir.ExistsAndIsDir(), "Directory should exist"); + RUNNER_ASSERT_MSG(!dir.ExistsAndIsFile(), "Is should not be a file"); +} + +/* +Name: path_mkfile_invalid_path +Description: tries to create file in not exisitng directory +Expected: failure at creation +*/ +RUNNER_TEST(path_mkfile_invalid_path) +{ + DPL::ScopedDir sd(rootTest); + + Path path = Path(rootTest) / "not_existing" / "touch.txt"; + bool cannotCreate = false; + Try + { + MakeEmptyFile(path); + } + Catch(Path::OperationFailed) + { + cannotCreate = true; + } + RUNNER_ASSERT_MSG(cannotCreate, "File created should not be able to be created"); +} + +/* +Name: path_mkdir +Description: creates valid directory +Expected: success direcotry creation +*/ +RUNNER_TEST(path_mkdir) +{ + DPL::ScopedDir sd(rootTest); + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + Path path = Path(rootTest) / "touchDir"; + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) != 0, "Directory should not be created"); + RUNNER_ASSERT(!path.Exists()); + MakeDir(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "Directory should be created"); + RUNNER_ASSERT(path.Exists()); + RUNNER_ASSERT(!path.IsFile()); + RUNNER_ASSERT(path.IsDir()); + RUNNER_ASSERT(!path.IsSymlink()); +} + +/* +Name: path_symlink +Description: chekc if symlink is correctly recognized +Expected: method isSymlink returns true +*/ +RUNNER_TEST(path_symlink) +{ + DPL::ScopedDir sd(rootTest); + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + Path path = Path(rootTest) / "symlink"; + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) != 0, "Symlink should not be created"); + RUNNER_ASSERT(!path.Exists()); + (void)symlink("/nonexistisfile/file/file/file ", path.Fullpath().c_str()); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "Symlink should be created"); + RUNNER_ASSERT(path.Exists()); + RUNNER_ASSERT(!path.IsFile()); + RUNNER_ASSERT(!path.IsDir()); + RUNNER_ASSERT(path.IsSymlink()); +} + +/* +Name: path_construction_empty +Description: tries to construct empty path +Expected: failure +*/ +RUNNER_TEST(path_construction_empty) +{ + bool passed = false; + Try + { + Path path1(std::string("")); + } + Catch(Path::EmptyPath) + { + passed = true; + } + RUNNER_ASSERT_MSG(passed, "Construction with empty path do not fails"); +} + +/* +Name: path_construction_root +Description: tries to construct root path +Expected: success +*/ +RUNNER_TEST(path_construction_root) +{ + Path path1(std::string("/")); + RUNNER_ASSERT(path1.Fullpath() == "/"); + RUNNER_ASSERT(path1.Filename() == ""); + bool passed = false; + Try + { + RUNNER_ASSERT(path1.DirectoryName() == "/"); + } + Catch(Path::InternalError) + { + passed = true; + } + RUNNER_ASSERT_MSG(passed, "Directory name for root should be an error"); +} + +/* +Name: path_construction_1 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_1) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + + Path path1(std::string("/test/bin/file")); + RUNNER_ASSERT(path1.Fullpath() == "/test/bin/file"); + RUNNER_ASSERT(path1.Filename() == "file"); + RUNNER_ASSERT(path1.DirectoryName() == "/test/bin"); +} + +/* +Name: path_construction_2 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_2) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + std::string cwd(sf.Get()); + + if("/" == cwd) + cwd = ""; + + Path path2(std::string("test/bin/file.eas")); + RUNNER_ASSERT(path2.Fullpath() == cwd + "/test/bin/file.eas"); + RUNNER_ASSERT(path2.Filename() == "file.eas"); + RUNNER_ASSERT(path2.DirectoryName() == cwd + "/test/bin"); +} + +/* +Name: path_construction_3 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_3) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + std::string cwd(sf.Get()); + + if("/" == cwd) + cwd = ""; + + Path path3("test/23/abc"); + RUNNER_ASSERT(path3.Fullpath() == cwd + "/test/23/abc"); + RUNNER_ASSERT(path3.Filename() == "abc"); + RUNNER_ASSERT(path3.DirectoryName() == cwd + "/test/23"); +} + +/* +Name: path_construction_4 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_4) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + + Path path4("/test/bin/abc"); + RUNNER_ASSERT(path4.Fullpath() == "/test/bin/abc"); + RUNNER_ASSERT(path4.Filename() == "abc"); + RUNNER_ASSERT(path4.DirectoryName() == "/test/bin"); +} + +/* +Name: path_construction_5 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_5) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + std::string cwd(sf.Get()); + + if("/" == cwd) + cwd = ""; + + Path path5(DPL::String(L"test/bin/file.st.exe")); + RUNNER_ASSERT(path5.Fullpath() == cwd + "/test/bin/file.st.exe"); + RUNNER_ASSERT(path5.Filename() == "file.st.exe"); + RUNNER_ASSERT(path5.DirectoryName() == cwd + "/test/bin"); +} + +/* +Name: path_construction_6 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_6) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + + Path path6(DPL::String(L"/test/bin/file")); + RUNNER_ASSERT(path6.Fullpath() == "/test/bin/file"); + RUNNER_ASSERT(path6.Filename() == "file"); + RUNNER_ASSERT(path6.DirectoryName() == "/test/bin"); +} + +/* +Name: path_construction_7 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_7) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + std::string cwd(sf.Get()); + + if("/" == cwd) + cwd = ""; + + Path path7 = Path("test") / "a///23/lol"; + RUNNER_ASSERT(path7.Fullpath() == cwd + "/test/a/23/lol"); + RUNNER_ASSERT(path7.Filename() == "lol"); + RUNNER_ASSERT(path7.DirectoryName() == cwd + "/test/a/23"); +} + +/* +Name: path_construction_8 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_8) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + + Path path8 = Path("/test/bin/") / "123" / "dir1.dll"; + RUNNER_ASSERT(path8.Fullpath() == "/test/bin/123/dir1.dll"); + RUNNER_ASSERT(path8.Filename() == "dir1.dll"); + RUNNER_ASSERT(path8.DirectoryName() == "/test/bin/123"); +} + +/* +Name: path_construction_9 +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_9) +{ + DPL::ScopedFree sf(getcwd(NULL, 0)); + + Path path9 = Path("/test/bin/file.txt//"); + RUNNER_ASSERT(path9.Fullpath() == "/test/bin/file.txt"); + RUNNER_ASSERT(path9.Filename() == "file.txt"); + RUNNER_ASSERT(path9.DirectoryName() == "/test/bin"); +} + +/* +Name: path_construction_10 +Description: constructs paths by appending +Expected: success full constrution +*/ +RUNNER_TEST(path_construction_10) +{ + Path path10 = Path("/test/"); + path10 /= "one"; + path10 /= std::string("two"); + path10 /= DPL::String(L"three"); + RUNNER_ASSERT(path10.Fullpath() == "/test/one/two/three"); + RUNNER_ASSERT(path10.Filename() == "three"); + RUNNER_ASSERT(path10.DirectoryName() == "/test/one/two"); +} + +/* +Name: path_remove +Description: tests removing paths +Expected: successfull path remove +*/ +RUNNER_TEST(path_remove_valid) +{ + DPL::ScopedDir sd(rootTest); + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + Path path = Path(rootTest) / "touchDir"; + RUNNER_ASSERT(!path.Exists()); + + MakeDir(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "Directory should be created"); + RUNNER_ASSERT(path.Exists()); + + Remove(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) != 0, "Directory should not be created"); + RUNNER_ASSERT(!path.Exists()); + + MakeEmptyFile(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "File should be created"); + RUNNER_ASSERT(path.Exists()); + + Remove(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) != 0, "File should not be created"); + RUNNER_ASSERT(!path.Exists()); +} + +/* +Name: path_try_remove +Description: tests removing paths +Expected: successfull path remove once +*/ +RUNNER_TEST(path_try_remove_valid) +{ + DPL::ScopedDir sd(rootTest); + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + Path path = Path(rootTest) / "touchDir"; + RUNNER_ASSERT(!path.Exists()); + + MakeDir(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "Directory should be created"); + RUNNER_ASSERT(path.Exists()); + + RUNNER_ASSERT(TryRemove(path)); + RUNNER_ASSERT(!TryRemove(path)); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) != 0, "Directory should not be created"); + RUNNER_ASSERT(!path.Exists()); + + MakeEmptyFile(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "File should be created"); + RUNNER_ASSERT(path.Exists()); + + RUNNER_ASSERT(TryRemove(path)); + RUNNER_ASSERT(!TryRemove(path)); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) != 0, "File should not be created"); + RUNNER_ASSERT(!path.Exists()); +} + +/* +Name: path_remove_invalid +Description: tests removing invalid paths +Expected: failure at path remove +*/ +RUNNER_TEST(path_remove_invalid) +{ + DPL::ScopedDir sd(rootTest); + + Path path = Path(rootTest) / "touchDir"; + + bool removedNotExisting = true; + Try + { + Remove(path); + } + Catch(Path::OperationFailed) + { + removedNotExisting = false; + } + RUNNER_ASSERT_MSG(!removedNotExisting, "Removing not existing file"); +} + +/* +Name: path_rename +Description: tests path renaming +Expected: path is successfully renamed +*/ +RUNNER_TEST(path_rename) +{ + DPL::ScopedDir sd(rootTest); + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + Path path = Path(rootTest) / "touchDir"; + Path dirpath = Path(rootTest) / "directory"; + Path path2 = dirpath / "touchDir2"; + + MakeDir(dirpath); + + MakeEmptyFile(path); + RUNNER_ASSERT_MSG(lstat(path.Fullpath().c_str(), &st) == 0, "File should be created"); + RUNNER_ASSERT(path.Exists()); + RUNNER_ASSERT(!path2.Exists()); + + Rename(path, path2); + RUNNER_ASSERT(!path.Exists()); + RUNNER_ASSERT(path2.Exists()); + + Rename(path2, path); + RUNNER_ASSERT(path.Exists()); + RUNNER_ASSERT(!path2.Exists()); +} + +/* +Name: path_rename_xdev +Description: tests path renaming between devices +Expected: path is successfully renamed +*/ +RUNNER_TEST(path_rename_xdev) +{ + //assuming /opt/usr and /usr is normally on other partitions on device + //TODO: better + Path path = Path("/opt/usr") / "touchDir"; + Path dirpath = path / "directory"; + Path filepath = path / "file.txt"; + + Path path2 = Path("/usr") / "touchDir2"; + Path dirpath2 = path2 / "directory"; + Path filepath2 = path2 / "file.txt"; + + TryRemove(path); + + MakeDir(path); + MakeDir(dirpath); + MakeEmptyFile(filepath); + + RUNNER_ASSERT(path.Exists()); + RUNNER_ASSERT(dirpath.Exists()); + RUNNER_ASSERT(filepath.Exists()); + RUNNER_ASSERT(!path2.Exists()); + RUNNER_ASSERT(!dirpath2.Exists()); + RUNNER_ASSERT(!filepath2.Exists()); + + Rename(path, path2); + RUNNER_ASSERT(!path.Exists()); + RUNNER_ASSERT(!dirpath.Exists()); + RUNNER_ASSERT(!filepath.Exists()); + RUNNER_ASSERT(path2.Exists()); + RUNNER_ASSERT(dirpath2.Exists()); + RUNNER_ASSERT(filepath2.Exists()); + + Rename(path2, path); + RUNNER_ASSERT(path.Exists()); + RUNNER_ASSERT(dirpath.Exists()); + RUNNER_ASSERT(filepath.Exists()); + RUNNER_ASSERT(!path2.Exists()); + RUNNER_ASSERT(!dirpath2.Exists()); + RUNNER_ASSERT(!filepath2.Exists()); + + Remove(path); +} + +/** + * Name: path_basename + * Description: check basename equivalents + * Expected: failure + */ +RUNNER_TEST(path_basename) +{ + DPL::ScopedDir sd(rootTest); + Path path = Path(rootTest) / "directory" / "touch.txt"; + RUNNER_ASSERT(path.DirectoryName() == path.DirectoryPath().Fullpath()); + RUNNER_ASSERT(path.DirectoryPath().DirectoryName() == path.DirectoryPath().DirectoryPath().Fullpath()); +} + +/** + * Name: path_safe + * Description: check if operations cannot be executed on root directory + * + * This is check because of default path is root and it should not be used usually + * Default constructor is unfortnatelly easier to use + * + * Expected: failure + */ +RUNNER_TEST(path_safe) +{ + DPL::ScopedDir sd(rootTest); + Path normal = Path(rootTest) / "directory" / "touch.txt"; + Path root("/"); + ROOTGUARD_TESTMETHOD( Rename(normal, root) ); + ROOTGUARD_TESTMETHOD( Rename(root, root) ); + ROOTGUARD_TESTMETHOD( Rename(root, normal) ); + ROOTGUARD_TESTMETHOD( CopyDir(normal, root) ); + ROOTGUARD_TESTMETHOD( CopyDir(root, root) ); + ROOTGUARD_TESTMETHOD( CopyDir(root, normal) ); + ROOTGUARD_TESTMETHOD( CopyFile(normal, root) ); + ROOTGUARD_TESTMETHOD( CopyFile(root, root) ); + ROOTGUARD_TESTMETHOD( CopyFile(root, normal) ); + ROOTGUARD_TESTMETHOD( Remove(root) ); + ROOTGUARD_TESTMETHOD( MakeEmptyFile(root) ); + ROOTGUARD_TESTMETHOD( MakeDir(root) ); +} + +/** + * Name: path_size + * Description: check testing size of file + * Expected: correct size + */ +RUNNER_TEST(path_size) +{ + DPL::ScopedDir sd(rootTest); + Path path = Path(rootTest) / "touch.txt"; + DPL::Utils::MakeEmptyFile(path); + RUNNER_ASSERT(path.Size() == 0); + + { + DPL::FileOutput out(path.Fullpath()); + DPL::BinaryQueue bq; + bq.AppendCopy("123456789", 9); + out.Write(bq, bq.Size()); + out.Close(); + RUNNER_ASSERT(path.Size() == 9); + } + + { + DPL::FileOutput out(path.Fullpath()); + DPL::BinaryQueue bq; + bq.AppendCopy("123456789", 4); + out.Write(bq, bq.Size()); + out.Close(); + RUNNER_ASSERT(path.Size() == 4); + } +} + +/** +Name: path_copy +Description: tests path coping directory andfiles +Expected: coping should be done +*/ +RUNNER_TEST(path_copy_directory) +{ + DPL::ScopedDir sd(rootTest); + + Path path = Path(rootTest) / "sourceDir"; + Path innerPath = Path(rootTest) / "sourceDir" / "level1" ; + Path innerPath2 = Path(rootTest) / "sourceDir" / "level1" / "level2"; + Path file1 = Path(rootTest) / "sourceDir" / "level1" / "level2" / "file1.txt"; + Path file2 = Path(rootTest) / "sourceDir" / "level1" / "level2" / "file2.txt"; + Path file3 = Path(rootTest) / "sourceDir" / "level1" / "file3.txt"; + Path file4 = Path(rootTest) / "sourceDir" / "file4.txt"; + + Path tfile1 = Path(rootTest) / "targetDir" / "level1" / "level2" / "file1.txt"; + Path tfile2 = Path(rootTest) / "targetDir" / "level1" / "level2" / "file2.txt"; + Path tfile3 = Path(rootTest) / "targetDir" / "level1" / "file3.txt"; + Path tfile4 = Path(rootTest) / "targetDir" / "file4.txt"; + + Path target = Path(rootTest) / "targetDir"; + + DPL::Utils::MakeDir(path); + DPL::Utils::MakeDir(innerPath); + DPL::Utils::MakeDir(innerPath2); + DPL::Utils::MakeEmptyFile(file1); + DPL::Utils::MakeEmptyFile(file2); + DPL::Utils::MakeEmptyFile(file3); + DPL::Utils::MakeEmptyFile(file4); + + DPL::Utils::CopyDir(path, target); + + RUNNER_ASSERT_MSG(tfile1.Exists(), tfile1.Fullpath() + " not exists"); + RUNNER_ASSERT_MSG(tfile1.IsFile(), tfile1.Fullpath() + " is not file"); + RUNNER_ASSERT_MSG(tfile2.Exists(), tfile2.Fullpath() + " not exists"); + RUNNER_ASSERT_MSG(tfile2.IsFile(), tfile2.Fullpath() + " is not file"); + RUNNER_ASSERT_MSG(tfile3.Exists(), tfile3.Fullpath() + " not exists"); + RUNNER_ASSERT_MSG(tfile3.IsFile(), tfile3.Fullpath() + " is not file"); + RUNNER_ASSERT_MSG(tfile4.Exists(), tfile4.Fullpath() + " not exists"); + RUNNER_ASSERT_MSG(tfile4.IsFile(), tfile4.Fullpath() + " is not file"); +} + +/* +Name: path_copy_inner +Description: tests path coping to subdirectory +Expected: coping shoudl fail +*/ +RUNNER_TEST(path_copy_inner) +{ + DPL::ScopedDir sd(rootTest); + + Path path = Path(rootTest) / "touchDir"; + Path inner = Path(rootTest) / "touchDir" / "innerDirectory"; + + bool exceptionCatched = false; + Try + { + DPL::Utils::CopyDir(path, inner); + } + Catch(DPL::Utils::Path::CannotCopy) + { + exceptionCatched = true; + } + RUNNER_ASSERT_MSG(exceptionCatched, "Copy should fail"); +} + +/* +Name: issubpath +Description: tests method compare if one path is subpath of another +Expected: correct results +*/ +RUNNER_TEST(path_issubpath) +{ + Path path1 = Path(rootTest) / "touchDir/asd/sdf"; + Path path2 = Path(rootTest) / "touchDir/asd/sdf/123"; + Path path3 = Path(rootTest) / "touchDir/asd/sdno"; + Path path4 = Path("/"); + + RUNNER_ASSERT(path1.isSubPath(path2)); + RUNNER_ASSERT(!path1.isSubPath(path3)); + RUNNER_ASSERT(!path1.isSubPath(path4)); + + RUNNER_ASSERT(!path2.isSubPath(path1)); + RUNNER_ASSERT(!path2.isSubPath(path3)); + RUNNER_ASSERT(!path2.isSubPath(path4)); + + RUNNER_ASSERT(path4.isSubPath(path1)); + RUNNER_ASSERT(path4.isSubPath(path2)); + RUNNER_ASSERT(path4.isSubPath(path3)); +} + +/* +Name: path_rename_same +Description: tests if renam does not brokens file if target location is equal to source location +Expected: path is avaliable +*/ +RUNNER_TEST(path_rename_same) +{ + DPL::ScopedDir sd(rootTest); + + struct stat st; + memset(&st, 0, sizeof(struct stat)); + Path path = Path(rootTest) / "touchDir"; + + MakeDir(path); + Rename(path, path); + RUNNER_ASSERT(path.Exists()); +} + +/* +Name: path_iterate_not_directory +Description: iterates not a directory +Expected: success full constrution +*/ +RUNNER_TEST(path_iterate_not_directory) +{ + DPL::ScopedDir sd(rootTest); + + Path fileTest = Path(rootTest) / "file.txt"; + MakeEmptyFile(fileTest); + + bool passed = false; + Try + { + FOREACH(file, fileTest) + { + + } + } + Catch(Path::NotDirectory) + { + passed = true; + } + RUNNER_ASSERT(passed); +} + +/* +Name: path_construction +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_iterate_empty_directory) +{ + DPL::ScopedDir sd(rootTest); + + Path dirTest = Path(rootTest) / "directory"; + MakeDir(dirTest); + + bool passed = true; + Try + { + FOREACH(file, dirTest) + { + passed = false; + LogError("Directory should be empty"); + } + } + Catch(Path::NotDirectory) + { + passed = false; + LogError("Directory should exists"); + } + RUNNER_ASSERT(passed); +} + +/* +Name: path_construction +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_iterate_notempty_directory) +{ + DPL::ScopedDir sd(rootTest); + + Path dirTest = Path(rootTest) / "directory"; + + Path path1 = Path(rootTest) / "directory" / "file1"; + Path path2 = Path(rootTest) / "directory" / "file2"; + Path path3 = Path(rootTest) / "directory" / "file3"; + + std::set resultSet; + std::set testSet; + testSet.insert(path1.Fullpath()); + testSet.insert(path2.Fullpath()); + testSet.insert(path3.Fullpath()); + + MakeDir(dirTest); + MakeEmptyFile(path1); + MakeEmptyFile(path2); + MakeEmptyFile(path3); + + FOREACH(file, dirTest) + { + resultSet.insert(file->Fullpath()); + } + + RUNNER_ASSERT_MSG(testSet == resultSet, "Testing"); +} + +/* +Name: path_construction +Description: constructs paths in many ways +Expected: success full constrution +*/ +RUNNER_TEST(path_iterator_copy_constructor) +{ + DPL::ScopedDir sd(rootTest); + + Path dirTest = Path(rootTest) / "directory"; + + Path path1 = Path(rootTest) / "directory" / "file1"; + Path path2 = Path(rootTest) / "directory" / "file2"; + Path path3 = Path(rootTest) / "directory" / "file3"; + + MakeDir(dirTest); + MakeEmptyFile(path1); + MakeEmptyFile(path2); + MakeEmptyFile(path3); + + std::shared_ptr iter1(new Path::Iterator((Path(rootTest) / "directory").Fullpath().c_str())); + + //as it's input iterator it's guaranteed for one element to be iterate only once + (*iter1)++; + std::shared_ptr iter2(new Path::Iterator( (*iter1))); + iter1.reset(); + (*iter2)++; + ++(*iter2); + RUNNER_ASSERT_MSG(*iter2 == dirTest.end(), "Iterator is in broken state"); + iter2.reset(); +} + +/* +Name: path_extension_test +Description: Tests if file extension is correct +Expected: Proper recognition of extensions +*/ +RUNNER_TEST(path_extension_test) +{ + Path path1("/path/to/file.dot"); + Path path2("/path/to/file..dot"); + Path path3("/path/to/file..dot."); + Path path4("/path/to/file..dot.dot"); + Path path5("/path/to.dot/file"); + Path path6("./path/to/file"); + Path path7("./path/to/file"); + Path path8("/path/../file.xml"); + Path path9("/path/../file.XML"); + Path path10("/path/../file.myfileextension"); + + RUNNER_ASSERT(path1.Extension() == "dot"); + RUNNER_ASSERT(path2.Extension() == "dot"); + RUNNER_ASSERT(path3.Extension() == ""); + RUNNER_ASSERT(path4.Extension() == "dot"); + RUNNER_ASSERT(path5.Extension() == ""); + RUNNER_ASSERT(path6.Extension() == ""); + RUNNER_ASSERT(path7.Extension() == ""); + RUNNER_ASSERT(path8.Extension() == "xml"); + RUNNER_ASSERT(path9.Extension() != "xml"); + RUNNER_ASSERT(path10.Extension() == "myfileextension"); +} + +/* +Name: path_has_extension_test +Description: Tests if file extension is correct +Expected: Proper recognition of extensions +*/ +RUNNER_TEST(path_has_extension_test) +{ + + Path dirTest = Path("extension"); + + Path path1 = dirTest / "file1.XML"; + Path path2 = dirTest / "file2.JPG"; + Path path3 = dirTest / "file3."; + Path path4 = dirTest / "file4"; + Path path5 = dirTest / "file5.HTML"; + Path path6 = dirTest / "file6.JS"; + Path path7 = dirTest / "file7.VERY_VERY_LONG_EXTENSION"; + Path path8 = dirTest / "file8.VERY.VERY.LONG.EXTENSION.WITH.DOTS"; + + RUNNER_ASSERT_MSG(path1.hasExtension("XML"), "Problem with comparison"); + RUNNER_ASSERT_MSG(path2.hasExtension("JPG"), "Problem with comparison"); + RUNNER_ASSERT_MSG(path5.hasExtension("HTML"), "Problem with comparison"); + RUNNER_ASSERT_MSG(path6.hasExtension("JS"), "Problem with comparison"); + RUNNER_ASSERT_MSG(path7.hasExtension("VERY_VERY_LONG_EXTENSION"), + "Problem with comparison"); + RUNNER_ASSERT_MSG(path8.hasExtension("DOTS"), "Problem with comparison"); + + RUNNER_ASSERT_MSG(!path1.hasExtension(".XML"), + "Wrong argument in hasExtension() function"); + RUNNER_ASSERT_MSG(!path1.hasExtension("MXL"), + "Wrong argument in hasExtension() function"); + RUNNER_ASSERT_MSG(!path2.hasExtension(".JPG"), + "Wrong argument in hasExtension() function"); + RUNNER_ASSERT_MSG(!path5.hasExtension(".HTML"), + "Wrong argument in hasExtension() function"); + RUNNER_ASSERT_MSG(!path6.hasExtension(".JS"), + "Wrong argument in hasExtension() function"); + + RUNNER_ASSERT_MSG(path3.hasExtension(""), "Extension length is 0"); + + RUNNER_ASSERT_MSG(path4.hasExtension(""), "Extension length is 0"); +} + +/* +Name: path_create_temp_dir +Description: tests if temp dir was created +Expected: temp dir exists +*/ +RUNNER_TEST(path_create_temp_dir) +{ + Path p1 = CreateTempPath(Path("/usr/tmp/")); + Path p2 = CreateTempPath(Path("/opt/usr/apps/tmp/")); + Path p3 = CreateTempPath(Path("/opt/usr/apps/tmp/")); + + RUNNER_ASSERT_MSG(p1.Exists(), "Temp dir doesn't exists"); + RUNNER_ASSERT_MSG(p2.Exists(), "Temp dir doesn't exists"); + RUNNER_ASSERT_MSG(p3.Exists(), "Temp dir doesn't exists"); + RUNNER_ASSERT_MSG(p2.Fullpath() != p3.Fullpath(), "Each temp path should be unique due to having tv_usec in dir name."); +} diff --git a/tests/utils/widget_version.cpp b/tests/utils/widget_version.cpp new file mode 100644 index 0000000..5d2bc71 --- /dev/null +++ b/tests/utils/widget_version.cpp @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file widget_version.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Implementation file for test cases for engine internal tests + */ +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL_WIDGET_VERSION) + +/* +Name: WidgetVersion_M2_O0 +Description: tests correct parsing of version widget in format: [major].[minor] +Expected: major and minor parts matches expected values +*/ +RUNNER_TEST(WidgetVersion_M2_O0) +{ + DPL::String raw(L"1.2"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == DPL::String(L"1")); + RUNNER_ASSERT(version.Minor() == DPL::String(L"2")); + RUNNER_ASSERT(version.Micro() == DPL::Optional()); + RUNNER_ASSERT(version.Optional() == DPL::Optional()); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M2_O0_nonwac_1 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M2_O0_nonwac_1) +{ + DPL::String raw(L"a1.2"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M2_O0_nonwac_2 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M2_O0_nonwac_2) +{ + DPL::String raw(L"1.2a"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M2_O0_nonwac_3 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M2_O0_nonwac_3) +{ + DPL::String raw(L"aaa1.2bbb"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M2_O0_nonwac_4 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M2_O0_nonwac_4) +{ + DPL::String raw(L"1a.a2"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M2_O0_long +Description: tests correct parsing of version widget in format: [major].[minor] + for huge number +Expected: major and minor parts matches expected values +*/ +RUNNER_TEST(WidgetVersion_M2_O0_long) +{ + DPL::String raw( + L"123456789012345678901234567890.98765432109876543210987654321"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == + DPL::String(L"123456789012345678901234567890")); + RUNNER_ASSERT(version.Minor() == + DPL::String(L"98765432109876543210987654321")); + RUNNER_ASSERT(version.Micro() == DPL::Optional()); + RUNNER_ASSERT(version.Optional() == DPL::Optional()); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M3_O0 +Description: tests correct wac version number +Expected: major and minor and micro parts matches expected values. + Version should be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M3_O0) +{ + DPL::String raw(L"1.2.3"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == DPL::String(L"1")); + RUNNER_ASSERT(version.Minor() == DPL::String(L"2")); + RUNNER_ASSERT(version.Micro() == DPL::Optional(L"3")); + RUNNER_ASSERT(version.Optional() == DPL::Optional()); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M3_O0_nonwac_1 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M3_O0_nonwac_1) +{ + DPL::String raw(L"a1a.2.3"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M3_O0_nonwac_2 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M3_O0_nonwac_2) +{ + DPL::String raw(L"1.b2.3"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M3_O0_nonwac_3 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M3_O0_nonwac_3) +{ + DPL::String raw(L"1.2.3c"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M3_O1_1 +Description: tests correct wac version number with optional part +Expected: major and minor and micro and optional parts matches expected values. + Version should be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M3_O1_1) +{ + DPL::String raw(L"1.2.3 test111"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == DPL::String(L"1")); + RUNNER_ASSERT(version.Minor() == DPL::String(L"2")); + RUNNER_ASSERT(version.Micro() == DPL::Optional(L"3")); + RUNNER_ASSERT(version.Optional() == DPL::Optional(L"test111")); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M3_O1_1 +Description: tests correct wac version number with numeric optional part +Expected: major and minor and micro and optional parts matches expected values. + Version should be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M3_O1_2) +{ + DPL::String raw(L"1.2.3 111"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == DPL::String(L"1")); + RUNNER_ASSERT(version.Minor() == DPL::String(L"2")); + RUNNER_ASSERT(version.Micro() == DPL::Optional(L"3")); + RUNNER_ASSERT(version.Optional() == DPL::Optional(L"111")); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M3_O1_3 +Description: tests if version is recognized as wac version number + when trailer spaces exists +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M3_O1_3) +{ + DPL::String raw(L"1.2.3 "); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M2_O1_1 +Description: tests if version is recognized as wac version number + when optional part +Expected: version should be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_M2_O1_1) +{ + DPL::String raw(L"1.2 t"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == DPL::String(L"1")); + RUNNER_ASSERT(version.Minor() == DPL::String(L"2")); + RUNNER_ASSERT(version.Micro() == DPL::Optional()); + RUNNER_ASSERT(version.Optional() == DPL::Optional(L"t")); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M2_O1_2 +Description: tests if version is recognized as wac version number + with numeric optional part. +Expected: major and minor and optional parts matches expected values. + Version should be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M2_O1_2) +{ + DPL::String raw(L"1.2 1234"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == DPL::String(L"1")); + RUNNER_ASSERT(version.Minor() == DPL::String(L"2")); + RUNNER_ASSERT(version.Micro() == DPL::Optional()); + RUNNER_ASSERT(version.Optional() == DPL::Optional(L"1234")); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M4_O0_1 +Description: Tests if version is recognized as wac version number. +Expected: major and minor and micro and optional parts matches expected values. + Version should be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O0_1) +{ + DPL::String raw(L"1.1"); + DPL::String majorV(L"1"); + DPL::String minorV(L"1"); + DPL::Optional microV = DPL::Optional(); + DPL::Optional optionalV = DPL::Optional(); + WidgetVersion version(majorV, minorV, microV, optionalV); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == majorV); + RUNNER_ASSERT(version.Minor() == minorV); + RUNNER_ASSERT(version.Micro() == microV); + RUNNER_ASSERT(version.Optional() == optionalV); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M4_O0_nonwac_1 +Description: Tests if version is recognized as wac version number. +Expected: Version should be recognized as non wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O0_nonwac_1) +{ + DPL::String raw(L"a1.1"); + WidgetVersion version(L"a1", L"1", DPL::Optional(), DPL::Optional()); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M4_O0_nonwac_2 +Description: Tests if version is recognized as wac version number. +Expected: Version should not be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O0_nonwac_2) +{ + DPL::String raw(L"1.1a"); + WidgetVersion version(L"1", L"1a", DPL::Optional(), DPL::Optional()); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M4_O1_1 +Description: Tests if version is recognized as wac version number. +Expected: major, minor, micro and optional parts matches expected values. + Version should be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O1_1) +{ + DPL::String raw(L"1.1.1"); + DPL::String majorV(L"1"); + DPL::String minorV(L"1"); + DPL::Optional microV = DPL::Optional(L"1"); + DPL::Optional optionalV = DPL::Optional(); + WidgetVersion version(majorV, minorV, microV, optionalV); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == majorV); + RUNNER_ASSERT(version.Minor() == minorV); + RUNNER_ASSERT(version.Micro() == microV); + RUNNER_ASSERT(version.Optional() == optionalV); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M4_O1_nonwac_1 +Description: Tests if version is recognized as wac version number. +Expected: Version should not be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O1_nonwac_1) +{ + DPL::String majorV(L"1"); + DPL::String minorV(L"1"); + WidgetVersion version(L"1", L"1", DPL::Optional(L"1a"), DPL::Optional()); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == L"1.1.1a"); +} + +/* +Name: WidgetVersion_M4_O1_nonwac_1 +Description: Tests if version is recognized as wac version number. +Expected: Version should not be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O1_nonwac_2) +{ + WidgetVersion version(L"1", L"1", DPL::Optional(L"a1"), DPL::Optional()); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == L"1.1.a1"); +} + +/* +Name: WidgetVersion_M4_O2_1 +Description: Tests if version is recognized as wac version number. +Expected: major, minor, micro and optional parts matches expected values. + Version should be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O2_1) +{ + DPL::String raw(L"1.1.1 a1"); + DPL::String majorV(L"1"); + DPL::String minorV(L"1"); + DPL::Optional microV = DPL::Optional(L"1"); + DPL::Optional optionalV = DPL::Optional(L"a1"); + WidgetVersion version(majorV, minorV, microV, optionalV); + + RUNNER_ASSERT(version.IsWac() == true); + RUNNER_ASSERT(version.Major() == majorV); + RUNNER_ASSERT(version.Minor() == minorV); + RUNNER_ASSERT(version.Micro() == microV); + RUNNER_ASSERT(version.Optional() == optionalV); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_M4_O2_1 +Description: Tests if version is recognized as wac version number. +Expected: major, minor, micro and optional parts matches expected values. + Version should be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_M4_O2_nonwac_1) +{ + WidgetVersion version(L"1", L"1", DPL::Optional(L"a1"), DPL::Optional(L"b1")); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == L"1.1.a1 b1"); +} + +/* +Name: WidgetVersion_Strange_0 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_Strange_0) +{ + DPL::String raw(L"1"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_Strange_1 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_Strange_1) +{ + DPL::String raw(L".1"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_Strange_2 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_Strange_2) +{ + DPL::String raw(L"..1"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_Strange_3 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_Strange_3) +{ + DPL::String raw(L"...1"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_Strange_4 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_Strange_4) +{ + DPL::String raw(L"qwerty"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_Strange_5 +Description: tests if version is recognized as wac version number +Expected: version should not be recognized as wac compatible +*/ +RUNNER_TEST(WidgetVersion_Strange_5) +{ + DPL::String raw(L"!@#$%^&*()_+ ^&%^*&%$^*&%*()& JHKJLHKJLH 685685687"); + WidgetVersion version(raw); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == raw); +} + +/* +Name: WidgetVersion_Strange_6 +Description: Tests if version is recognized as wac version number. +Expected: Version should not be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_Strange_6) +{ + WidgetVersion version(L"1", L"", DPL::Optional(), DPL::Optional()); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == L"1."); +} + +/* +Name: WidgetVersion_Strange_7 +Description: Tests if version is recognized as wac version number. +Expected: Version should not be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_Strange_7) +{ + WidgetVersion version(L"a", L"b", DPL::Optional(), DPL::Optional()); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == L"a.b"); +} + +/* +Name: WidgetVersion_Strange_8 +Description: Tests if version is recognized as wac version number. +Expected: Version should not be recognized as wac compatible. +*/ +RUNNER_TEST(WidgetVersion_Strange_8) +{ + WidgetVersion version(L"", L"", DPL::Optional(L"12"), DPL::Optional(L"abcd123")); + + RUNNER_ASSERT(version.IsWac() == false); + RUNNER_ASSERT(version.Raw() == L"..12 abcd123"); +} + +/* +Name: WidgetVersion_Compare_0 +Description: Tests versions comparision by less than operator. +Expected: Compare should work as expected. +*/ +RUNNER_TEST(WidgetVersion_Compare_0) +{ + RUNNER_ASSERT(WidgetVersion(L"1.1") < WidgetVersion(L"1.2")); + RUNNER_ASSERT(WidgetVersion(L"01.001") < WidgetVersion(L"0001.002")); + RUNNER_ASSERT(WidgetVersion(L"01.001") < WidgetVersion(L"0001.0010")); + RUNNER_ASSERT(WidgetVersion(L"01.001.01") < WidgetVersion(L"0001.001.012 abc")); + RUNNER_ASSERT(WidgetVersion(L"087654321.0123456789") < WidgetVersion(L"0987654321.0123456789")); +} + +/* +Name: WidgetVersion_Compare_1 +Description: Tests versions comparision by more than operator. +Expected: Compare should work as expected. +*/ +RUNNER_TEST(WidgetVersion_Compare_1) +{ + RUNNER_ASSERT(WidgetVersion(L"1.2") > WidgetVersion(L"1.1")); + RUNNER_ASSERT(WidgetVersion(L"1.020") > WidgetVersion(L"0001.00002")); + RUNNER_ASSERT(WidgetVersion(L"01.0020") > WidgetVersion(L"0001.001")); + RUNNER_ASSERT(WidgetVersion(L"0001.0020.01") > WidgetVersion(L"01.0002.0 abcd")); + RUNNER_ASSERT(WidgetVersion( + L"19647963733338932479072098437089778943732432.00000000000000004324324324324321") + > WidgetVersion(L"4324324324324324324321.000432")); +} + +/* +Name: WidgetVersion_Compare_2 +Description: Tests versions comparision by less than or equal operator. +Expected: Compare should work as expected. +*/ +RUNNER_TEST(WidgetVersion_Compare_2) +{ + RUNNER_ASSERT(WidgetVersion(L"1.1") <= WidgetVersion(L"01.2")); + RUNNER_ASSERT(WidgetVersion(L"0001.02") <= WidgetVersion(L"1.02")); + RUNNER_ASSERT(WidgetVersion(L"001.002") <= WidgetVersion(L"0002.002")); + RUNNER_ASSERT(WidgetVersion(L"2.00000000000000") <= + WidgetVersion(L"2.0 test")); +} + +/* +Name: WidgetVersion_Compare_3 +Description: Tests versions comparision more than or equal operator. +Expected: Compare should work as expected. +*/ +RUNNER_TEST(WidgetVersion_Compare_3) +{ + RUNNER_ASSERT(WidgetVersion(L"1.2") >= WidgetVersion(L"1.1")); + RUNNER_ASSERT(WidgetVersion(L"1.20") >= WidgetVersion(L"01.2")); + RUNNER_ASSERT(WidgetVersion(L"001.20") >= WidgetVersion(L"01.0020")); + RUNNER_ASSERT(WidgetVersion(L"001.20.11") >= WidgetVersion(L"01.0020.10 abc")); + RUNNER_ASSERT(WidgetVersion(L"1.00000000000000") >= + WidgetVersion(L"1.0 test")); +} + +/* +Name: WidgetVersion_Compare_4 +Description: Tests versions comparsion by equality operator. +Expected: Versions should be equal. +*/ +RUNNER_TEST(WidgetVersion_Compare_4) +{ + RUNNER_ASSERT(WidgetVersion(L"0.1") == WidgetVersion(L"00.1")); + RUNNER_ASSERT(WidgetVersion(L"0002.0001") == WidgetVersion(L"02.01")); + RUNNER_ASSERT(WidgetVersion(L"0001.02") == WidgetVersion(L"1.02")); + RUNNER_ASSERT(WidgetVersion(L"2.0001.12") == WidgetVersion(L"002.01.12 abcd")); + RUNNER_ASSERT(WidgetVersion(L"12345.1") == WidgetVersion(L"12345.1")); + RUNNER_ASSERT(WidgetVersion(L"000123000.0 notatest") == + WidgetVersion(L"00123000.0 testtesttest")); +} + +/* +Name: WidgetVersion_Compare_5 +Description: Tests versions comparsion by inequality operator. +Expected: Versions should not be equal. +*/ +RUNNER_TEST(WidgetVersion_Compare_5) +{ + RUNNER_ASSERT(WidgetVersion(L"1.1") != WidgetVersion(L"1.11")); + RUNNER_ASSERT(WidgetVersion(L"2.1.1") != WidgetVersion(L"2.1.11")); + RUNNER_ASSERT(WidgetVersion(L"003.10.1") != WidgetVersion(L"3.10.11")); + RUNNER_ASSERT(WidgetVersion(L"4.2.1 abc") != WidgetVersion(L"4.2.11 abc")); +} + +/* +Name: WidgetVersion_Compare_6 +Description: Tests insertin WidgetVersion object into a stream (operator<<) +Expected: Version should be successfully inserted into a stream. +*/ +RUNNER_TEST(WidgetVersion_Compare_6) +{ + std::stringbuf buf; + std::ostream stream(&buf); + DPL::String raw(L"1.1"); + + stream << WidgetVersion(raw); + + RUNNER_ASSERT(DPL::StringCompare(raw, DPL::FromASCIIString(buf.str())) == 0); +} diff --git a/tests/utils/wrt_utility.cpp b/tests/utils/wrt_utility.cpp new file mode 100644 index 0000000..710b578 --- /dev/null +++ b/tests/utils/wrt_utility.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file wrt_utility.cpp + * @author Janusz Majnert (j.majnert@samsung.com) + * @version 1.0 + * @brief Implementation file for test cases for wrt_utility functions + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RUNNER_TEST_GROUP_INIT(DPL_WRT_UTILITY) + +/* +Name: wrt_utility_WrtUtilJoinPaths +Description: join paths test +Expected: correctly used separator +*/ +RUNNER_TEST(wrt_utility_WrtUtilJoinPaths) +{ + std::string result; + + WrtUtilJoinPaths(result, "a/b/c/", "e/f/g.asd"); + RUNNER_ASSERT(result == "a/b/c/e/f/g.asd"); + + WrtUtilJoinPaths(result, "/a/b/c", "/e/f/g/"); + RUNNER_ASSERT(result == "/a/b/c/e/f/g/"); + + WrtUtilJoinPaths(result, "/a/b/c/", "/e/f/g/"); + RUNNER_ASSERT(result == "/a/b/c/e/f/g/"); + + WrtUtilJoinPaths(result, "/a/b/c", "e/f/g/"); + RUNNER_ASSERT(result == "/a/b/c/e/f/g/"); +} + +/** + * Create recursive path with specified permissions. + * Check if folders exist. + * Check if permissions are set. + */ +RUNNER_TEST(wrt_utility_WrtUtilMakeDir) +{ + struct stat st; + //First delete the dir if it exists + WrtUtilRemove("/tmp/test"); + WrtUtilMakeDir("/tmp/test/1/2/3/4/5/6/7/8/9", 0755); + if (stat("/tmp/test/1/2/3/4/5/6/7/8/9", &st) == 0) { + RUNNER_ASSERT_MSG(st.st_mode & S_IRWXU, + "read, write, execute/search by owner"); + RUNNER_ASSERT_MSG(st.st_mode & S_IXGRP, + "execute/search permission, group"); + RUNNER_ASSERT_MSG(st.st_mode & S_IRGRP, "read permission, group"); + RUNNER_ASSERT_MSG(!(st.st_mode & S_IWGRP), + "NO write permission, group "); + RUNNER_ASSERT_MSG(st.st_mode & S_IXOTH, + "execute/search permission, others"); + RUNNER_ASSERT_MSG(st.st_mode & S_IROTH, "read permission, others"); + RUNNER_ASSERT_MSG(!(st.st_mode & S_IWOTH), + "NO write permission, others "); + } else { + RUNNER_ASSERT_MSG(false, "Cannot stat folder"); + } +} + +/** + * Create directory without permission to write. + */ +RUNNER_TEST(wrt_utility_WrtUtilMakeDir_PermissionError) +{ + if (0 == getuid()) { + int bufsize; + if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) + RUNNER_ASSERT_MSG(false, + "Getting an initial value suggested for the size of buffer failed."); + + //Change UID to execute the test correctly + errno = 0; + char *buffer = new char[bufsize]; + struct passwd p; + struct passwd *result = NULL; + int return_value = getpwnam_r("app", &p, buffer, bufsize, &result); + delete[] buffer; + + if (return_value != 0 || !result) { + int error = errno; + RUNNER_ASSERT_MSG(false, "Getting app user UID failed: " + << (error == + 0 ? "No error detected" : strerror(error))); + } + if (setuid(p.pw_uid) != 0) { + int error = errno; + RUNNER_ASSERT_MSG(false, "Changing to app user's UID failed: " + << (error == + 0 ? "No error detected" : strerror(error))); + } + } + RUNNER_ASSERT_MSG(WrtUtilMakeDir("/tmp/test2/1", + 0055) == false, + "Creating directory '1' in /temp/test2/ should have failed"); + //Going back to root UID + if (setuid(0) != 0) { + int error = errno; + LogWarning("Changing back to root UID failed: " + << (error == 0 ? "No error detected" : strerror(error))); + } +} + +/** + * Create directory with file inside. + * Check if file was removed with directory. + */ +RUNNER_TEST(wrt_utility_WrtUtilRemoveDir) { + RUNNER_ASSERT_MSG(WrtUtilMakeDir("/tmp/test3/", 0755) == true, + "Could not set up directory for test"); + + std::ofstream file; + file.open("/tmp/test3/example.txt"); + file.close(); + struct stat tmp; + RUNNER_ASSERT_MSG(stat("/tmp/test3/example.txt", &tmp) == 0, + "Couldn't create the test file"); + + WrtUtilRemove("/tmp/test3"); + if (stat("/tmp/test3", &tmp) != 0) { + int error = errno; + RUNNER_ASSERT(error == ENOENT); + return; + } + RUNNER_ASSERT(false); +} + +/** + * Try to remove not existing folder. + */ +RUNNER_TEST(wrt_utility_WrtUtilRemoveDir_NoDirError) +{ + //First making sure the test dir doesn't exist + WrtUtilRemove("/tmp/NOT_EXISTING"); + + RUNNER_ASSERT_MSG(WrtUtilRemove("/tmp/NOT_EXISTING") == false, + "Removing non existing directory returned success"); +} + +/* +Name: wrt_utility_WrtUtilFileExists +Description: tests file existence +Expected: existing file should be reported as existing +*/ +RUNNER_TEST(wrt_utility_WrtUtilFileExists) +{ + std::ofstream file; + file.open("/tmp/test_file1"); + file.close(); + RUNNER_ASSERT(WrtUtilFileExists("/tmp/test_file1")); + + WrtUtilRemove("/tmp/test_file1"); + RUNNER_ASSERT(WrtUtilFileExists("/tmp/test_file1") == false); +} + +/* +Name: wrt_utility_WrtUtilDirExists +Description: tests directory existence +Expected: existing directory should be reported as existing +*/ +RUNNER_TEST(wrt_utility_WrtUtilDirExists) +{ + RUNNER_ASSERT(WrtUtilDirExists("/tmp")); + RUNNER_ASSERT(WrtUtilDirExists("/UNAVAILABLE_DIR") == false); +} diff --git a/uncrustify.cfg b/uncrustify.cfg new file mode 100644 index 0000000..2bf1d96 --- /dev/null +++ b/uncrustify.cfg @@ -0,0 +1,170 @@ +indent_align_string=true +indent_braces=false +indent_braces_no_func=false +indent_brace_parent=false +indent_namespace=false +indent_extern=false +indent_class=true +indent_class_colon=false +indent_else_if=false +indent_func_call_param=false +indent_func_def_param=false +indent_func_proto_param=false +indent_func_class_param=false +indent_func_ctor_var_param=false +indent_template_param=false +indent_func_param_double=false +indent_relative_single_line_comments=false +indent_col1_comment=true +indent_access_spec_body=false +indent_paren_nl=false +indent_comma_paren=false +indent_bool_paren=false +indent_square_nl=false +indent_preserve_sql=false +indent_align_assign=false +sp_balance_nested_parens=false +align_keep_tabs=false +align_with_tabs=false +align_on_tabstop=false +align_number_left=false +align_func_params=false +align_same_func_call_params=false +align_var_def_colon=false +align_var_def_attribute=false +align_var_def_inline=false +align_right_cmt_mix=false +align_on_operator=false +align_mix_var_proto=false +align_single_line_func=false +align_single_line_brace=false +align_nl_cont=false +align_left_shift=true +nl_collapse_empty_body=true +nl_assign_leave_one_liners=false +nl_class_leave_one_liners=false +nl_enum_leave_one_liners=false +nl_getset_leave_one_liners=false +nl_func_leave_one_liners=false +nl_if_leave_one_liners=false +nl_multi_line_cond=true +nl_multi_line_define=false +nl_before_case=false +nl_after_case=false +nl_after_return=false +nl_after_semicolon=true +nl_after_brace_open=false +nl_after_brace_open_cmt=false +nl_after_vbrace_open=false +nl_after_brace_close=false +nl_define_macro=false +nl_squeeze_ifdef=false +nl_ds_struct_enum_cmt=false +nl_ds_struct_enum_close_brace=false +nl_create_if_one_liner=false +nl_create_for_one_liner=false +nl_create_while_one_liner=false +ls_for_split_full=true +ls_func_split_full=true +nl_after_multiline_comment=false +eat_blanks_after_open_brace=true +eat_blanks_before_close_brace=true +mod_pawn_semicolon=false +mod_full_paren_if_bool=false +mod_remove_extra_semicolon=true +mod_sort_import=false +mod_sort_using=false +mod_sort_include=false +mod_move_case_break=false +mod_remove_empty_return=false +cmt_indent_multi=true +cmt_c_group=false +cmt_c_nl_start=false +cmt_c_nl_end=false +cmt_cpp_group=false +cmt_cpp_nl_start=false +cmt_cpp_nl_end=false +cmt_cpp_to_c=false +cmt_star_cont=true +cmt_multi_check_last=true +cmt_insert_before_preproc=false +pp_indent_at_level=false +pp_region_indent_code=false +pp_if_indent_code=false +pp_define_at_level=false +indent_columns=4 +indent_member=4 +indent_access_spec=-2 +code_width=80 +nl_max=2 +nl_before_access_spec=2 +cmt_width=80 +indent_with_tabs=0 +sp_arith=force +sp_assign=force +sp_enum_assign=force +sp_pp_concat=remove +sp_pp_stringify=remove +sp_bool=force +sp_compare=force +sp_paren_brace=force +sp_angle_paren=remove +sp_before_sparen=force +sp_inside_sparen=remove +sp_after_sparen=force +sp_sparen_brace=force +sp_before_semi=remove +sp_after_semi_for_empty=remove +sp_before_square=remove +sp_before_squares=remove +sp_inside_square=remove +sp_after_comma=force +sp_before_comma=remove +sp_after_class_colon=force +sp_before_class_colon=force +sp_before_case_colon=remove +sp_inside_braces=add +sp_inside_fparens=remove +sp_inside_fparen=remove +sp_func_call_paren=remove +sp_func_class_paren=remove +sp_else_brace=force +sp_brace_else=force +sp_catch_brace=force +sp_brace_catch=force +sp_try_brace=force +sp_before_dc=remove +sp_after_dc=remove +sp_not=remove +sp_inv=remove +sp_addr=remove +sp_member=remove +sp_deref=remove +sp_sign=remove +sp_incdec=remove +sp_cond_colon=force +sp_cond_question=force +sp_case_label=force +nl_assign_brace=remove +nl_if_brace=remove +nl_brace_else=remove +nl_elseif_brace=remove +nl_else_brace=remove +nl_else_if=remove +nl_try_brace=remove +nl_for_brace=remove +nl_catch_brace=remove +nl_brace_catch=remove +nl_while_brace=remove +nl_do_brace=remove +nl_brace_while=remove +nl_switch_brace=remove +nl_namespace_brace=remove +nl_class_brace=force +nl_fdef_brace=force +pos_class_comma=trail +pos_class_colon=trail +mod_full_brace_do=add +mod_full_brace_for=add +mod_full_brace_if=add +mod_full_brace_while=add diff --git a/uncrustify.sh b/uncrustify.sh new file mode 100755 index 0000000..2ccffef --- /dev/null +++ b/uncrustify.sh @@ -0,0 +1 @@ +uncrustify -c uncrustify.cfg --no-backup `find . -regex "\(.*\.cpp\|.*\.h\|.*\.c\|.*\.cc\)" | grep -v "orm.h\|orm_generator.h\|examples"` diff --git a/wrt-commons b/wrt-commons new file mode 100644 index 0000000..a285a63 --- /dev/null +++ b/wrt-commons @@ -0,0 +1,204 @@ +wrt-commons: +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/wrt-commons.manifest b/wrt-commons.manifest new file mode 100644 index 0000000..6b910cf --- /dev/null +++ b/wrt-commons.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + -- 2.7.4